如何解决使用 javascript Math.sin, Math.cos 在 2D 中旋转 svg 多边形
我正在尝试使用带有 Math.sin
和 Math.cos
的 javascript 旋转 svg 多边形。我创建了一个代码笔 here 来说明我正在尝试做的事情和问题。我使用 Math.sin
和 Math.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
顺时针旋转的 center
。 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,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};
};
我认为没有必要为此使用 atan2
和 hypot
。
只是为了完全解决这个问题,@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
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。