[2 days left] Whatâ€™s wrong with your cloud strategy? Learn why multicloud solutions matter with Nimble Storage.Register Now

x
Solved

# Simple rotational procedure in mode 13h

Posted on 1998-12-19
Medium Priority
266 Views
Hello,

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.

THANKS
0
Question by:siralop
[X]
###### Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

• Help others & share knowledge
• Earn cash & points
• 5
• 5
• 2

LVL 3

Expert Comment

ID: 1216629
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;

Finally, restore displacements:
Xp:=Xp+Xrot; Yp:=Yp+Yrot;

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

0

LVL 5

Expert Comment

ID: 1216630
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');
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');
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}

----------------
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

Author Comment

ID: 1216631
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;
End.

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

Sinus,Cosine:Real;

Begin
XRot:=160;
YRot:=100;

For I:=1 To 360 Do
Begin
Cosine:=Cos(Ang*(PI/180));
Sinus:=Sin(Ang*(PI/180));
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

LVL 5

Expert Comment

ID: 1216632
In the first one, you didn't convert degrees to radians.

0

LVL 5

Expert Comment

ID: 1216633
To rotate something an entire image:

In pseudocode:

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

Author Comment

ID: 1216634
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;
End.

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

Sinus,Cosine:Real;

Begin
XRot:=160;
YRot:=100;

For I:=1 To 360 Do
Begin
Cosine:=Cos(Ang*(PI/180));
Sinus:=Sin(Ang*(PI/180));
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

Author Comment

ID: 1216635
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.

Thanks again,

Siralop
0

LVL 5

Accepted Solution

scrapdog earned 600 total points
ID: 1216636
Thanks!!  Feel free to ask for further help.
0

Author Comment

ID: 1216637
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.

Thanks again,

Siralop
0

LVL 3

Expert Comment

ID: 1216638
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.

Anyway, glad to have helped you.

0

LVL 5

Expert Comment

ID: 1216639
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

Author Comment

ID: 1216640
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

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Working from home is a dream for many people who arenâ€™t happy about getting up early, going to the office, and spending long hours at work. There are lots of benefits of remote work for employees.
Itâ€™s time for spooky stories and consuming way too much sugar, including the many treats weâ€™ve whipped for you in the world of tech. Check it out!
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can reâ€¦
Weâ€™ve all felt that sense of false security beforeâ€”locking down external access to a database or component and feeling like weâ€™ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many wâ€¦
###### Suggested Courses
Course of the Month14 days, 17 hours left to enroll