简体   繁体   中英

2d transformations, rotation not as intended

I'm trying to implement a set of basic euclidean transforms in 2d space in javascript and I seem to be having a problem with my rotation.

    // simple 2d html5 interface
"use strict";

class Point{
    constructor(x,y){
        this.x = x;
        this.y = y;
    }
    mul(c){
        this.x *= c;
        this.y *= c;
    }
}

class TransMatrix{
    /*    see https://pages.mtu.edu/~shene/COURSES/cs3621/NOTES/geometry/geo-tran.html
     *    for more info.
     *    c1 c2 c3
     *    c4 c5 c6
     *    c7 c8 c9 
     */
    constructor(){
        this.c1 = 1;
        this.c2 = 0;
        this.c3 = 0;

        this.c4 = 0;
        this.c5 = 1;
        this.c6 = 0;

        this.c7 = 0;
        this.c8 = 0;
        this.c9 = 1;
    }

    applyMatrix(point){
        point.x = this.c1*point.x + this.c2*point.y + this.c3;
        point.y = this.c4*point.x + this.c5*point.y + this.c6;
    }

    copy(){
        var matrix = new TransMatrix();
        matrix.c1 = this.c1;
        matrix.c2 = this.c2;
        matrix.c3 = this.c3;

        matrix.c4 = this.c4;
        matrix.c5 = this.c5;
        matrix.c6 = this.c6;

        matrix.c7 = this.c7;
        matrix.c8 = this.c8;
        matrix.c9 = this.c9;
        return matrix;
    }

    translation(x,y){
        var newMatrix = this.copy();

        newMatrix.c3 += x;
        newMatrix.c6 += y;

        return newMatrix;
    }
    scale(s){
        var newMatrix = this.copy();

        newMatrix.c1 += s;
        newMatrix.c5 += s;

        return newMatrix;
    }
    rotation(r){ //radians
        var newMatrix = this.copy();

        newMatrix.c1 += Math.cos(r);
        newMatrix.c2 += -Math.sin(r);
        newMatrix.c4 += Math.sin(r);
        newMatrix.c5 += Math.cos(r);

        return newMatrix;
    }
}

function drawHexagon(canvas, matrix, strokeColor, fillColor) {
    if (!canvas) {
        return;
    }

    var points = [new Point(0.5 ,  1),
                  new Point(1   ,  0),
                  new Point(0.5 , -1),
                  new Point(-0.5, -1),
                  new Point(-1  ,  0),
                  new Point(-0.5,  1)
    ];

    points.forEach(point => {
        matrix.applyMatrix(point);
    });

    drawHexagonLit(canvas,points[0],points[1],points[2],points[3],points[4],points[5], "red", "green");
}

function drawHexagonLit(canvas, p1, p2, p3 ,p4 ,p5, p6, strokeColor, fillColor){ // add border cases here
    if(!canvas){
        return;
    }
    var ctx = canvas.getContext("2d");
    if(!ctx){
        return;
    }
    ctx.beginPath();
    ctx.moveTo(p1.x, p1.y);
    ctx.lineTo(p2.x, p2.y);
    ctx.lineTo(p3.x, p3.y);
    ctx.lineTo(p4.x, p4.y);
    ctx.lineTo(p5.x, p5.y);
    ctx.lineTo(p6.x, p6.y);
    ctx.lineTo(p1.x, p1.y);
    ctx.strokeStyle = strokeColor;
    ctx.fillColor = fillColor;
    ctx.stroke();
    ctx.fill();
    ctx.closePath();
}


function dynamicBackgroundInit(canvas){
    if(!canvas){
        return;
    }
    var worldMatrix = new TransMatrix();

    var rotate = 0;

    function step(){
        canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height);
        rotate += 0.01;
        var transform = worldMatrix.rotation(rotate); // this is better reflected by a matrix inside an object
        transform = transform.translation(50,50);
        transform = transform.scale(30,30);
        drawHexagon(canvas, transform, "red", "green");
        window.requestAnimationFrame(step);
    }

    window.requestAnimationFrame(step);
}

Calling and translation work as intended but rotation seems to generate poor results. Initially I thought I was just rotating on an external origin point but I no longer think so as the problem is still there when the initial object is simply scaled up.

Your transformation code produces artifacts because you use point coordinates both before and after transform, so in second line the transformed coordinate in used instead of the original:

applyMatrix(point){
        point.x = this.c1*point.x + this.c2*point.y + this.c3;
        point.y = this.c4*point.x + this.c5*point.y + this.c6; // transformed point.x is used instead of the original point.x

}

Instead do the following:

applyMatrix(point){
        var x = point.x, y = point.y;
        point.x = this.c1*x + this.c2*y + this.c3;
        point.y = this.c4*x + this.c5*y + this.c6;
    }

Use similar caching of original coordinates in any other transformation you try to apply simlultaneously. Store them in temp variables first then apply using original and new coords as different variables

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM