Sign in to follow this  
mikeman1984

2D Image Rotation around origin

Recommended Posts

Hi, Sorry if this is in the wrong forum, it seemed the most appropriate. I have a problem with my rotation which im stumped with. Im trying to rotate the image around its centre. The image rotates but the drawing area when rotated by so much cuts off the image :(. This can be seen in the image at the below link, when progressing to 90degree rotation the image is now not drawn :/. Any help would be greatly appreciated.
float radians = (2*3.1416*angle)/360;
float cosine = (float)cos(radians);
float sine = (float)sin(radians);

int x1 = (int)(-m_imageheight * sine);
int y1 = (int)(m_imageheight * cosine);
int x2 = (int)(m_imagewidth * cosine - m_imageheight * sine);
int y2 = (int)(m_imageheight * cosine + m_imagewidth * sine);
int x3 = (int)(m_imagewidth * cosine);
int y3 = (int)(m_imagewidth * 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;

int xyoffet = (x + y * windowWidth);

int x10 = m_imagewidth/2;
int y10 = m_imageheight/2;

for( int y_ = (miny-y10); y_ <= (maxy-y10); y_++ )
{
	for( int x_ = (minx-x10); x_ <= (maxx-x10); x_++ )
	{			
		int sourcex = x_*cosine + y_*sine;
		int sourcey = y_*cosine - x_*sine;

		if( (sourcex + x10) >= 0 && (sourcex + x10) < m_imagewidth && (sourcey + y10) >= 0 && (sourcey + y10) < m_imageheight )
			topleftimage[ (x_ + x10) + ((y_ + y10) * windowWidth) +xyoffet ] = imagepointer[ (sourcex+x10) + m_imagewidth * (sourcey+y10) ];
	}
}


Share this post


Link to post
Share on other sites
The image is probably rotating fine, but it looks like you're not expanding or rotating the actual drawing surface for the image. Are you doing this in DirectX?

Share this post


Link to post
Share on other sites
If I'm right then your routine iterates the drawing area on a per pixel basis, computes where the pixel originates in the source image, and transfers that pixel. This is, in fact, the correct way of doing such things.

However, the extent of the drawing area is definitely given by the ranges of the both loops y_ and x_. Presumbly you want to iterate over the _whole_ drawing area.

EDIT: You're doing much "mysterious" calculations that look like optimizations to me. Perhaps you should go back to the roots by calculating the original pixel address in 1 step inside the loops e.g. by a combined affine transformation and look what happens if changing things. This would give you the flexibility of scaling and translation and non-center rotations all at once. Later then, with that understanding, start to optimize if necessary.

Share this post


Link to post
Share on other sites


I went back to basics and tried rotating around the top left 0,0 and the problem similar is in here also.
It is fine until 90 degrees in which the edges start to move in similar to the previous problem.




float radians = (2*3.1416*angle)/360;
float cosine = (float)cos(radians);
float sine = (float)sin(radians);

int x1 = (-m_imageheight * sine);
int y1 = (m_imageheight * cosine);
int x2 = ((m_imagewidth * cosine) - (m_imageheight * sine));
int y2 = ((m_imageheight * cosine) + (m_imagewidth * sine));
int x3 = (m_imagewidth * cosine);
int y3 = (m_imagewidth * 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;

int xyoffet = (x + y * windowWidth);

for( int y_ = miny; y_ < maxy; y_++ )
{
for( int x_ = minx; x_ < maxx; x_++ )
{
int sourcex = x_*cosine + y_*sine;
int sourcey = y_*cosine - x_*sine;

if( sourcex >= 0 && sourcex < m_imagewidth && sourcey >= 0 && sourcey < m_imageheight )
topleftimage[x_+(y_*windowWidth)+xyoffet] = imagepointer[sourcex+(m_imagewidth*sourcey)];
}
}

Share this post


Link to post
Share on other sites
Here's some SDL code I came up with a while back for an Asteroids clone I am/was working on:

void RotBlitSurface(SDL_Surface* src, SDL_Rect* srcrect, SDL_Surface* dst, SDL_Rect* dstrect, int angle)
{
double cosT, sinT;
double radangle = angle * (3.141592654 / 180.0);
cosT = cos(radangle);
sinT = sin(radangle);

// fix alignment on cardinal directions
if(angle == 0) { cosT = 1; sinT = 0; }
if(angle == 90) { cosT = 0; sinT = 1; }
if(angle == 180) { cosT = -1; sinT = 0; }
if(angle == 270) { cosT = 0; sinT = -1; }

// center of rotation
int x1p = srcrect->w/2 + srcrect->x;
int y1p = srcrect->h/2 + srcrect->y;

// blit position
int x1 = dstrect->x + dstrect->w/2;
int y1 = dstrect->y + dstrect->h/2;

// destination area (clipped to dst surface)
int min_x = max(dstrect->x, (Sint16)0); // cast to shut up gcc/STL
int max_x = min(min_x+dstrect->w, dst->w);
int min_y = max(dstrect->y, (Sint16)0);
int max_y = min(min_y+dstrect->h, dst->h);

Uint32* s = (Uint32*)src->pixels;
Uint32* d = (Uint32*)dst->pixels;
Uint32 color;
double xp, yp;

for(int y = min_y; y < max_y; y++)
{
xp = (min_x-x1)*cosT + (y-y1)*sinT + x1p;
yp = (y-y1)*cosT - (min_x-x1)*sinT + y1p;
for(int x = min_x; x < max_x; x++)
{
if(xp >= srcrect->x &&
yp >= srcrect->y &&
xp < srcrect->x+srcrect->w &&
yp < srcrect->y+srcrect->h)
{
color = s[(int)xp+(int)yp*src->w];
if(color != src->format->colorkey) d[x+y*dst->w] = color;
}
xp += cosT;
yp -= sinT;
}
}
}


I'm pretty sure I simply glued together two rotation algorithms I found, but I can't remember which ones.

Off-topic, but does anyone know why my code is double-spaced? It looks fine on my system, but gdnet seems to mangle it somehow.

Oops, forgot usage. Make sure dstrect is large enough to contain your rotated sprite, otherwise it will clip to dstrect as in your screenshots.

EDIT: Fixed code spacing.

[Edited by - GenPFault on August 19, 2007 10:17:23 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by GenPFault
[...]Off-topic, but does anyone know why my code is double-spaced? It looks fine on my system, but gdnet seems to mangle it somehow.[...]
It's probably related to line endings. I'd guess you are on a mac, which has line endings in the opposite order as windows (one is CR LF the other LF CR) and the way GDNet copes with "broken"(since it's made for windows probably) line endings ends up expanding mac line endings to two HTML line endings.

Share this post


Link to post
Share on other sites
Quote:
Original post by Extrarius
Quote:
Original post by GenPFault
[...]Off-topic, but does anyone know why my code is double-spaced? It looks fine on my system, but gdnet seems to mangle it somehow.[...]
It's probably related to line endings. I'd guess you are on a mac, which has line endings in the opposite order as windows (one is CR LF the other LF CR) and the way GDNet copes with "broken"(since it's made for windows probably) line endings ends up expanding mac line endings to two HTML line endings.


Linux, actually. Copy-pasted out of gedit, so it's probably just LF's. Weird. Thanks for the heads-up though.

Share this post


Link to post
Share on other sites
thanks, I sorted this now with centre origin. It was the drawing area, I devised a method which changed the loop sizes so they expand and decrease with the size.

Now to think how to do pixel collisions between the rotated and scaled sprites :/, but thats another problem.

Thanks for your help.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this