Rotations

Two further nights I have spent the re-engineering of the coordinate transformation of rotated graphical objects. Oracle Forms allows it to rotate rectangle or lines with a defined angle. The angle can be integers between 0 and 359 degree.

Actually I haven’t any interest in graphical transformations, simple moves of objects can program everybody, but to calculate new coordinates for a rotated object is more complex.

The good news are, the FMX file contains the angle value. So I can calculate the new coordinates with a little bit mathematics.

I have started with rectangles, four corners, should be possible. As I entered a rotation angle, there were a lot of changes within the FMX file. I found the rotation angle, but why there are other changes? Some of the changes I had already located as x, y, width and height of the rectangle, but the meaning has been changed with a rotating angle != 0. To find out, what is going on in the file, I have to go deeper into mathematics.

Oracle Forms rotates the rectangle around its center. Every corner will get new coordinates. So the first thing I need is the center of the rectangle. It is simple to calculate for a non-rotated rectangle:

cx = x + (width/2)
cy = y + (height/2)

Next, I calculate every corner coordinate:

x0 = x, y0 = y
x1 = x + width, y1 = y
x2 = x + width, y + height
x3 = x, y + height

These four coordinates I have to transform by the following formula, where (x,y) is the corner coordinate, (cx,cy) is the center coordinate, q is the rotation angle and (x’,y’) is the new coordinate:

x' = x1 + cos(q) * (x - cx) - sin(q) * (y - cy)
y' = y1 + sin(q) * (x - cx) + cos(q) * (y - cy)

With a little bit Java, I can describe it as:

package info.phosco.forms.rotate;

public class OraclePoint {

	private final double x;
	private final double y;

	public OraclePoint(double x, double y) {
		this.x = Math.round(x * 1000.0) / 1000.0;
		this.y = Math.round(y * 1000.0) / 1000.0;
	}

	public OraclePoint(int x, int y) {
		this((double) x, (double) y);
	}

	public double getX() {
		return this.x;
	}

	public double getY() {
		return this.y;
	}

	@Override
	public String toString() {
		return getClass().getName() + "[" + this.x + ", " + this.y + "]";
	}

}
package info.phosco.forms.rotate;

public class RotateRect {

	// Rotation point: x1,y1
	// Original x,y
	// Rotated x',y'
	// Rotation angle q

	private static OraclePoint rotate(OraclePoint p, OraclePoint c, int angle) {
		// x' = x1 + cos(q) * (x - x1) - sin(q) * (y - y1)
		double x = c.getX() + Math.cos(Math.toRadians(angle)) * (p.getX() - c.getX()) - Math.sin(Math.toRadians(angle))
				* (p.getY() - c.getY());

		// y' = y1 + sin(q) * (x - x1) + cos(q) * (y - y1)
		double y = c.getY() + Math.sin(Math.toRadians(angle)) * (p.getX() - c.getX()) - Math.cos(Math.toRadians(angle))
				* (p.getY() - c.getY());

		return new OraclePoint(x, y);
	}

	public static void main(String args[]) {
		int x = 37;
		int y = 47;
		int w = 120;
		int h = 73;
		int angle = 45;

		// calc every corner
		OraclePoint p0 = new OraclePoint(x, y);
		OraclePoint p1 = new OraclePoint(x + w, y);
		OraclePoint p2 = new OraclePoint(x + w, y + h);
		OraclePoint p3 = new OraclePoint(x, y + h);

		System.out.println("rotate angle: 0°");
		System.out.println(p0);
		System.out.println(p1);
		System.out.println(p2);
		System.out.println(p3);

		// calc center point
		OraclePoint center = new OraclePoint((double) x + ((double) w / 2.0), (double) y + ((double) h / 2.0));

		// Rotate rectangle
		OraclePoint r0 = rotate(p0, center, angle);
		OraclePoint r1 = rotate(p1, center, angle);
		OraclePoint r2 = rotate(p2, center, angle);
		OraclePoint r3 = rotate(p3, center, angle);

		System.out.println("----------");
		System.out.println("rotate angle: " + angle + "°");
		System.out.println(r0);
		System.out.println(r1);
		System.out.println(r2);
		System.out.println(r3);

	}
}

I can round the new coordinates a bit and it was possible to find the values (after a further transformation with the Oracle Form coordinate system factor) within the changes of the FMX file. Some changes I cannot explain, some cordinates seems to be double stored into the file.

Leave a Reply