LoginLogin
Nintendo shutting down 3DS + Wii U online services, see our post

Rotating a set of coordinates around a point?

Root / Programming Questions / [.]

MZ952Created:
Is there a formula or equation available for rotating a pixel (rather, a whole bunch of pixels) around a common point? I'm imagining rotation of graphics (coordinates) would work something like this: For distance, D, from the origin there is an imaginary circle with radius D, and any given pixel which lies on this imaginary circle (at distance D) would rotate around on the circle at the same rate as any other coordinate at any other distance. Though I like math enough, I cant seem to wrap my head around it. How do i describe where a pixel would be when i rotate it N degrees around a point? I know there must be a formula describing this transformation.

In the realm of planar 2D geometry, the formula for rotating a point (x,y) about the origin point (0,0) in the counter-clockwise direction is taken to be this:
new x = x * cos(angle) - y * sin(angle) new y = x * sin(angle) + y * cos(angle)
This can be adapted to SB pretty much directly, assuming all numbers are real-type. To rotate around a point that isn't the origin, simply subtract the center point's coordinates from the coordinates to rotate. SIN and COS take angles in radians. Some SB pseudo-code:
'assuming CX# and CY# are the coordinates of the center
'assuming X# and Y# are the coordinates of the point to be rotated
'assuming R# is the angle of rotation, in radians
'assuming NX# and NY# are the coordinates of the new point (the result)
C#=COS(R#)
S#=SIN(R#)
DX#=X#-CX#
DY#=Y#-CY#
NX#=DX#*C#-DY#*S
NY#=DX#*S#+DY#*C

In the realm of planar 2D geometry, the formula for rotating a point (x,y) about the origin point (0,0) in the counter-clockwise direction is taken to be this...
Wow, thanks! I was just researching the Rotation Matrix, but this seriously helps me out. Thanks again!

In the realm of planar 2D geometry, the formula for rotating a point (x,y) about the origin point (0,0) in the counter-clockwise direction is taken to be this:
new x = x * cos(angle) - y * sin(angle) new y = x * sin(angle) + y * cos(angle)
This can be adapted to SB pretty much directly, assuming all numbers are real-type. To rotate around a point that isn't the origin, simply subtract the center point's coordinates from the coordinates to rotate. SIN and COS take angles in radians. Some SB pseudo-code:
'assuming CX# and CY# are the coordinates of the center
'assuming X# and Y# are the coordinates of the point to be rotated
'assuming R# is the angle of rotation, in radians
'assuming NX# and NY# are the coordinates of the new point (the result)
C#=COS(R#)
S#=SIN(R#)
DX#=X#-CX#
DY#=Y#-CY#
NX#=DX#*C#-DY#*S
NY#=DX#*S#+DY#*C
Last two lines should be:
NX#=CX#+DX#*C#-DY#*S
NY#=CY#+DX#*S#+DY#*C

Last two lines should be:
NX#=CX#+DX#*C#-DY#*S
NY#=CY#+DX#*S#+DY#*C
He already handled the distance between the origin and the coordinates that are being rotated by using
DX#=X#-CX#
DY#=Y#-CY#

He already handled the distance between the origin and the coordinates that are being rotated by using
DX#=X#-CX#
DY#=Y#-CY#
He handled it before the rotation. He didn't handle it after the rotation. EDIT: Perhaps an analogy. I am standing at the bus-stop, waiting for a bus to go to school, when I realize I did not pack my lunch, it's still at home. I devise a solution: Step 1 - Go from the bus stop to home. Step 2 - Put lunch in my bag. Has the problem been solved? ... The getting-lunch is solved. The distance between the bus stop and home is "handled". But, a full solution requires the third step: Step 3 - Go from home to the bus stop.

Yeah Square is right here. What I did by subtracting the center point is effectively translating the point-to-be-rotated to the origin, since the rotation only works about the origin. I have to add the center point back to the result to orient it back around the center. So the last two lines should be to the tune of this:
NX#=DX#*C#-DY#*S#+CX#
NY#=DX#*S#+DY#*C#+CY#

The code does not work. I tested it using a line which rotates around the center of the screen. The line transforms in size both vertically and horizontally and eventually collapses into a single point at the center of the screen. It rotates, sort of. Seemingly erratic. Here's the code word for word.
A1#=60
B1#=60
A2#=234
B2#=200
OX#=160
OY#=120
ANG#=0
@L
BN=BUTTON()
GOSUB @D
IF BN THEN GOSUB @B
VSYNC 1
GOTO @L

@D
GCLS
GLINE A1#,B1#,A2#,B2#,RGB(255,255,255)
RETURN

@B
IF BN==1 THEN ANG#=ANG#+1
IF BN==2 THEN ANG#=ANG#-1
IF ANG#>360 THEN ANG#=0
IF ANG#<0 THEN ANG#=360

