使用 javascript Math.sin, Math.cos 在 2D 中旋转 svg 多边形

问题描述

我正在尝试使用带有 Math.sinMath.cos 的 javascript 旋转 svg 多边形。我创建了一个代码here 来说明我正在尝试做的事情和问题。我使用 Math.sinMath.cos 而不是 transform 因为我需要访问旋转点的坐标。基本上是我的代码

var r = (Math.PI / 180.0) * a,cos = Math.cos(r),sin = Math.sin(r),cx=350,cy=250;
for(var p of rectangle){
   p[0]=cos*(p[0]-cx)-sin*(p[1]-cy)+cx;
   p[1]=cos*(p[1]-cy)+sin*(p[0]-cx)+cy;
}

无法正常工作,旋转点不太正确。它们应该在 2D 中逆时针旋转 cx=350,cy=250。相反,矩形被扭曲了,看起来像是在 3D 中做一个数字 8。

解决方法

rotatePoint 函数返回围绕 point 顺时针旋转的 centerangle 以弧度给出:

const rotatePoint = (point,center,angle) => {
  const dx = point.x - center.x;
  const dy = point.y - center.y;
  const fromAngle = Math.atan2(dy,dx);
  const toAngle = fromAngle + angle;
  const radius = Math.hypot(dx,dy);
  const x = center.x + radius * Math.cos(toAngle);
  const y = center.y + radius * Math.sin(toAngle);
  return {x,y};
};

const rotatePoint = (point,y};
};

const svg = d3.select('svg');
const drawPath = points => points.forEach((p,i) => {
  const another = i === 0 ? points[points.length - 1] : points[i - 1];
  svg.append('line')
    .attr('x1',p.x)
    .attr('y1',p.y)
    .attr('x2',another.x)
    .attr('y2',another.y)
    .style('fill','none')
    .style('stroke','black');
});

const centerP = {x: 100,y: 100};
svg.append('circle')
  .attr('cx',centerP.x)
  .attr('cy',centerP.y)
  .attr('r',5)
  .style('fill','red')

let rect = [
  {x: 110,y: 20},{x: 150,y: 80},{x: 110,y: 80}
];
drawPath(rect);

for (let i = 0; i < 6; i++) {
  rect = rect.map(p => rotatePoint(p,centerP,Math.PI / 3));
  drawPath(rect);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="250" height="200" />

,

您的解决方案的问题是您正在更新旋转点 (p[0]) 的 x 坐标,然后在计算 y 坐标时使用这个更新后的值,而不是原始值 -那里,完成了:)

p[0]=cos*(p[0]-cx)-sin*(p[1]-cy)+cx;
p[1]=cos*(p[1]-cy)+sin*(p[0]-cx)+cy;

应该是这样的:

var rotX = cos*(p[0]-cx)-sin*(p[1]-cy)+cx;
var rotY = cos*(p[1]-cy)+sin*(p[0]-cx)+cy;
p[0] = rotX;
p[1] = rotY;

或者,更好的是,定义一个函数

const rotatePoint = (point,angle) => {
  const dx = point.x - center.x;
  const dy = point.y - center.y;
  const ca = Math.cos(angle);
  const sa = Math.sin(angle);
  const x = center.x + dx * ca - dy * sa;
  const y = center.y + dx * sa + dy * ca;
  return {x,y};
};

我认为没有必要为此使用 atan2hypot

,

只是为了完全解决这个问题,@RaffleBaffle 发布的答案是使用更新后的 x 坐标来更新我的 y 坐标。这是进行所需更改后的工作代码:

var r = (Math.PI / 180.0) * a,cos = Math.cos(r),sin = Math.sin(r),cx=350,cy=250;
for(var p of rectangle){
   var p0=cos*(p[0]-cx)-sin*(p[1]-cy)+cx;
   p[1]=cos*(p[1]-cy)+sin*(p[0]-cx)+cy;
   p[0]=p0;
}

你看孩子们,最后它sooooo简单易行。没有必要为那些小时的烦恼而烦恼。这就是计算机编程的故事。晚安,好梦。 xxx