Click to See Complete Forum and Search --> : rotating an bitmap with center not at (0,0)


bbomeli
April 19th, 2008, 09:27 AM
Hi,

I am actualy rotating a bitmap with a rotating point (pinpoint) at (0,0 - top,left of the source bitmap rectangle), this works well, and I get the resulting new bitmap including the rotated source bitmap (new width/height and new top/left coordinates in difference from the source one).

I now need to do the same rotation (same angle, same source bitmap) but with a rotation pinpoint not at (0,0).

The resulting new bitmap is exacly the same as the previous (pinpoint at 0,0) but shifted (x and y). I need to calculate the difference between the original top/left border resulting from the pinpoint(0,0) and the new top/left corner (the shifted one) resulting from the pinpoint(x,y). This in order to recenter the image to the correct coordinates (correcting the pinpoint(x,y) effect.

Stuck on this for some days now and I parse a lot of web but didn't find any answer for now.

I am using a modified version of the excellent "Rotate a bitmap image" from zafir, and I am running on an WM6 phone.

Any help would be highly appreciated.

Ben.

MikeAThon
April 19th, 2008, 08:52 PM
I am using a modified version of the excellent "Rotate a bitmap image" from zafir ...
Do you mean the article here: http://www.codeguru.com/cpp/g-m/bitmap/specialeffects/article.php/c1743/ ?

If so, then the article gives three different techniques. Which one are you using? Please show the exact code.

Also, did you consult this comment on the Zafir article: "Here it is how to rotate abuot a point" at http://www.codeguru.com/cpp/g-m/bitmap/specialeffects/comments.php/c1743/?thread=22784 ? Does the comment provide an appropriate solution?

Mike

srelu
April 19th, 2008, 11:27 PM
F*cking math !:lol:
It's about geometric transformations... one of the simplest, rotations around a point.
Here is a function that does the job. I ignored your rectangle because I only needed its top left corner, a point.
#include <math.h>
POINT GetRotated(POINT ptIni, POINT ptCenter, float radius)
{
// Parameters:
//
// ptIni - The initial position of the point to be rotated (top-left corner of the rect)
// ptCenter - The center of the rotation (around which the rotation occur)
// radius - how many degrees to rotate expressed in radians (counterwise)
//
// Return value:
//
// The new position of the rotated point.

const float pi = 3.141592;
float x = (float) (ptIni.x - ptCenter.x);
float y = (float) (ptIni.y - ptCenter.y);
float angle;
if(x)
angle = (float) atan(y/x) - radius;
else
{
if(!y)
// ptIni is in the center of the rotation, its position will not change
return ptIni;
if(y > 0)
angle = pi / 2 - radius;
else
angle = 3 * pi / 2 -radius;
}
float ray = (float) sqrt(x * x + y * y);
POINT ptRet;
ptRet.x = (long) (ptCenter.x + ray * (float) cos(angle));
ptRet.y = (long) (ptCenter.y + ray * (float) sin(angle));
return ptRet;
}

I tested it and it works fine. If in doubt, I can send you an email with a test program. (I will not attach it to this post because I have a limited space for attachments and don't want to use it for unimportant files)

bbomeli
April 20th, 2008, 12:21 PM
Thanks guys.

I totally agree about the math apreciation ;-). Should have put more attention when in school ...

I am using the last function ("GetRotatedBitmap() using DIB"), the probleme occure in the part "Compute dimensions of the resulting bitmap".

This function assume that the rotation point is always (0,0).
I didn't find where to insert the rotating point shift to get the correct minx/miny value, as I need to anchor my new picture using those (adding those to the real picture coordinates in the screen).

I can't understand how to use the 2 samples you gave to me:
For the first one, from Paolo:
"
nx1 = (int)((x1-CX)*cosine + (y1-CY)*sine);
ny1 = (int)((y1-CY)*cosine - (x1-CX)*sine);
"
I can't see what is x1 /y1 and nx1/ny1. Are they replacement points for the (0/0) default point, if yes then do I need to also modify the minx/miny calculation taking this points into the calculation ?

For the second (the "GetRotated" function), I can't see how to apply to the minx/miny point (the top/left new rectangle including the rotated image).

I am sure that the solution is simple, just can't pinpoint :-) this one.

Thanks for your help.

srelu
April 20th, 2008, 03:16 PM
For the second (the "GetRotated" function), I can't see how to apply to the minx/miny point (the top/left new rectangle including the rotated image).

The answer is in the comments of the code. See:
// ptIni - The initial position of the point to be rotated (top-left corner of the rect)


The first parameter is the top left corner of the rectangle.
The second parameter is the 'pinpoint' of the rotation it can be any point not just (0,0).
The third parameter tells how many degrees to rotate it (must be in radians).

Briefly your "minx/miny point" must be the first parameter of the function.

The return value is the new position of the top left corner

Actually the whole algorithm is just an implementation of the polar coordiantes of the rotated point, the general formula is:
x1 = x0 + r * cos(a)
y1 = y0 + r * sin(a)
(Don't look for these variables in the program, the real implementaiton uses different ones and it's a litle bit more complex. There was a division, it was necessary to make sure the divisor will be never zero. Also the angle 'a' required some calculations. Same for the ray 'r'.)

bbomeli
April 20th, 2008, 04:52 PM
Thanks Srelu.

I do understand the algo and your function without any problem. But in the implementation the first point (the 'ptIni ') is always 0,0 as this is the top left corner of the bitmap to rotate (the source bitmap).
Here is the used Algo to get the new rectangle coordinates:
As you see, here we assume that the origine is always 0,0.



float cosine = (float)cos(radians);
float sine = (float)sin(radians);

int x1 = (int)(-nHeight * sine);
int y1 = (int)(nHeight * cosine);
int x2 = (int)(nWidth * cosine - nHeight * sine);
int y2 = (int)(nHeight * cosine + nWidth * sine);
int x3 = (int)(nWidth * cosine);
int y3 = (int)(nWidth * sine);
int minx = min(0,min(x1, min(x2,x3)));
int miny = min(0,min(y1, min(y2,y3)));
int maxx = max(x1, max(x2,x3));
int maxy = max(y1, max(y2,y3));
int w = maxx - minx;
int h = maxy - miny;



Therefore, the correct size of the inclusive rectangle is correctly calculated and the minx/miny (Left/Top coordonate of the inclusive rectangle) is OK for a rotation point set to (0/0).
What I try to do, is modify this algo to get additional information: When the user do a rotation with a center not at (0/0), the resultant inclusive rectangle is shifted, I can't manage to find this new coordonate for the Left/Top of the inclusive rectangle.

I did replace and try to use this code:


float cosine = (float)cos(radians);
float sine = (float)sin(radians);

int x0 = (- pin->x)* cosine + (-pin->y)* sine;
int y0 = (-pin->y)* cosine - (- pin->x)* sine;
int x1 = (_rc->right - pin->x)* cosine + (-pin->y)* sine;
int y1 = (-pin->y)* cosine - (_rc->right - pin->x)* sine;
int x2 = (_rc->right - pin->x)* cosine + (_rc->bottom-pin->y)* sine;
int y2 = (_rc->bottom-pin->y)* cosine - (_rc->right - pin->x)* sine;
int x3 = (- pin->x)* cosine + (_rc->bottom-pin->y)* sine;
int y3 = (_rc->bottom-pin->y)* cosine - (- pin->x)* sine;

int minx1 = min(x0,min(x1, min(x2,x3)));
int miny1 = min(y0,min(y1, min(y2,y3)));
int maxx1 = max(x1, max(x2,x3));
int maxy1 = max(y1, max(y2,y3));



where _rc->right/bottom are width/heigth of the source image and pin->x/y the rotation point. I assume that the top/left coordonate of the source image is now at (-pin->x),(-pin->y) and the width/height could be (_rc->right-pin->x),(_rc->bottom-pin->y).

But this is not working and I cna't figure where the error is :confused: .

Hope this help more.

Anyway, many thanks for your help.

srelu
April 25th, 2008, 03:50 AM
Frankly it's hard to me to follow your code without a drawing, the exact definition of all variables invoolved and the algorithm you intend to follow.

As about the code I posted, I assumed that the origin is in the bottom left corner of the rectangle. Now I can see you consider the origin in the top-left corner.
That's not serious issue but explains why I used a parameter for the top left corner and also explains why are you wondering about that.

The formula is a general one, doesn't matter where are the points, the only difference is that the angle will increase clockwise not counterwise (due to the symmetry between my approach and yours).

In your case just pass for the first parameter the origin (0,0), it will work.

Example: if you want to rotate it 30 degree about point (200,300) you will need the following call:
POINT ptIni = {0, 0};
float angle = pi / 6;
POINT ptCenter = {200, 300};
POINT ptRotated = GetRotated(ptIni, ptCenter, angle);
After calling the function you'll have the new coordinates of the top left corner in the ptRotated variable.

You can even remove the ptIni from the function's list of parameters and replace everywhere ptIni.x and ptIni.y with zero. (But in this case you will be unable to handle the case when the user wants to apply a second rotation on an already rotated rectangle - if such a request is possible or necessary).

The test application I used is attached. If interrested, download it now because I will remove it along with this paragraph. It's not an artwork, just a window with a black pixel as the centre of the rotation and a red pixel to be rotated (if you need glasses now it's the right time to use them). Every time you left-click the window, the point is rotated 0.1 radians. Multiple clicks will draw lots of red points on a circle around the black point.

bbomeli
April 28th, 2008, 09:02 AM
Thanks srelu,

You where right! the problem is very basic :blush: . The Y axis is reversed from convention when drawing as I start from top/left, so the y should be -y.
Corrected -> works !.

Many thanks for your great help.

:wave: