## Simple + More Advanced Ellipse Renderer

Pritchard
Posts: 5485
Joined: Sep 12, 2005 20:06
Location: Ohio, USA

### Simple + More Advanced Ellipse Renderer

Credits to Jofers and Kristopher Windsor for helping/showing how this is done. Figured I should post my versions in Tips & Tricks, so that one day yet another will be able to search and find two commented versions.

Also, props to anyone who can add a Simple and Clean precision step to this, so only the pixels that need to be drawn are, rather than just 0 to 360 step 1. With a small ellipse, it's a waste of CPU speed and with a larger ellipse, it's not enough to simply go 1 degree at a time for some.

Code: Select all

`#include once "fbgfx.bi"#define pi 3.14159265#define RadToDeg(__rad__) (__rad__ * (180/Pi))#define DegToRad(__rad__) (__rad__ * (pi/180))Declare Sub DrawEllipse( ByVal X as Integer, ByVal Y as Integer, ByVal W as Integer, ByVal H as Integer, ByVal Ang as Integer )Screenres 640, 480, 32'' Our settings.Dim as Integer X = 319, Y = 239, W = 60, H = 60, AngScreenlockDo    '' Get Key Presses  '' Move the Ellipse  If Multikey(FB.SC_LEFT) then X -= 1  If Multikey(FB.SC_RIGHT) then X += 1  If Multikey(FB.SC_UP) then Y -= 1  If Multikey(FB.SC_DOWN) then Y += 1  '' Change Ellipse Width  If Multikey(FB.SC_A) then W -= 1  If Multikey(FB.SC_D) then W += 1  '' Change Ellipse Height  If Multikey(FB.SC_W) then H += 1  If Multikey(FB.SC_S) then H -= 1  '' Increase Our Angle  Ang += 1    '' Check all of our variables and make sure they are valid.  If W < 1 then W = 1  If H < 1 then H = 1  If Ang > 359 then Ang = 0      '' Draw our ellipse.  DrawEllipse( X, Y, W, H, Ang )      '' "GUI" - Uhmm...Just text information ;p  '' Background  Line (0,0)-(250, 40), rgb(10, 20, 80), bf  Line (0,0)-(250, 40), rgb(80, 20, 10), b  Locate 1, 1  '' Text  Draw String (2,2), "Move with Arrow Keys"  Draw String (2,10), "Stretch Ellipse with WASD"  Draw String (2,18), "Pos: " & "(" & str(x) & "," & str(y) & "," & str(Ang) & ")"  Draw String (2,26), "W/H: " & "(" & str(w) & "," & str(h) & ")"    '' Flip our Page  screenunlock    sleep 15, 1  screenlock  cls    Loop until multikey(FB.SC_ESCAPE)screenunlockSub DrawEllipse( ByVal X as Integer, ByVal Y as Integer, ByVal W as Integer, ByVal H as Integer, ByVal Ang as Integer )    '' Ellipse Drawing Positions  Dim as Integer EX, EY  '' Rotated Positions  Dim as Double RX, RY  '' Our Sin/Cos Angles.  No reason to calculate it every step.  Dim as Double SinAng = Sin(DegToRad(Ang)), CosAng = Cos(DegToRad(Ang))    '' Custom Ratios.  Normally this would be r*cos(ang)  Ex = ( W * Cos(0) )  Ey = ( H * -Sin(0) )    '' Rotate our Ellipse.  We're rotating around our own center.  '' Since we didn't include our Drawing Positions, no complex math needed!  '' FYI:  This is rotate around ourself math, using our own center as origin!  Rx = ( Ex * CosAng ) - ( Ey * SinAng )  Ry = ( Ey * CosAng ) + ( Ex * SinAng )    '' Draw First Point.  '' We don't include X in the above math so we can have rotation free from  '' Our Ellipse Center  Pset ( X + Rx, Y + Ry ), rgb(255, 255, 255)    '' Loop through our ellipse angles.  For CurAng as Double = 1 to 360    '' Custom Ratios instead of Rad    Ex = ( W * Cos(DegToRad(CurAng)) )    Ey = ( H * -Sin(DegToRad(CurAng)) )        '' Rotate our Ellipse    Rx = ( Ex * CosAng ) - ( Ey * SinAng )    Ry = ( Ey * CosAng ) + ( Ex * SinAng )        '' A version of Line (x,y) - step (x2, y2)    '' Except this is nothing but a step.    Line - ( X + Rx, Y + Ry ), rgb(255, 255, 255)  NextEnd Sub`

You could add an arc begin/end to this by changing the For loop to go from StartAng to EndAng rather than 1 to 360, with only minor configuration.

Code: Select all

`#include once "fbgfx.bi"#define pi 3.14159265#define RadToDeg(__rad__) (__rad__ * (180/Pi))#define DegToRad(__rad__) (__rad__ * (pi/180))'' An ellipse object.'' Store info on the object here, render it.Type Ellipse  '' Ellipse Drawing Center  X as Integer  Y as Integer  '' Width/Height Ratios  W as Integer  H as Integer  '' Rotation Angle  Rot as Double = 0  '' Start/End Ang  BegAng as Double = 0  EndAng as Double = 360  '' Direction.  This is our loop step.  ArcStep as Integer = 1  '' Fill or not? 0 = No Fill.  <> 0 = Fill  '' Only fills if BegAng is 0, and EndAng is 360  Fill as Integer = 0    '' Draw the Ellipse.  Declare Sub Draw()End TypeScreenres 640, 480, 32'' Our settings.Dim as Ellipse MyArc'' PositionMyArc.X = 319MyArc.Y = 239'' SizeMyArc.W = 60MyArc.H = 60ScreenlockDo    '' Get Key Presses  '' Move the Ellipse  If Multikey(FB.SC_LEFT) then MyArc.BegAng -= 1  If Multikey(FB.SC_RIGHT) then MyArc.BegAng += 1  If Multikey(FB.SC_UP) then MyArc.EndAng -= 1  If Multikey(FB.SC_DOWN) then MyArc.EndAng += 1  '' Change Ellipse Width  If Multikey(FB.SC_A) then MyArc.W -= 1  If Multikey(FB.SC_D) then MyArc.W += 1  '' Change Ellipse Height  If Multikey(FB.SC_W) then MyArc.H += 1  If Multikey(FB.SC_S) then MyArc.H -= 1  '' Increase Our Angle  MyArc.Rot += 1    '' Check all of our variables and make sure they are valid.  If MyArc.W < 1 then MyArc.W = 1  If MyArc.H < 1 then MyArc.H = 1  If MyArc.Rot > 359 then MyArc.Rot = 0  If MyArc.BegAng < 0 then MyArc.BegAng += 360  If MyArc.BegAng > 360 then MyArc.BegAng -= 360  If MyArc.EndAng < 0 then MyArc.EndAng += 360  If MyArc.EndAng > 360 then MyArc.EndAng -= 360  '' Reverse Drawing Direction if our End Angle's less than our start angle.  If MyArc.EndAng < MyArc.BegAng then    MyArc.ArcStep = -1  Else    MyArc.ArcStep = 1  End If  '' Fill if we have a full Ellipse.  If ( MyArc.BegAng = 0 ) then    If ( MyArc.EndAng = 360 ) then      MyArc.Fill = 1    Else      MyArc.Fill = 0    End If  Else    MyArc.Fill = 0  End If      '' Draw our ellipse.  MyArc.Draw()      '' "GUI" - Uhmm...Just text information ;p  '' Background  Line (0,0)-(250, 48), rgb(10, 20, 80), bf  Line (0,0)-(250, 48), rgb(80, 20, 10), b  Locate 1, 1  '' Text  Draw String (2,2), "Change Arc With Arrow Keys"  Draw String (2,10), "Stretch Ellipse with WASD"  Draw String (2,18), "Pos: " & "(" & str(MyArc.x) & "," & str(MyArc.y) & "," & str(MyArc.Rot) & ")"  Draw String (2,26), "W/H: " & "(" & str(MyArc.w) & "," & str(MyArc.h) & ")"  Draw String (2,34), "Start/End Ang: " & "(" & str(MyArc.BegAng) & "," & str(MyArc.EndAng) & ")"    '' Flip our Page  screenunlock    sleep 15, 1  screenlock  cls    Loop until multikey(FB.SC_ESCAPE)screenunlockSub Ellipse.Draw()    '' Ellipse Drawing Positions  Dim as Integer EX, EY  '' Rotated Positions  Dim as Double RX, RY  '' Our Sin/Cos Angles.  No reason to calculate it every step.  Dim as Double SinAng = Sin(DegToRad(This.Rot)), CosAng = Cos(DegToRad(This.Rot))    '' Custom Ratios.  Normally this would be r*cos(ang)  Ex = ( This.W * Cos(DegToRad(This.BegAng)) )  Ey = ( This.H * -Sin(DegToRad(This.BegAng)) )    '' Rotate our Ellipse.  We're rotating around our own center.  '' Since we didn't include our Drawing Positions, no complex math needed!  '' FYI:  This is rotate around ourself math, using our own center as origin!  Rx = ( Ex * CosAng ) - ( Ey * SinAng )  Ry = ( Ey * CosAng ) + ( Ex * SinAng )    '' Draw First Point.  '' We don't include X in the above math so we can have rotation free from  '' Our Ellipse Center  Pset ( This.X + Rx, This.Y + Ry ), rgb(255, 255, 255)    '' Loop through our ellipse angles.  For CurAng as Double = This.BegAng + 1 to This.EndAng step This.ArcStep    '' Custom Ratios instead of Rad    Ex = ( This.W * Cos(DegToRad(CurAng)) )    Ey = ( This.H * -Sin(DegToRad(CurAng)) )        '' Rotate our Ellipse    Rx = ( Ex * CosAng ) - ( Ey * SinAng )    Ry = ( Ey * CosAng ) + ( Ex * SinAng )        '' A version of Line (x,y) - step (x2, y2)    '' Except this is nothing but a step.    Line - ( This.X + Rx, This.Y + Ry ), rgb(255, 255, 255)  Next    '' Fill our ellipse if we have chosen to do so.  If This.Fill <> 0 then    Paint (This.X, This.Y), rgb(255, 255, 255), rgb(255, 255, 255)  End IfEnd Sub`

