Geometrics - Solving the PDFLib_dotnet rotate rectangle (image) around center point

Working on a project that used the PDFLib_dotnet library that has the same co-ordinate system as PostScript (origin 0 0 = left bottom point) and even though the user co-ordinate system can be defined and top down, the only and fixed co-ordinate spot to undertake rotation is and remains bottom left.

I needed to rotate a rectangle from its center point. Wanted to see how this can be calculated and put it to the test by creating a visualization of the process not really knowing if PDFLib used the rotated rectangles lower left point or that of the bounding box (a rectangle at zero degrees containing the rotated rectangle.

It shows the lower left co-ordinates of the bounding box of the rectangle, this can be used to calculate the offset from the center.


Rotation point X:
Rotation Point Y:
Rectangle Box Bottom Left X:
Rectangle Box Bottom Left Y:
Bounding Box Bottom Left X:
Bounding Box Bottom Left Y:

Tracking lower left co-ordinates for transform offsets

Wanting to rotate around the centerpoint of the origional (unrotated rectangle), the yellow point at 225,215. We track both the lowest left botton co-ordinates indicated by the green market as well as the bounding box co-ordinates as indicated by the red marker.

FACTS: PdfLib_dotnet comes with two PDF documents of interest. 1. PDFlib-API-reference.pdf and 2. PDFlib-tutorial.pdf both of which are the envy of Microsoft. Just like Microsoft documentation it is very comprehensive but not directly unusable because of the diverse options that are nearly impossible to find, and then it appears that not can be applied to any given element y time. The lack of working examples also does not help.

So what's the problem? Look for rotation information. Once you found it, try to rotate an image that needs to fit into the bounds of the rotated 'fitbox' constraints. It now becomes very apparent that whatever co-ordinate system you have set up does not apply here, and if you use the 'fitmethod' then scale and position information no longer applies. This and more of these strange behaviours cannot be found, just like a list of which options apply to which elements under which conditions.

Geometry does not apply here, or does it! The math here is not rocket science, or have I missed the complete rotation point of PDFLib again? Using the exact same math to achieve what you see here we applied it to a 'top down' and 'bottom up' co-ordinate system

new_x = x * cos(angle) - y * sin(angle)
new_y = x * sin(angle) + y * cos(angle)

The way to determine (top left) x and y and then translate to either co-ordinate system was a flag that would not fly. The results were amazing fractal patterns with strange deviations not definable to the current geometric co-ordinate space. Rather facinating, in fact so much so I waisted a lot of time working with real and bounding co-ordinates, thinking this was the problem, while the math seemed sound... except for one creveat.. at the point the rotation reaches 45 degees y3 and y4 are equal! The question is, which x do you take if you need it ;). Do you know the answer?

PDFLib_dotnet rotate image around center point solution

After a weekend with frustrating PDF results I decided to go back to the roots and concentrate on the object at hand and approach it using fundamental high school math. This was the answer!

Example solution for a 'top down' PDFLib co-ordinate system

PDFlib_dotnet.PDFlib p = default(PDFlib_dotnet.PDFlib);

string imagefile = "c:\\test-image.jpg";

p = new PDFlib();

string o = "linearize";

p.set_parameter("errorpolicy", "return");

string previewfile = "c:\\rotation_test.pdf";

int ok = p.begin_document(previewfile, o);

p.set_option("topdown=true");

dynamic image = p.load_image("auto", imagefile, "");

p.begin_page_ext(400, 400, "");

double LocX = 200;

double LocY = 200;

double AW = 100;

double AH = 100;

double R = 45;

p.fit_image(image, LocX, LocY, "boxsize={" + AH + " " + AW + "} fitmethod=meet");

// TEST Placeholder

p.save();

p.translate(LocX + (AW / 2), LocY - (AH / 2));

p.rotate(R);

p.fit_image(image, ((AW / 2) - AW), -((AH / 2) - AH), "boxsize={" + AH + " " + AW + "} fitmethod=meet");

p.end_page_ext("");

p.end_document("");

p.Dispose();

