2017-06-26 1 views
1

Ich habe ein seltsames Problem beim manuellen Anwenden von Transformationsmatrizen auf 2D-Punkte. Wenn ich eine Translation oder Skalierung auf die Transformationsmatrix anwende, ist die resultierende Position des 2D-Punktes genau dort, wo man es erwarten würde. Die Drehung hingegen scheint die Form auf seltsame und unerwartete Weise zu verzerren und zu drehen.Warum verhalten sich Übersetzung und Skalierung wie erwartet, aber Rotation nicht in einer naiven Transformationsimplementierung?

Ich habe versucht herauszufinden, warum dieses Problem für ein paar Tage auftritt, aber ohne Erfolg. Ich habe die Mathematik überprüft und es scheint nicht die Ursache des Problems zu sein (die zusammengesetzte Transformation verhält sich wie erwartet, wenn sie über das Transformationsattribut in SVG angewendet wird, aber nicht wenn sie manuell auf jedes Pixel angewendet wird), also bin ich führend zu glauben, dass es ein Fehler in meinem Verständnis ist, wie Transformationsmatrizen tatsächlich auf 2D-Punkte angewendet werden. Ich multipliziere naiv den 2D-Punkt mit der Transformationsmatrix, um den neuen Punkt zu erhalten.

Warum verhält sich die Drehung nicht wie erwartet?

Ein Beispiel, das dieses Problem veranschaulicht, ist unter jsfiddle verfügbar. Ignoriere die invertierte y-Achse, da das Problem selbst dann auftritt, wenn eine korrekt ausgerichtete Rotationsmatrix verwendet wird. Hier ist der wichtigste Teil:

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

Antwort

1

Nur ein einfacher Tippfehler in der Transformationsfunktion

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

Sie haben x und y erklärt, aber sie sind bereits als Argumente definiert. Somit wird x in der ersten Zeile geändert, wodurch die zweite Zeile den falschen Wert x verwendet.

Fix ist einfach.

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

Oder besser

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

ich ein paar Tage verbracht haben dieses kleine Programm in mehreren Sprachen Neuimplementierung und Rendering es jedes Mal tauchten mehrere Systeme mit dem gleichen Problem mit. Ich hätte nicht gedacht, dass das Problem ein einfacher Fehler war. Im Nachhinein hätte es offensichtlich sein müssen. Ich kann Ihnen nicht genug danken, dass Sie darauf hingewiesen haben. Ich werde deine Antwort morgen annehmen! – Doe

+0

Wenn Sie mit einer Antwort zufrieden sind, beachten Sie bitte [akzeptieren] (http://stackoverflow.com/help/accepted-answer) it ..! – TaW

Verwandte Themen