And finally, here's a version useful for enemy paths, if you want to curve to direct from the player (center, edge of ellipse) to the target. Replace the "Advanced" Ellipse.Draw Sub with This One:

Code: Select all

`Sub Ellipse.Draw()   '' Ellipse Drawing Positions  Dim As Integer EX, EY  '' Rotated Positions  Dim As Double RX, RY  '' Origin Position  Dim as Integer OX, OY  '' Our Sin/Cos Angles.  No reason to calculate it every step.  Dim As Double SinAng = Sin(DegToRad(This.Rot)), CosAng = Cos(DegToRad(This.Rot))   '' Set an origin point for all of the ellipse drawing.  Ox = ( This.W * Cos(DegToRad(This.BegAng)) )  Oy = ( This.H * -Sin(DegToRad(This.BegAng)) )   '' Custom Ratios.  Normally this would be r*cos(ang)  Ex = ( This.W * Cos(DegToRad(This.BegAng)) ) + OX  Ey = ( This.H * -Sin(DegToRad(This.BegAng)) ) + OY    '' Rotate our Ellipse.  We're rotating around our own center.  '' Since we didn't include our Drawing Positions, no complex math needed!  '' FYI:  This is rotate around ourself math, using our own center as origin!  Rx = ( Ex * CosAng ) - ( Ey * SinAng )  Ry = ( Ey * CosAng ) + ( Ex * SinAng )   '' Draw First Point.  '' We don't include X in the above math so we can have rotation free from  '' Our Ellipse Center  Pset ( This.X + Rx, This.Y + Ry ), rgb(255, 255, 255)   '' Loop through our ellipse angles.  For CurAng As Double = This.BegAng + 1 To This.EndAng Step This.ArcStep    '' Custom Ratios instead of Rad    Ex = ( This.W * Cos(DegToRad(CurAng)) ) + OX    Ey = ( This.H * -Sin(DegToRad(CurAng)) ) + OY       '' Rotate our Ellipse    Rx = ( Ex * CosAng ) - ( Ey * SinAng )    Ry = ( Ey * CosAng ) + ( Ex * SinAng )       '' A version of Line (x,y) - step (x2, y2)    '' Except this is nothing but a step.    Line - ( This.X + Rx, This.Y + Ry ), rgb(255, 255, 255)  Next   '' Fill our ellipse if we have chosen to do so.  If This.Fill <> 0 Then    Paint (This.X + Rx / 2, This.Y + Ry / 2), rgb(255, 255, 255), rgb(255, 255, 255)  End IfEnd Sub`