My objective is to have a SIMPLE (keyword, not FAST) procedure written entirely in pascal. I've found most rotate procedures on the 'net are written in asm. Unfortunately, i have no knowledge there.

Anyhow, I've seen many methods discussed for doing this.
Apparently, the method of just transferring a pixel from the picture to it's new location leaves holes. But if you work backwards, pic the new location, then look back to see what color pixel is there, you can fix this problem nicely. Or something along those lines.

The farthest i've been able to get in any sort of rotational thing would be to draw a circle. Or should i say, rotate a point a set distance around the center. (I hear there is a different 'circle' formula)

At any rate, if someone could supply a SOURCE for doing this, it would be great. You can really just put pixel's onto the screen and rotate them, I can always put in an image file loader later.

Most importantly, this has to be SIMPLE please. No need to use lookup tables or anything, calculate the sin/cos everytime. My goal here is to understand it.

To rotate a point (in the plane), you must know:
a) Coordinates of the point which your point will rotate around
(this is, "COR" = the "center of rotation").
b) The angle you want to rotate.

To apply Pithagoras' theorem, the COR must be at (0,0); thus, the trick is to calculate the differences (in coordinates units) respect to COR; after that, you can apply the angle, and, finally, to adjust the point with original displacement. That will give you the new coordinates of point.

Let's call Xrot and Yrot the center of rotation, and Ang, the angle to rotate.

Then, you can evaluate new location of point, which is located at Xp and Yp, with this algorithm:

Evaluate displacements as the difference between point and COR [coordinates]. Dx & Dy represent the "virtual" point you'll rotate as if COR really were at (0,0):
Dx:=Xp-Xrot; Dy:=Yp-Yrot;

Rotate the so obtained values. Watch out: first expression states "Cos-Sin"; second one says "Sin+Cos":
Xp:=Cos(Ang)*Dx - Sin(Ang)*Dy;
Yp:=Sin(Ang)*Dx + Cos(Ang)*Dy;

Here is an answer I posted to a similar question a few months ago:
----------------------------------------------------------

program rotate;

{written by scrapdog 10/6/98}

uses crt;

const
MAX_WIDTH = 32;
MAX_HEIGHT = 32;

type
TSprite = record
Width, Height :integer;
Picture :array[0..MAX_WIDTH, 0..MAX_WIDTH] of byte;
end;

procedure Rotate(var Sprite :TSprite;
var NewSprite :TSprite;
Theta :integer);
var
nx,ny,x,y,i,j :integer;
CosA, SinA :real;
CenterX, CenterY :integer;
begin
SinA := sin(Theta/180 * pi);
CosA := cos(Theta/180 * pi);
CenterX := Sprite.Width div 2;
CenterY := Sprite.Height div 2;
NewSprite.Width := Sprite.Width;
NewSprite.Height := Sprite.Height;
for i := 0 to Sprite.Width - 1 do
for j := 0 to Sprite.Height - 1 do begin
x := i - CenterX;
y := j - CenterY;
nx := (CenterX+(round(x*CosA-y*SinA)) mod Sprite.Width);
ny := (CenterY+(round(x*SinA+y*CosA)) mod Sprite.Height);
NewSprite.Picture[i,j] := Sprite.Picture[nx,ny];
end;
end;

procedure Scale(var Sprite :TSprite;
var NewSprite :TSprite;
Scale :Real);
var
nx,ny,x,y,i,j :integer;
CenterX, CenterY, NewCenterX, NewCenterY :integer;
begin
scale := abs(scale);
if scale = 0 then exit;
NewSprite.Width := round(Scale*Sprite.Width);
NewSprite.Height := round(Scale*Sprite.Height);
CenterX := Sprite.Width div 2;
CenterY := Sprite.Height div 2;
NewCenterX := NewSprite.Width div 2;
NewCenterY := NewSprite.Height div 2;
for i := 0 to NewSprite.Width - 1 do
for j := 0 to NewSprite.Height - 1 do begin
x := i- NewCenterX;
y := j- NewCenterY;
nx := (CenterX+round(x/scale) mod Sprite.Width);
ny := (CenterY+round(y/scale) mod Sprite.Height);
NewSprite.Picture[i,j] := Sprite.Picture[nx,ny]
end;
end;

