Javascript 旋转矩阵向内旋转

Javascript 旋转矩阵向内旋转,javascript,canvas,matrix,Javascript,Canvas,Matrix,我试着做一个原地旋转的正方形,但是我的正方形向内旋转,我不知道为什么。这是代码,如果有人能解释一下发生了什么,为什么它不只是原地旋转 var angle = 2 * (Math.PI / 180); var rotate = [ [Math.cos(angle),Math.sin(angle)], [-Math.sin(angle),Math.cos(angle)] ]; var points = [[300,0],[0,300],[-300,0],[0,-300]]; init.ct

我试着做一个原地旋转的正方形,但是我的正方形向内旋转,我不知道为什么。这是代码,如果有人能解释一下发生了什么,为什么它不只是原地旋转

var angle = 2 * (Math.PI / 180);
var rotate = [
  [Math.cos(angle),Math.sin(angle)],
  [-Math.sin(angle),Math.cos(angle)]
];

var points = [[300,0],[0,300],[-300,0],[0,-300]];
init.ctx.translate(init.canvas.width/2,init.canvas.height/2);


function loop(){
  draw();
}
setInterval(loop,10);

function draw(){
  init.ctx.beginPath();
  init.ctx.moveTo(points[0][0],points[0][1]);
  init.ctx.lineTo(points[1][0],points[1][1]);
  init.ctx.lineTo(points[2][0],points[2][1]);
  init.ctx.lineTo(points[3][0],points[3][1]);
  init.ctx.closePath();
  init.ctx.stroke();
  for(let i=0;i<points.length;i++){
    init.ctx.beginPath();
    init.ctx.fillStyle = "red";
    init.ctx.fillRect(points[i][0],points[i][1],5,5);
    points[i][0] = points[i][0]*rotate[0][0] + points[i][1]*rotate[0][1];
    points[i][1] = points[i][0]*rotate[1][0] + points[i][1]*rotate[1][1];
  }

}
var角度=2*(Math.PI/180);
变量旋转=[
[Math.cos(角度),Math.sin(角度)],
[-Math.sin(角度),Math.cos(角度)]
];
var点=[[300,0],[0300],-300,0],[0,-300];
init.ctx.translate(init.canvas.width/2,init.canvas.height/2);
函数循环(){
draw();
}
设置间隔(循环,10);
函数绘图(){
init.ctx.beginPath();
init.ctx.moveTo(点[0][0],点[0][1]);
初始ctx.lineTo(点[1][0],点[1][1]);
初始ctx.lineTo(点[2][0],点[2][1]);
初始ctx.lineTo(点[3][0],点[3][1]);
init.ctx.closePath();
init.ctx.stroke();

对于(假设i=0;i那么,每次调用draw时,您都会应用一个小的旋转,特别是完全旋转的1/180。问题是您依赖浮点数学来给出精确的值,这并不是因为它没有。这是由迭代计算的点数组造成的。我建议在每个点上计算新的点通过将当前角度的正确旋转矩阵应用于起点,逐步完成绘制

var angle = 0;

var startPoints = [[300,0],[0,300],[-300,0],[0,-300]];
var points = [[300,0],[0,300],[-300,0],[0,-300]];

init.ctx.translate(init.canvas.width/2,init.canvas.height/2);

function loop(){
  draw();
}
setInterval(loop,10);

function draw(){
  init.ctx.beginPath();
  init.ctx.moveTo(points[0][0],points[0][1]);
  init.ctx.lineTo(points[1][0],points[1][1]);
  init.ctx.lineTo(points[2][0],points[2][1]);
  init.ctx.lineTo(points[3][0],points[3][1]);
  init.ctx.closePath();
  init.ctx.stroke();
  angle = angle + Math.PI / 90;
    var rotate = [
      [Math.cos(angle),Math.sin(angle)],
      [-Math.sin(angle),Math.cos(angle)]
    ];
  for(let i=0;i<points.length;i++){
    init.ctx.beginPath();
    init.ctx.fillStyle = "red";
    init.ctx.fillRect(points[i][0],points[i][1],5,5);
    points[i][0] = startPoints[i][0]*rotate[0][0] + startPoints[i][1]*rotate[0][1];
    points[i][1] = startPoints[i][0]*rotate[1][0] + startPoints[i][1]*rotate[1][1];
  }
}
var角度=0;
var起始点=[[300,0],[0300],-300,0],[0,-300];
var点=[[300,0],[0300],-300,0],[0,-300];
init.ctx.translate(init.canvas.width/2,init.canvas.height/2);
函数循环(){
draw();
}
设置间隔(循环,10);
函数绘图(){
init.ctx.beginPath();
init.ctx.moveTo(点[0][0],点[0][1]);
初始ctx.lineTo(点[1][0],点[1][1]);
初始ctx.lineTo(点[2][0],点[2][1]);
初始ctx.lineTo(点[3][0],点[3][1]);
init.ctx.closePath();
init.ctx.stroke();
角度=角度+数学PI/90;
变量旋转=[
[Math.cos(角度),Math.sin(角度)],
[-Math.sin(角度),Math.cos(角度)]
];

对于(假设i=0;i那么,每次调用draw时,您都会应用一个小的旋转,特别是完全旋转的1/180。问题是您依赖浮点数学来给出精确的值,这并不是因为它没有。这是由迭代计算的点数组造成的。我建议在每个点上计算新的点通过将当前角度的正确旋转矩阵应用于起点,逐步完成绘制

var angle = 0;

var startPoints = [[300,0],[0,300],[-300,0],[0,-300]];
var points = [[300,0],[0,300],[-300,0],[0,-300]];

init.ctx.translate(init.canvas.width/2,init.canvas.height/2);

function loop(){
  draw();
}
setInterval(loop,10);

function draw(){
  init.ctx.beginPath();
  init.ctx.moveTo(points[0][0],points[0][1]);
  init.ctx.lineTo(points[1][0],points[1][1]);
  init.ctx.lineTo(points[2][0],points[2][1]);
  init.ctx.lineTo(points[3][0],points[3][1]);
  init.ctx.closePath();
  init.ctx.stroke();
  angle = angle + Math.PI / 90;
    var rotate = [
      [Math.cos(angle),Math.sin(angle)],
      [-Math.sin(angle),Math.cos(angle)]
    ];
  for(let i=0;i<points.length;i++){
    init.ctx.beginPath();
    init.ctx.fillStyle = "red";
    init.ctx.fillRect(points[i][0],points[i][1],5,5);
    points[i][0] = startPoints[i][0]*rotate[0][0] + startPoints[i][1]*rotate[0][1];
    points[i][1] = startPoints[i][0]*rotate[1][0] + startPoints[i][1]*rotate[1][1];
  }
}
var角度=0;
var起始点=[[300,0],[0300],-300,0],[0,-300];
var点=[[300,0],[0300],-300,0],[0,-300];
init.ctx.translate(init.canvas.width/2,init.canvas.height/2);
函数循环(){
draw();
}
设置间隔(循环,10);
函数绘图(){
init.ctx.beginPath();
init.ctx.moveTo(点[0][0],点[0][1]);
初始ctx.lineTo(点[1][0],点[1][1]);
初始ctx.lineTo(点[2][0],点[2][1]);
初始ctx.lineTo(点[3][0],点[3][1]);
init.ctx.closePath();
init.ctx.stroke();
角度=角度+数学PI/90;
变量旋转=[
[Math.cos(角度),Math.sin(角度)],
[-Math.sin(角度),Math.cos(角度)]
];
for(让i=0;等轴测提示)改进代码。
作为一个初学者,我可以看到一些坏习惯潜移默化,因为已经有了答案,我想我会给你一些提示来改进你的代码


  • 不要使用
    setInterval
    创建动画。
    requestAnimationFrame
    提供了质量更好的动画

  • 数组是用高级语言创建的,目的是让生活更简单,而不是更困难
你打字很痛苦

如果你得了100分,那将是一场噩梦。最好创建一个通用函数来帮你做到这一点

function drawShape(ctx,shape){  
    ctx.beginPath();                            
    for(var i = 0; i < shape.length; i++){
       ctx.lineTo(shape[i][0], shape[i][1]);
    }
    ctx.closePath(); 
    ctx.stroke();
}
    

  • 如果使用统一比例,则可以通过重用变换的x轴来稍微缩短变换
请注意,后两个值如何只是前两个值,而新的x值是否定的。您还可以在其中包含一个刻度,并只保留前两个值

var angle = ?
var scale = 1; // can be anything

// now you only need two values for the transform
var xAx = Math.cos(angle) * scale;  // direction and size of x axis
var xAy = Math.sin(angle) * scale;
然后将变换应用于一个点,如下所示

var px = ?;  // point to transform
var py = ?;
    
var tx = px * xAx - py * xAy;
var ty = px * xAy + py * xAx;
并添加一个原点

var tx = px * xAx - py * xAy + ox;  // ox,oy is the origin
var ty = px * xAy + py * xAx + oy;

但是最好让canvas 2D API为您进行转换。下面的示例显示了上面描述的渲染长方体和设置长方体动画的各种方法

使用最佳实践的示例。
const ctx=canvas.getContext(“2d”);
var w=canvas.width;//w,h如果调整画布的大小,则会设置这些值
var h=画布高度;
var cw=w/2;//中心宽度
var ch=h/2;//中心高度
var globalScale=1;//用于缩放形状以适合画布
球形变种;
变量角度=数学PI/2;
var rotateRate=90;//度/秒
变量点=[
[300, 0],
[0, 300],
[-300, 0],
[0, -300]
];
var maxSize=Math.hypot(600600);//用于计算比例的对角线大小
//所以这个形状适合画布
//将路径添加到当前路径
//形状包含路径点
//x,y形状原点
//比例是形状的比例
//角度是以弧度为单位的旋转量。
函数createShape(形状、x、y、比例、角度){
var i=0;
setTransform(比例,0,0,比例,x,y);//设置比例和原点
ctx.rotate(angle);//设置旋转
ctx.moveTo(shape[i][0],shape[i++][1]);
而(ivar px = ?;  // point to transform
var py = ?;
    
var tx = px * xAx - py * xAy;
var ty = px * xAy + py * xAx;
var tx = px * xAx - py * xAy + ox;  // ox,oy is the origin
var ty = px * xAy + py * xAx + oy;