Page 1 of 3
Drawing Arcs
Posted: Tue Aug 28, 2007 8:43 pm
by Xombie
I tried this question earlier in the GDI+ post under Tips & Tricks to no avail. So now I'm making it a little more generic.
How can I draw an elliptical arc at any angle of my choosing? Anti-aliased would be nice but I can live without if I have to. Also, when I say "at any angle" I mean to rotate the theoretical ellipse before tracing it's arc. I do not mean to just start the arc angle at some degree followed by a different end angle.
Hope that makes sense and that someone out there can help.
Posted: Tue Aug 28, 2007 9:26 pm
by Kaeru Gaman
you can first calculate the coordinates of the unrotated ellipse.
these could also be understood as a radius of a circle.
along this circle you can now rotate the point.
for each point on the (¼) ellipse you will get a different radius.
.

Posted: Tue Aug 28, 2007 10:53 pm
by Ollivier
(And to accelerate the execution of your algo)
(To explain what you wanna create, I put a convention : ^a = vector a)
In a classical plane (orthonormal or 'carthesian plane') named (O;^i;^j)
Code: Select all
>>O is the origin
>>^i is a horizontal vector (1;0) (x axial)
>>^j is a vertical vector (0;1) (y axial)
But these values are the result of trigo calcul like that:
Code: Select all
>> ^i [Cos(0); Sin(0) ]
>> ^j [Cos((Pi/2)+0); Sin((Pi/2)+0) ] }} (Results are above)
Zéro is the angle of your draw (ellipse) in the plane (Z rotation)
So you replace 0 by a variable 'Zr'
Code: Select all
>> ^i [Cos(Zr); Sin(Zr) ]
>> ^j [Cos(Pi/2+Zr); Sin(Pi/2+Zr) ]
Now, when you have a point p(x, y), you know that:
Code: Select all
^p = x^i + y^j (syntax: x^i = x*^i)
^p = x^[Cos(Zr); Sin(Zr) ] + y^[Cos((Pi/2)+Zr); Sin((Pi/2)+Zr) ]
^p = x^[A; B] + y^[C; D]
= ^p[xA + yC; xB + yD] (Sum of 2 vectors)
= ^p[ xCos(Zr) + yCos((Pi/2)+Zr) ; xSin(Zr) + ySin((Pi/2)+Zr) ]
Examples:
>> Zr = 0 (no rotation)
Code: Select all
^p1[ xCos(0) + yCos((Pi/2)+0) ; xSin(0) + ySin((Pi/2)+0) ]
^p1[ x*1 + y*0) ; x*0 + y*1]
^p1[ x ; y ]
>> Zr = Pi/2 (90° left rotation)
Code: Select all
^p2[ xCos(Pi/2) + yCos((Pi/2)+Pi/2) ; xSin(Pi/2) + ySin((Pi/2)+Pi/2) ]
^p2[ xCos(Pi/2) + yCos(Pi) ; xSin(Pi/2) + ySin(Pi) ]
^p2[ x*0 + y*-1 ; x*1 + y*0 ]
^p2[ -y ; x ]
To begin a 3D engine, I
wrote this code:
Code: Select all
InitSprite()
InitKeyboard()
OpenScreen(1024, 768, 32, "x")
;***********
R.F = 100.0
Xtheta.F = 0.0
Ytheta.F = 0.0
Ztheta.F = 0.0
Ttheta.F = 0.0
;***********
Repeat
StartDrawing(ScreenOutput() )
Box(0, 0, 1024, 768, #Black)
Vxx.F = Cos(Ztheta)
Vxy.F = -Sin(Ztheta)
Vyx.F = Cos(Ztheta + #PI / 2.0)
Vyy.F = -Sin(Ztheta + #PI / 2.0)
Line(512, 384, Vxx * 20.0, Vxy * 20.0, #Blue)
Line(512, 384, Vyx * 20.0, Vyy * 20.0, #Blue)
For i = 0 To 359
; MaJ référentiel Vecteur x et Vecteur y
X.F = #PI * i / 180.0
Tx.F = Cos(X) * Cos(Ytheta) * 100.0
Ty.F = Sin(X) * 100.0
Ex.F = Vxx * Tx + Vxy * Ty
Ey.F = Vxy * Tx + Vyy * Ty
;Trace vecteur E
Plot(512 + Ex, 384 + Ey, #Blue)
If Abs(X - Xtheta) < 0.01
Line(512, 384, Ex, Ey, #White)
Box(511 + Ex, 383 + Ey, 3, 3, #White)
EndIf
Next
Xtmp = Xtheta * 180 / #PI
Xtmp % 180
DrawText(0, 0, Str(Xtmp), #White, #Black)
Ytmp = Ytheta * 180 / #PI
Ytmp % 180
DrawText(0, 16, Str(Ytmp), #White, #Black)
ZTmp = (Ztheta * 180 / #PI)
Ztmp % 180
DrawText(0, 32, Str(Ztmp), #White, #Black)
DrawText(0, 48, "ARROW KEYS PageUp PageDown to change x, y, et z values")
StopDrawing()
FlipBuffers()
ExamineKeyboard()
If KeyboardPushed(#PB_Key_PageUp)
Ztheta + 0.04
EndIf
If KeyboardPushed(#PB_Key_PageDown)
Ztheta - 0.04
EndIf
If KeyboardPushed(#PB_Key_Up)
Xtheta + 0.04
If Xtheta > 2.0 * #PI
Xtheta - 2.0 * #PI
EndIf
EndIf
If KeyboardPushed(#PB_Key_Down)
Xtheta - 0.04
If Xtheta < 0.0
Xtheta + 2.0 * #PI
EndIf
EndIf
If KeyboardPushed(#PB_Key_Left)
Ytheta + 0.04
EndIf
If KeyboardPushed(#PB_Key_Right)
Ytheta - 0.04
EndIf
Until KeyboardPushed(#PB_Key_Escape)
Posted: Wed Aug 29, 2007 6:33 pm
by Xombie
Thanks, Kaeru Gaman and Ollivier.
Your code is really nifty, Ollivier (I especially like the 3D view) but way beyond my means. I only need a simple 2d elliptical arc that can be rotated about it's ... Y? axis.
And I'm afraid I don't quite follow your example, Kaeru Gaman. I'm afraid I'm just not a mathematician =/
Would I be able to beg an algorithm or a link to an algorithm in any language that would allow me to draw an elliptical arc rotated an arbitrary amount?
Sorry for being greedy but I tried digging around with Google and came up short. Lines and rectangles are more my speed

Posted: Wed Aug 29, 2007 7:13 pm
by Ollivier
I'm just not a mathematician =/
Excuse me!
Kaeru show you (really good draw

) how to turn your draw.
Do you know drawing a circle with 'Plot' in a loop 'For...Next'?
Posted: Thu Aug 30, 2007 3:32 pm
by Xombie
Well, I know drawing and understand the basic programming side of it. My problem comes in when having to work out the formulas for the thing I'm drawing.
I'm pretty sure I could work out a circle, though.
Posted: Thu Aug 30, 2007 5:30 pm
by Kaeru Gaman
my point was, when you can draw a horizontal ellipse, you can work the rotation out.
- you calculate an x/y for a point on the horizontal ellipse.
- from this x/y, you take the radius and angle, to interprete it as a point on a circle.
- you turn the angle of this radius along your desired rotation angle.
- you plot the point.
- repeat all these steps for each desired point of the ellipse.
you will get different radiuses each calculation.
the result will be a rotated ellipse.
this is just the theory behind it.
sorry, I'm too lazy to work it out as code right now.
and I think, understanding this basic concept will help you more than a complete routine.

Posted: Thu Aug 30, 2007 5:57 pm
by Helle
Is this too simple?
Code: Select all
Width = 500
Height = 300
If OpenWindow(0, 0, 0, Width, Height+1, "Rotations-Ellipse", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
If StartDrawing(WindowOutput(0))
i = 1
x = Width/2
y = Height/2
For w = 0 To 360
If w <= 90 Or w>=270
col = 1234
Else
col = 123456
EndIf
Ellipse(x, y, x*Cos(w*#PI/180), y, col+i)
FillArea(0, 0, col+i, RGB(212, 208, 200))
i = ~i
Delay(10)
Next
StopDrawing()
EndIf
Repeat : Event = WaitWindowEvent() : Until Event = #PB_Event_CloseWindow
EndIf
Gruss
Helle
Posted: Sat Sep 01, 2007 10:26 am
by Ollivier
Code: Select all
xCenter FLOAT (pixel)
yCenter FLOAT (pixel)
xRadius FLOAT (pixel)
yRadius FLOAT (pixel)
zRotation FLOAT (rad)
StartAngle FLOAT (rad)
FinishAngle FLOAT (rad)
Code: Select all
Procedure EllipseWithRotation(xCenter.F, yCenter.F, xRadius.F, yRadius.F, zRotation.F, StartAngle.F, FinishAngle.F, Color.L)
Protected Angle.F
Protected AngleStep.F
Protected X.F
Protected Y.F
Protected DisplayX.F
Protected DisplayY.F
Protected GreatestRadius.F
If xRadius > yRadius
GreatestRadius.F = xRadius
Else
GreatestRadius = yRadius
EndIf
AngleStep.F = #PI / GreatestRadius
NewList DrawX.POINT()
Angle = StartAngle
Repeat
X.F = Cos(Angle) * xRadius ; Draw an ellipse...
Y.F = -Sin(Angle) * yRadius
DisplayX.F = X * Cos(zRotation) - Y * Sin(zRotation) ; Rotation...
DisplayY.F = X * Sin(zRotation) + Y * Cos(zRotation)
AddElement(DrawX() ) ; Record...
DrawX()\X = xCenter + DisplayX
DrawX()\Y = yCenter + DisplayY
Angle + AngleStep
Until Angle > FinishAngle
ResetList(DrawX() ) ; Draw...
For i = 1 To CountList(DrawX() ) - 1
SelectElement(DrawX(), i - 1)
x1 = DrawX()\X
y1 = DrawX()\Y
SelectElement(DrawX(), i)
x2 = DrawX()\X
y2 = DrawX()\Y
LineXY(x1, y1, x2, y2, Color)
Next
ClearList(DrawX() )
EndProcedure
Nice day!
Posted: Sat Sep 01, 2007 11:29 am
by dell_jockey
Look Ma! No API....
Well done, thanks a lot Ollivier! Your usage of lists forces me to re-think parts of an application that I'm currently developing. Thanks again.
Posted: Sat Sep 01, 2007 11:44 am
by Ollivier
Indeed, lists offer many possibilities

Posted: Sat Sep 01, 2007 12:00 pm
by Ollivier
2 Xombie (or somebody who knows the answer)
What is 'anti-aliased' ???
Posted: Sat Sep 01, 2007 12:36 pm
by dell_jockey
Ollivier,
check out:
http://en.wikipedia.org/wiki/Xiaolin_Wu ... _algorithm
Xiaolin Wu's algorithm is one of many anti-aliassing techniques.
bye
Hans
Posted: Sat Sep 01, 2007 12:57 pm
by Ollivier
So, reading the wikipedia's article, I think I answer Xombie enough correctly... With a list! He'll have just to manage the 2 lines 'NewList' and 'ClearList' to recuperate coordonates x and y arcs...
Thanks
Posted: Sat Sep 01, 2007 8:11 pm
by Xombie
Thanks, everyone! I'm excited to try this out tonight and see what kind of damage I can do.
So, yes, thanks again for being patient with me even though I'm quite slow at stuff like this :p
Thanks again, Ollivier, Helle and Kaeru Gaman!