procedure DisplaySprite(var Sprite :TSprite);
var i,j :integer;
begin
for i := 0 to Sprite.Height do begin
for j := 0 to Sprite.Width do write(Chr(Sprite.Picture[j,i]),Chr(Sprite.Picture[j,i]));
writeln;
end;
end;

var Sprite, NewSprite :TSprite;
i,j :integer;
begin
Sprite.Width := 10;
Sprite.Height := 10;
NewSprite.Width := 10;
NewSprite.Height := 10;
for i := 0 to 20 do for j := 0 to 9 do
if (random(10)>7) then Sprite.Picture[j,i] := 219
else Sprite.Picture[j,i] := 32;
DisplaySprite(Sprite);
writeln('------');
for i := 0 to 360 do begin
Rotate(Sprite, NewSprite, i);
clrscr;
DisplaySprite(NewSprite);
Delay(1);
end;
writeln('press enter');
readln;
clrscr;
for i := 1 to 20 do begin
Scale(Sprite, NewSprite, i/10);
clrscr;
DisplaySprite(NewSprite);
Delay(30);
end;
for i := 20 downto 1 do begin
Scale(Sprite, NewSprite, i/10);
clrscr;
DisplaySprite(NewSprite);
Delay(30);
end;
writeln('press enter');
readln;
end.

------------------------------------------

This program is a demonstration of how to rotate sprites. Text mode sprites are used to demonstrate the functions, but rotation of graphics in any mode is done the same way (MCGA, text, whatever).

The only functions you need to be concerned with are the Rotate and Scale functions. You did not specify to me how you were storing your sprite, so I made my own data type TSprite (which you can change to fit your needs).

TSprite holds the height and width of the sprite in pixels, and the array "Picture" holds the pixels for the sprite.

To map one sprite onto another (rotated), call the rotate function. The sprite will be rotated around its center, and the new sprite will have the same dimensions as the old one.

Example:

var
Sprite, RotatedSprite :TSprite;

Rotate(Sprite, RotatedSprite, 45); {Copys the Sprite onto Rotated Sprite and rotates it by 45 degrees}

Note that this doesn't change Sprite in anyway. It just puts the rotated version of the sprite into RotatedSprite. (Rotating the ACTUAL sprite will result in loss of data eventually, so it is always good to keep a record of the original unrotated sprite, so thats why the function works this way).

Note that the number of degrees must be integer. It can be positive or negative to indicate the diretion of rotation.

Scale works almost the same way. It copys one sprite onto another and scales it.

Scale(Sprite, ScaledSprite, 1.5);

causes ScaledSprite to be a 1.5x copy of Sprite.

You can use the code above in your program (you might have to make some changes due to how your sprite data type works). All you need are the Rotate and Scale procedures (and maybe the type declaration for TSprite). The rest of the program is to demonstrate how they work and will not be needed by your program. The only thing the rotate and scale functions handle are the mathematical transformations...it does not display the graphics. Therefore this will work in any graphics mode. Displaying the new rotated/scaled sprite is up to you.

Example:

Rotate(Sprite, RotatedSprite, 45);
DisplayOnScreen(RotatedSprite); {one of your procedures, or however you want to do it}

Additional note
----------------
When rotating a sprite, it is necessary that the height and width of the sprite are the same (or close), or there will be a loss of data. Make sure the height and width are large enough so edges won't be cut out when you rotate it. Making the height/width 1.414 times higher than the actual height/width of the graphic will accomplish this.