p = null;

 Dim p As PDFlib_dotnet.PDFlib

    Dim imagefile As String = "c:\test-image.jpg"

     p = New PDFlib()

    Dim o As String = "linearize"

     p.set_parameter("errorpolicy", "return")

    Dim previewfile As String = "c:\rotation_test.pdf"

    Dim ok As Integer = p.begin_document(previewfile, o)

     p.set_option("topdown=true")

    Dim image = p.load_image("auto", imagefile, "")

     p.begin_page_ext(400, 400, "")

    Dim LocX As Double = 200

    Dim LocY As Double = 200

    Dim AW As Double = 100

    Dim AH As Double = 100

    Dim R As Double = 45

    p.fit_image(image, LocX, LocY, "boxsize={" & AH & " " & AW & "} fitmethod=meet") ' TEST Placeholder

 p.save()

 p.translate(LocX + (AW / 2), LocY - (AH / 2))

 p.rotate(R)

 p.fit_image(image, ((AW / 2) - AW), -((AH / 2) - AH), "boxsize={" & AH & " " & AW & "} fitmethod=meet")

 p.end_page_ext("")

 p.end_document("")

 p.Dispose()

 p = Nothing

Example solution for a 'bottom up ' (default) PDFLib co-ordinate system

PDFlib_dotnet.PDFlib p = default(PDFlib_dotnet.PDFlib);

string imagefile = "c:\\test-image.jpg";

p = new PDFlib();

string o = "linearize";

p.set_parameter("errorpolicy", "return");

string previewfile = "c:\\rotation_test.pdf";

int ok = p.begin_document(previewfile, o);

dynamic image = p.load_image("auto", imagefile, "");

p.begin_page_ext(400, 400, "");

double LocX = 200;

double LocY = 200;

double AW = 100;

double AH = 100;

double R = 45;

p.fit_image(image, LocX, LocY, "boxsize={" + AH + " " + AW + "} fitmethod=meet");

// TEST Placeholder

p.save();

p.translate(LocX + AW / 2, LocY + AH / 2);

p.rotate(R);

p.fit_image(image, (-AW / 2), -(AH / 2), "boxsize={" + AH + " " + AW + "} fitmethod=meet");

p.restore();

p.end_page_ext("");

p.end_document("");

p.Dispose();

p = null;

Dim p As PDFlib_dotnet.PDFlib

    Dim imagefile As String = "c:\test-image.jpg"

     p = New PDFlib()

    Dim o As String = "linearize"

     p.set_parameter("errorpolicy", "return")

    Dim previewfile As String = "c:\rotation_test.pdf"

    Dim ok As Integer = p.begin_document(previewfile, o)

    Dim image = p.load_image("auto", imagefile, "")

     p.begin_page_ext(400, 400, "")

    Dim LocX As Double = 200

    Dim LocY As Double = 200

    Dim AW As Double = 100

    Dim AH As Double = 100

    Dim R As Double = 45

 p.fit_image(image, LocX, LocY, "boxsize={" & AH & " " & AW & "} fitmethod=meet") ' TEST Placeholder

 p.save()

 p.translate(LocX + AW / 2, LocY + AH / 2)

 p.rotate(R)

 p.fit_image(image, (-AW / 2), -(AH / 2), "boxsize={" & AH & " " & AW & "} fitmethod=meet")

 p.restore()

 p.end_page_ext("")

 p.end_document("")

 p.Dispose()

 p = Nothing

As my father would say (refering to newspapers), 'Do not believe everything you read' (or think you read). I guess this can also apply to technical documentation. As it is very clear that when using the 'transform' and 'rotate' methods it applies directly to the real co-ordinate system within the global co-ordinate space, and does not revolve the 'actual dynamic' bottom left x and y co-ordinates. I had a hard time wrapping my small brain around this one and hope it someday helps out others with this strange PDFLib rotation challenge.

My error at the end of the day was thinking I was working with an object in the global geometric space (which it actually is) and that working with it uses this co-ordinate system. The trick was to treat the rectangle as its own entity and apply the transforms to it directly and then place it in the global co-ordinate space. Just goes to show...In my confusion I made it much too difficult for myself while all it takes is some simple math... Another lesson learned again ;)