2017-06-26 4 views
1

J'ai rencontré un problème étrange avec l'application manuelle des matrices de transformation aux points 2D. Lorsque j'applique une translation ou une mise à l'échelle à la matrice de transformation, l'emplacement du point 2D qui en résulte est celui auquel on s'attendrait. D'autre part, la rotation semble biaiser et faire pivoter la forme de manière étrange et inattendue.Pourquoi les translations et la mise à l'échelle se comportent-elles comme prévu, mais la rotation ne se fait pas dans une implémentation de transformation naïve?

J'ai essayé de comprendre pourquoi ce problème se produit pendant quelques jours, mais en vain. J'ai vérifié les mathématiques et il ne semble pas être la cause du problème (la transformation composite se comporte comme prévu lorsqu'il est appliqué via l'attribut de transformation en SVG, mais pas lorsqu'il est appliqué manuellement à chaque pixel), donc je suis chef de file croire que c'est une faille dans ma compréhension de la façon dont les matrices de transformation sont réellement appliquées aux points 2D. Je multiplie naïvement le point 2D avec la matrice de transformation pour obtenir le nouveau point.

Pourquoi la rotation ne se comporte-t-elle pas comme prévu? Un exemple illustrant ce problème est disponible sur le jsfiddle. Ignorez l'axe y inversé lorsque le problème se manifeste même si une matrice de rotation correctement orientée est utilisée. Voici la partie principale:

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"); 
    } 
}; 

Répondre

1

Juste une simple faute de frappe dans votre fonction de transformation

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); 
    } 

Vous avez déclaré x et y, mais ils sont déjà définis comme arguments. Ainsi, x est modifié sur la première ligne, ce qui fait que la deuxième ligne utilise la valeur incorrecte de x.

La réparation est simple.

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); 
    } 

Ou mieux

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

J'ai passé quelques jours Réimplémenter ce petit programme en plusieurs langues et de rendu à l'aide de plusieurs systèmes avec le même problème surgissent à chaque fois. Je n'aurais pas deviné que le problème était un simple bogue comme celui-ci. En rétrospective, cela aurait dû être évident. Je ne peux pas vous remercier assez pour le signaler. Je vais accepter votre réponse demain! – Doe

+0

Si vous êtes satisfait d'une réponse, veuillez considérer [accepter] (http://stackoverflow.com/help/accepted-answer) it ..! – TaW