Example: if your graphic is 10 x 10, make the sprite height and width 14 x 14, and fill this outer edge with transparent pixels (value of 0,etc.), and in your display procedure don't map the transparent pixels. Just a suggestion.

There are better ways of doing this, but this is the simplest.

scrapdog

---------------------------------------------

Vikiing's explanation is mathematically correct...however, in practice, it is good to copy pixels from one image to another as shown above in order to avoid gaps in the image.

0

siralopAuthor Commented:

I have a couple questions regarding this. In the below code, I had it rotate a point around 160,100 the center of the screen. Theoretically, this should draw a circle, instead it does a sorta inaccurate type circle (hopefully you'll run the code i made and see what i mean) Maybe i did something wrong, or there's a reason why is ?should? do that? I'll add the formula I used to draw and rotate a point around the center of the screen. The one I used previously seems more accurate. But apparently, it would still leave wholes when rotation a full image, and that's what I want resolved. Here is what I made out of your formulas:

Var CoR,Ang,XRot,YRot,XP,YP,Dx,Dy:Integer;
Begin
InitMCGA; {into graphics}
XRot:=160;YRot:=100; {I chose the center of the screen}
XP:=150;YP:=90;{This gives like a 10 pixel radius}

For Ang:=1 To 360 Do
Begin
Dx:=XP-XRot;
Dy:=YP-YRot;
XP:=Round((Cos(Ang)*Dx) - (Sin(Ang)*Dy));
YP:=Round((Sin(Ang)*Dx) + (Cos(Ang)*Dy));
XP:=XP+XRot;
YP:=YP+YRot;
SetPixel(XP,YP,13,$a000); {put the pixel to screen}
End;
readkey;
End.

Hopefully you'll run that and see what I mean. Now on with what I used previously:

Var XRot,YRot,Radius,NX,NY,Ang:Integer;
Sinus,Cosine:Real;

Begin
Radius:=10;
XRot:=160;
YRot:=100;

For I:=1 To 360 Do
Begin
Cosine:=Cos(Ang*(PI/180));
Sinus:=Sin(Ang*(PI/180));
NX:=Round((Radius*Sinus)-(Radius*Cosine));
NY:=Round((Radius*Cosine)+(Radius*Sinus));
NX:=NX+XRot;
NY:=NY+YRot;
SetPixel(NX,NY,10,$a000);
End;

If you try that, you'll see it's more 'accurate' as i'm calling it. That apparently still gives holes to a picture when rotated, and I can see why it would. Also, the radius thing is not accurate, it's always a little smaller than what appears. I'm not sure what causes that. I'm just really looking for something that will ACCURATELY (meaning, without holes) rotate a picture, but as always, simple like the above codes

Any ideas?

0

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

for newx = 0 to 100
for newy = 0 to 100
oldx = formula (newx) {applied backwards}
oldy = formula (newy) {also applied backwards!!}
newimage.pixel[newx,newy] = oldimage.pixel[oldx,oldy]

This method guarantees that there will be no holes.

0

siralopAuthor Commented:

I have a couple questions regarding this. In the below code, I had it rotate a point around 160,100 the center of the screen. Theoretically, this should draw a circle, instead it does a sorta inaccurate type circle (hopefully you'll run the code i made and see what i mean) Maybe i did something wrong, or there's a reason why is ?should? do that? I'll add the formula I used to draw and rotate a point around the center of the screen. The one I used previously seems more accurate. But apparently, it would still leave wholes when rotation a full image, and that's what I want resolved. Here is what I made out of your formulas:

Var CoR,Ang,XRot,YRot,XP,YP,Dx,Dy:Integer;
Begin
InitMCGA; {into graphics}
XRot:=160;YRot:=100; {I chose the center of the screen}
XP:=150;YP:=90;{This gives like a 10 pixel radius}

For Ang:=1 To 360 Do
Begin
Dx:=XP-XRot;
Dy:=YP-YRot;
XP:=Round((Cos(Ang)*Dx) - (Sin(Ang)*Dy));
YP:=Round((Sin(Ang)*Dx) + (Cos(Ang)*Dy));
XP:=XP+XRot;
YP:=YP+YRot;
SetPixel(XP,YP,13,$a000); {put the pixel to screen}
End;
readkey;
End.

Hopefully you'll run that and see what I mean. Now on with what I used previously:

Var XRot,YRot,Radius,NX,NY,Ang:Integer;
Sinus,Cosine:Real;

Begin
Radius:=10;
XRot:=160;
YRot:=100;

For I:=1 To 360 Do
Begin
Cosine:=Cos(Ang*(PI/180));
Sinus:=Sin(Ang*(PI/180));
NX:=Round((Radius*Sinus)-(Radius*Cosine));
NY:=Round((Radius*Cosine)+(Radius*Sinus));
NX:=NX+XRot;
NY:=NY+YRot;
SetPixel(NX,NY,10,$a000);
End;

If you try that, you'll see it's more 'accurate' as i'm calling it. That apparently still gives holes to a picture when rotated, and I can see why it would. Also, the radius thing is not accurate, it's always a little smaller than what appears. I'm not sure what causes that. I'm just really looking for something that will ACCURATELY (meaning, without holes) rotate a picture, but as always, simple like the above codes

Any ideas?

0

siralopAuthor Commented:

That looks great scrapdog. Thanks! Thanks to Vikiing too. Scrapdog: If you want to just post an answer, i'll give you the points. You helped out BIG time.

That looks great scrapdog. Thanks! Thanks to Vikiing too. Scrapdog: If you want to just post an answer, i'll give you the points. You helped out BIG time.

The reason why you see an ellipse is because actual width and height units are not the same. If you draw a line from (0,0) to (100,0) (a 100-pixels horizontal line), you will see the difference in length with a line drawed from (0,0) to (0,100) (a 100-pixels vertical line).

Respect to your main goal (simplicity), I've explained you the simplest way to rotate a point; I (wrongly) suposed the rest was up to you.

siralop: The relationship of the height/width of pixels is the aspect ratio...an aspect ratio of 1 means square pixels. 320x200 (13h) has pixels which are slightly wider than they are high...I think that 640x480 has square pixels, but don't quote me on that...

0

siralopAuthor Commented:

Thanks, I already knew that though (: I think it's a 3/2 ratio between height/width. I imagine they would be square pixels for a 640x480 res, because when you think about it: 640x400 would be the same 'aspect ratio', just half the size pixels. So if you squish more pixels in on the bottom, it would make each pixel a little less high, probably making them out to be square.

Nevertheless, thanks for commenting on that

0

Featured Post

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

a) Coordinates of the point which your point will rotate around

(this is, "COR" = the "center of rotation").

b) The angle you want to rotate.

To apply Pithagoras' theorem, the COR must be at (0,0); thus, the trick is to calculate the differences (in coordinates units) respect to COR; after that, you can apply the angle, and, finally, to adjust the point with original displacement. That will give you the new coordinates of point.

Let's call Xrot and Yrot the center of rotation, and Ang, the angle to rotate.

Then, you can evaluate new location of point, which is located at Xp and Yp, with this algorithm:

Evaluate displacements as the difference between point and COR [coordinates]. Dx & Dy represent the "virtual" point you'll rotate as if COR really were at (0,0):

Dx:=Xp-Xrot; Dy:=Yp-Yrot;

Rotate the so obtained values. Watch out: first expression states "Cos-Sin"; second one says "Sin+Cos":

Xp:=Cos(Ang)*Dx - Sin(Ang)*Dy;

Yp:=Sin(Ang)*Dx + Cos(Ang)*Dy;

Finally, restore displacements:

Xp:=Xp+Xrot; Yp:=Yp+Yrot;

Xp and Yp have now the coordinates of new location of original point.