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.