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

rotating svg polygon in 2D using javascript Math.sin, Math.cos

我正在尝试使用 javascript 与 Math.sinMath.cos 旋转 svg 多边形。我创建了一个 codepen 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函数returns将pointcenter顺时针旋转。 angle 以弧度表示:

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, 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 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: 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, center, 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;
}

你看children,结果太好了简单又容易。那些小时的烦恼是没有必要的。这就是计算机编程的故事。晚安,好梦。 xxx