为什么翻译和缩放的行为与预期的一样,但旋转不在天真的变换实现中?

问题描述:

手动将转换矩阵应用于2D点时,我遇到了一个奇怪的问题。当我将变换或缩放应用到变换矩阵时,2D点的结果位置就是人们所期望的位置。另一方面,旋转似乎倾斜并以奇怪和意想不到的方式旋转形状。为什么翻译和缩放的行为与预期的一样,但旋转不在天真的变换实现中?

我一直在试图找出为什么这个问题发生了几天,但无济于事。我检查了数学,并且它似乎并不是问题的原因(当通过SVG中的transform属性应用复合变换时,复合变换的行为与预期相同,但手动应用于每个像素时不会发生),所以我是铅相信这是我理解变换矩阵实际应用于2D点的一个缺陷。我天真地将2D点与变换矩阵相乘以得到新的点。

为什么轮转表现不如预期?

举例说明此问题,请登录jsfiddle。忽略倒转的y轴,因为即使使用正确定向的旋转矩阵,问题也会出现。以下是主要部分:

window.onload = function(e) { 
    var canvas = document.getElementsByTagName('canvas')[0]; 

    if (canvas.getContext) { 
     var ctx = canvas.getContext('2d'); 
     var ctm = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]; 
     ctx.lineWidth = 0.0; 

     function matrix_mul(a, b) { 
      return [ 
       a[1]*b[2] + a[0]*b[0], 
       a[1]*b[3] + a[0]*b[1], 
       a[3]*b[2] + a[2]*b[0], 
       a[3]*b[3] + a[2]*b[1], 
       b[4] + a[5]*b[2] + a[4]*b[0], 
       b[5] + a[5]*b[3] + a[4]*b[1] 
      ]; 
     } 
     function rotate(ang) { 
      ctm = matrix_mul(ctm, [Math.cos(ang), Math.sin(ang), -Math.sin(ang), Math.cos(ang), 0.0, 0.0]); 
     } 
     function paint_point(x, y) { 
      var x = ctm[0]*x + ctm[2]*y + ctm[4]; 
      var y = ctm[1]*x + ctm[3]*y + ctm[5]; 
      ctx.fillRect(x, y, 1, 1); 
     } 
     function square() { 
      for (i = 0; i <= 100; ++i) { paint_point(150+i, 150); } 
      for (j = 0; j <= 100; ++j) { paint_point(150, 150+j); 
             paint_point(250, 150+j); } 
      for (i = 0; i <= 100; ++i) { paint_point(150+i, 250); } 
     } 


     square(); 
     for (d=0; d<3; ++d) { 
      rotate(Math.PI/14); 
      ctx.fillStyle = 'rgb(0, ' + d+30*40 + ', 0)'; 
      square(); 
     } 

     ctm = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]; 
     ctx.fillStyle = 'rgb(0, 0, 255)'; 
     rotate(Math.PI/14 * 3); 
     square(); 

    } else { 
     alert("Something bad happend"); 
    } 
}; 

只是一个简单的拼写错误在您的转换功能

function paint_point(x, y) { 
    var x = ctm[0]*x + ctm[2]*y + ctm[4]; 
    var y = ctm[1]*x + ctm[3]*y + ctm[5]; 
    ctx.fillRect(x, y, 1, 1); 
    } 

您已经声明xy,但他们已经被定义为参数。因此x在第一行上被修改,使得第二行使用不正确的值x

修复很简单。

function paint_point(x, y) { 
    var x1 = ctm[0]*x + ctm[2]*y + ctm[4]; 
    var y1 = ctm[1]*x + ctm[3]*y + ctm[5]; 
    ctx.fillRect(x1, y1, 1, 1); 
    } 

或者更好

function paint_point(x, y) { 
    ctx.fillRect(
     ctm[0]*x + ctm[2]*y + ctm[4], 
     ctm[1]*x + ctm[3]*y + ctm[5], 
     1, 1 
    ); 
    } 
+0

我花了几天时间重新实现多语言这个小程序,并使用多个系统使用相同的问题突然出现每一次渲染它。我不会猜测这个问题是一个简单的bug。事后看来,这应该是显而易见的。我不能非常感谢你指出这一点。我明天会接受你的回答! – Doe

+0

如果您对答案感到满意,请考虑[接受](http://stackoverflow.com/help/accepted-answer).. ..! – TaW