Computer Graphics: Rotating a polygon

2019-09-12 06:21发布

问题:

Purpose

I'm implementing a polygon rotation with Java AWT.

I'm already able to draw polygons on the screen, and I'd like to apply a rotation matrix manually upon my polygons coordinates (rotation is done around the lookAt point of the user).

What I've already done

In order to rotate the world, the user first clicks on the screen and then drags the mouse around to perform the rotation.

Let's note the first click point as S, the following point from the drag event as L, and the center of the screen as C.

In order to calculate the rotation angle, when first clicking the screen, I keep a vector from C to S: C-S.

Then, when a drag event occurs, I calculate the vector from C to L: C-L. I then calculate the angle in radians between C-S to C-L, and that's what I apply on my world.

This works well, and the polygon is indeed rotation around the lookAt point.

My problem

The problem occurs when the user finishes a rotation of PI, and then the polygon is rotating backward.

e.g. When the user starts rotating, the angle starts from 0.1.... 0.2... 1.. 2.. 3.. and in value ~3.1 (I assume PI), the values are starting to go down: 3... 2.. 1.. until 0, and vice versa.

This makes sense since the radians range is [0, PI].

I assume the base vector C-S lies on the right side of X axis, and when the rotation goes down below the X axis the polygon is rotating backwards.

However, I have no idea how to keep the polygon rotating in the same direction all the time (when the user performs a full rotation around the polygon).

Edit

Angle function is:

public final double angle(Vector2D v1)
{
    double vDot = this.dot(v1) / ( this.length()*v1.length() );
    if( vDot < -1.0) vDot = -1.0;
    if( vDot >  1.0) vDot =  1.0;
    return ((double) (Math.acos( vDot )));
}

回答1:

This is a problem of the arcus cosine, acos(cos(x)) is a periodic hat function moving up and down in the range of 0 to pi.

In higher dimensions that can not be avoided, as there is no preferred frame of reference, so there is no way to say that phi should really be -phi. In 2 dimensions there is a prefered orientation of the plane so that one can say what is the first and what the second vector and define a unique angle in positive orientation. Rotate the situation so that the first vector comes to lay on the positive real half axis to get the angle and correct quadrant from the coordinates of the rotated second vector.

Easiest to reconstruct is the complex picture, to compute the angle from a=a.x+i*a.y to b=b.x+i*b.y rotate b back by multiplying with the conjugate of a to get an angle from the zero angle resp. the positive real axis,

arg((a.x-i*a.y)*(b.x+i*b.y))

=arg((a.x*b.x+a.y*b.y)+i*(a.x*b.y-a.y*b.x))

=atan2( a.x*b.y-a.y*b.x , a.x*b.x+a.y*b.y )

Note that screen coordinates use the opposite orientation to the cartesian/complex plane, thus change atan2(y,x) to atan2(-y,x) to get an angle in the usual direction.



回答2:

public Point rotate(Point original, Point vertex, double angle){
        Point translated = new Point(original.x - vertex.x, original.y - vertex.y);
        int x = (int)Math.round(translated.x * Math.cos(angle) - translated.y * Math.sin(angle));
        int y = (int)Math.round(translated.x * Math.sin(angle) + translated.y * Math.cos(angle));
        return new Point(vertex.x+x,vertex.y+y);
    }

This is a simple rotation method that you can use to rotate a point around a given vertex.