JavaScript实现旋转矩阵遇问题:2D旋转时点间距异常缩小
搞定2D旋转矩阵的点间距问题
嘿,我太懂你想亲手啃透旋转底层数学的执念了——直接用Three.js确实省心,但自己撸一遍才是真的把原理刻进脑子里。你遇到的旋转后点间距变小的问题,其实根本不是旋转矩阵本身的锅(2D旋转矩阵是正交变换,本来就不会改变两点间距离),大概率是坐标原点没处理对,或者旋转流程有疏漏,我给你一步步拆解:
最可能的元凶:旋转原点没选对
画布默认的坐标系是左上角为(0,0),但我们旋转图形时,肯定是想绕图形中心(或者画布中心)转对吧?如果直接对画布上的原始坐标应用旋转矩阵,相当于绕左上角旋转——这时候图形会一边转一边往角落跑,视觉上看起来就像“间距变小、在后退”,其实是旋转后的图形在原坐标系下的投影错觉。
正确的旋转流程必须是这三步:
- 把所有点的坐标平移到以旋转中心为原点(也就是点坐标减去旋转中心的坐标)
- 应用标准的2D旋转矩阵
- 把旋转后的坐标平移回原来的坐标系(加上旋转中心的坐标)
别踩“重复旋转”的坑
另外还要注意:一定要保存原始点的副本!如果你的循环是每一帧都执行,却每次都对已经旋转过的点再次应用旋转,虽然旋转矩阵叠加不会缩放,但如果是动画的话,角度累加容易出错(不过你当前的问题不是这个,但提前避坑总是好的)。
给你写个正确的代码示例
假设你的PTS.Demo.pts是原始点数组,旋转中心就是画布中心,代码应该这么写:
// 先备份原始点,避免每次旋转修改原始数据 const originalPoints = [...PTS.Demo.pts]; const sin = Math.sin; const cos = Math.cos; // 这里可以改成随时间变化的角度,比如做动画的话ang += 0.01 const rotationAngle = (Math.PI / 180) * 10; // 转10度 const canvasCenter = { x: canvas.width / 2, y: canvas.height / 2 }; for (let p = 0; p < originalPoints.length; p++) { const [x, y] = originalPoints[p]; // 步骤1:平移到旋转中心(临时原点) const tempX = x - canvasCenter.x; const tempY = y - canvasCenter.y; // 步骤2:应用2D旋转矩阵 [cosθ, -sinθ; sinθ, cosθ] const rotatedX = tempX * cos(rotationAngle) - tempY * sin(rotationAngle); const rotatedY = tempX * sin(rotationAngle) + tempY * cos(rotationAngle); // 步骤3:平移回画布坐标系 PTS.Demo.pts[p][0] = rotatedX + canvasCenter.x; PTS.Demo.pts[p][1] = rotatedY + canvasCenter.y; }
验证方法
你可以先画个正方形的四个顶点测试:用上面的代码旋转后,正方形应该还是正方形,边长完全不变。如果变成菱形或者边长变短,那肯定是坐标平移的步骤漏了。
额外排查点
如果按上面的改了还是有问题,检查下:
- 有没有在绘制时不小心用了
ctx.scale()?缩放会直接改变点间距 - 画布有没有被拉伸?比如CSS设置的画布尺寸和实际像素尺寸不一致,会导致视觉上的缩放错觉
内容的提问来源于stack exchange,提问作者openquestions
相关产品推荐
相关产品推荐

