使用 javascript Math.sin, Math.cos 在 2D 中旋转 svg 多边形
rotating svg polygon in 2D using javascript Math.sin, Math.cos
我正在尝试使用 javascript 与 Math.sin
和 Math.cos
旋转 svg 多边形。我创建了一个 codepen 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
函数returns将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, 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};
};
我认为没有必要为此使用 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;
}
你看children,结果太好了简单又容易。那些小时的烦恼是没有必要的。这就是计算机编程的故事。晚安,好梦。 xxx
我正在尝试使用 javascript 与 Math.sin
和 Math.cos
旋转 svg 多边形。我创建了一个 codepen 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
函数returns将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, 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};
};
我认为没有必要为此使用 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;
}
你看children,结果太好了简单又容易。那些小时的烦恼是没有必要的。这就是计算机编程的故事。晚安,好梦。 xxx