C#=COS(ANG#)
S#=SIN(ANG#)

DX1#=A1#-OX#
DY1#=B1#-OY#
DX2#=A2#-OX#
DY2#=B2#-OY#

A1#=DX1#*C#-DY1#*S#+OX#
B1#=DX1#*C#+DY1#*S#+OY#
A2#=DX1#*C#-DY1#*S#+OX#
B2#=DX1#*C#+DY1#*S#+OY#
RETURN
OX# and OY# are the OriginX and OriginY coordinates, while A1#, B1#, A2#, and B2# are the coordinates of the end points of this line. ANG# is the Angle of rotation (0<ANG<360) Is there something I'm doing wrong?

Try this code, I used it on my program ClockZ to rotate the sun and moon.
DIM RX[360],RY[360]
CX=200;CY=120
RD=50
FOR I=0 TO 359
 AN=RAD(I)
 RX[I]=SIN(AN)*RD+CX
 RY[I]=COS(AN)*RD+CY
NEXT
SPSET 0,0
SPOFS 0,CX,CY
SPSET 1,1
WHILE 1
 FOR I=0 TO 359
  SPOFS 1,RX[I],RY[I]
  VSYNC 1
 NEXT
WEND

First: From the previous code,
'assuming R# is the angle of rotation, in radians
You seem to be using degrees. Use COS(RAD(ANG#)) and SIN(RAD(ANG#)) instead. Second: A2 and B2 should use DX2 and DY2. Third: if you keep pressing 'up', for instance, ANG# will get ever bigger and the points get rotated by ANG# each time. So, say when you begin, you press 'up', ANG# will become 1, and the line will rotate by 1 degree. The next frame 'up' is pressed, ANG# will now be 2, and the line will be rotated by 2 degrees - from its current position, meaning 3 degrees from its starting orientation. Next frame, 6 degrees, then 10 degrees, then 15 degrees. If you then press 'down', ANG# will be 4, and the line will be at 19 degrees - yes, further in the same direction. If you want one frame of 'up' button to rotate one degree, then use IF BN==1 THEN ANG#=1. - Even better, IF (BN AND #UP)!=0 THEN ANG#=1. Either way, include at the beginning of the subroutine, ANG#=0, unless you want other buttons to cause rotation too. Also, you are accumulating rounding errors. On the fifth frame, you have a transformation of a transformation of a transformation of a transformation of a transformation of the original shape: with a little rounding error happening each time, you can see how this could be a problem.

I'm using a different method, which is to convert to polar coordinates, then rotate, and the convert back:
DEF ROTATE PX,PY,RX,RY,RA OUT PX2,PY2
 
'RX,RY,RA = rotation center, angle to rotate
'PX,PY,PX2,PY2 = point to rotate
'PX2,PY2 = new position (different variables needed for OUT)
VAR PA,PD 'polar coordinates (internal variables)

 '== rectangular -> polar ==
 PA=ATAN(RX-PX,RY-PY)
 PD=SQR(POW(PX-RX,2)+POW(PY-RY,2))
 
 '== rotate ==
 INC PA,RAD(RA-180) 'rotate
 
 '== polar -> rectangular ==
 PX2=SIN(PA)*PD+RX
 PY2=COS(PA)*PD+RY

END
tested and it works

I'm using a different method, which is to convert to polar coordinates, then rotate, and the convert back:
The 'OUT' parameters need a comma between them. The parameters should not be redeclared within the body of the function. They especially should not be redeclared twice. The angle PA should be calculated with regard the center of rotation RX, RY. The distance PD should be calculated with the Y-difference, rather than the X-difference twice.

The 'OUT' parameters need a comma between them. The parameters should not be redeclared within the body of the function. They especially should not be redeclared twice. The angle PA should be calculated with regard the center of rotation RX, RY. The distance PD should be calculated with the Y-difference, rather than the X-difference twice.
fixed. half of those were typos anyway EDIT: anyway, I tested mine and it works. Maybe not the fastest though... Also: SlackerSnail: "assuming all numbers are real-type" *adds type suffixes anyway*

Well, by adding the suffix I'm assuming the input and output are intended to be real-type. If you want it to be integer you can deal with that yourself I guess.

I've used the previous method several times on different languages and i cannot get it to work. I'll try the Polar Rotation method. I have no idea why the other does not work. Maybe someone can test it, the point does not rotate in a circle, but rather a figure 8 type of motion.

I've used the previous method several times on different languages and i cannot get it to work. I'll try the Polar Rotation method. I have no idea why the other does not work. Maybe someone can test it, the point does not rotate in a circle, but rather a figure 8 type of motion.
I've used the code in SlackerSnail's post (#2 in the thread), modified as in my post #4, and it works.

Hey look, code!

I saw the title of this thread and was so ready to run in screaming "I WROTE A FUNCTION FOR THIS IN DEFY!"