draw a arc

General discussion relating to the library modules supplied with the compiler

Moderators: David Barker, Jerry Messina

Post Reply
Mast
Posts: 65
Joined: Wed Aug 29, 2007 6:24 am
Location: France

draw a arc

Post by Mast » Fri Jan 29, 2010 10:47 pm

hello,
how can i draw a arc with the ks0108. i can't find it in the graphic module.

thanks

Francis
Registered User
Registered User
Posts: 314
Joined: Sun Mar 25, 2007 9:40 am
Location: Devon

Post by Francis » Sat Jan 30, 2010 9:10 am

If it isn't there then you'll have to roll your own.

I would start by looking up equations of circles, both Cartesian and using good old Pythagorus. This should help to derive an equation to work out coordinates.

With a bit of fiddling I'm sure you could produce a useful function that could draw arcs and sectors.
There may be functions already posted on the Nerdynet.

Mast
Posts: 65
Joined: Wed Aug 29, 2007 6:24 am
Location: France

Post by Mast » Sat Jan 30, 2010 12:29 pm

Thanks Francis

Raistlin
Registered User
Registered User
Posts: 69
Joined: Tue Apr 01, 2008 1:13 pm

Post by Raistlin » Sat Jan 30, 2010 1:18 pm

depending on the ARC you want if its a quater circle look up Bresenham cirlce algo and only iterate a quarter. The circle algo in GLCD lib is bresh i beleive , so you could copy the function rename and mod for arc.

http://en.wikipedia.org/wiki/Midpoint_circle_algorithm to start you off

if you want a more complex curve look for the Bezier curve algo

http://en.wikipedia.org/wiki/B%C3%A9zier_curve to start you off there

for bezier cubic form is probably easiest to implement and most useful.
a simple arc can be made with either (cubic bezier make P1 and p2 the same a line midpoit to create an isoslies triange in coords)

Bresanham is faster to compute and better for a true circle (or part of) bezier (slpines) is better for sweeping curves.
If you can read this you are too close

User avatar
RangerBob
Posts: 152
Joined: Thu May 31, 2007 8:52 am
Location: Beds, UK

Post by RangerBob » Sun Jan 31, 2010 9:27 am

Hello Mast,

I assume you are after a circular arc? I wound up modifying a set of drawing routines in "the other compiler" for an SSD0323 Oled Driver, heres the bit of interest to you. Should be fairly easy to convert to SF basic. The sub call PIXELWIDTH_ON_OFF is just the actual pixel draw sub. If you're having problems with it let me know and i'll try to help - its been a while though!

Nathan

Edit: Next reply has actual code now

User avatar
RangerBob
Posts: 152
Joined: Thu May 31, 2007 8:52 am
Location: Beds, UK

Post by RangerBob » Tue Feb 02, 2010 11:59 am

Ok, I got bored and it was bothering me that I hadn't done the code, so here it is.

Dependent upon Maths.bas and GLCD.bas

Image

Code: Select all

{
********************************************************************************
* Name    : DrawArc                                     			           *
* Purpose : Draws a circular arc section									   *
********************************************************************************
} 
  
Sub DrawArc(xCentre As Word, yCentre As Word, radius As Word, xStart As Word, yStart As Word, xEnd As Word, yEnd As Word)

	Dim ang1 As Float
	Dim ang2 As Float
	Dim tempfloat1 As Float
	Dim tempfloat2 As Float
	Dim xDraw As Word
	Dim yDraw As Word
	Dim tempword1 as word
	Dim tempword2 as word

	// Set the Granularity of the plot
	// 0.03 is a bit fine (i.e. small gaps in arc), 0.02 is moderate, 0.01 is a bit coarser (i.e. certain points start to get heavy)
	Const Granularity = 0.02

	// Check Ang1
	If xStart - xCentre = 0 Then
		If yStart < yCentre Then
			ang1 = 3 * 3.14 / 2
		Else
			ang1 = 3.14 / 2
		EndIf
	ElseIf yStart = yCentre Then
		If xStart < xCentre Then
			ang1 = 3.14
		Else
			ang1 = 0
		EndIf
 	
	Else
         
		If xStart > xCentre And yStart > yCentre Then 	// Quadrant 1
			tempword1 = (yStart - yCentre)
			tempword2 = (xStart - xCentre)
			ang1 = tempword1 / tempword2
			ang1 = atan(ang1)
		EndIf
         
		If xStart < xCentre And yStart > yCentre Then	// Quadrant 2 
			tempword1 = (yStart - yCentre)
			tempword2 = (xCentre - xStart)
			ang1 = tempword1 / tempword2
			ang1 = 3.14 - (atan(ang1))
		EndIf
         
		If xStart < xCentre And yStart < yCentre Then	// Quadrant 3 
			tempword1 = (yCentre - yStart)
			tempword2 = (xCentre - xStart)
			ang1 = tempword1 / tempword2
			ang1 = (atan(ang1)) + 3.14
		EndIf
         
		If xStart > xCentre And yStart < yCentre Then 	// Quadrant 4
			tempword1 = (yCentre - yStart)
			tempword2 = (xStart - xCentre)
			ang1 = tempword1 / tempword2
			ang1 = (2 * 3.14) - (atan(ang1))
		EndIf
         
	EndIf
            
	// Check Ang2
	If xEnd - xCentre = 0 Then
		If yEnd < yCentre Then
			ang2 = 3 * 3.14 / 2
		Else
			ang2 = 3.14 / 2
		EndIf
	ElseIf yEnd = yCentre Then
		If xEnd < xCentre Then
			ang2 = 3.14
		Else
			ang2 = 0
		EndIf
	Else
         
		If xEnd > xCentre And yEnd > yCentre Then	// Quadrant 1
			tempword1 = (yEnd - yCentre)
			tempword2 = (xEnd - xCentre)
			ang2 = tempword1 / tempword2
			ang2 = atan(ang2)		
		EndIf
         
		If xEnd < xCentre And yEnd > yCentre Then	// Quadrant 2
			tempword1 = (yEnd - yCentre)
			tempword2 = (xCentre - xEnd)
			ang2 = tempword1 / tempword2
			ang2 = 3.14 - (atan(ang2))
		EndIf
         
		If xEnd < xCentre And yEnd < yCentre Then	// Quadrant 3
			tempword1 = (yCentre - yEnd)
			tempword2 = (xCentre - xEnd)
			ang2 = tempword1 / tempword2
			ang2 = (atan(ang2)) + 3.14
		EndIf
         
		If xEnd > xCentre And yEnd < yCentre Then	// Quadrant 4
			tempword1 = (yCentre - yEnd)
			tempword2 = (xEnd - xCentre)
			ang2 = tempword1 / tempword2
			ang2 = (2 * 3.14) - (atan(ang2))
		EndIf
         
	EndIf
            
	// draws anti-clockwise
      
	Repeat
		tempfloat1 = radius * (cos(ang1))
		tempfloat2 = radius * (sin(ang1))
		xDraw = xCentre + tempfloat1
		yDraw = yCentre - tempfloat2
        SetPixel(xDraw, yDraw) 
		ang1 = ang1 + Granularity
		tempfloat1 = ang2 - 0.05
		tempfloat2 = ang2 + 0.05
		If ang1 > (2 * 3.14) Then 
			ang1 = 0
		EndIf			
	Until ang1 > tempfloat1 And ang1 < tempfloat2

End Sub
Edit: Reduced the amount of excess FP math as per Octal's suggestion
Last edited by RangerBob on Wed Feb 03, 2010 9:45 am, edited 1 time in total.

User avatar
octal
Registered User
Registered User
Posts: 586
Joined: Thu Jan 11, 2007 12:49 pm
Location: Paris IDF
Contact:

Post by octal » Tue Feb 02, 2010 12:18 pm

Nice work,
but I think about two things:
1- Avoiding Floating points is mandatory if you want it to be quick enough, so you can use integers and move your floating point accordingly when interpreting results.

2- If the user wants to draw an arc dynamically to show some measurements for example, if he use this code intensively it will be really cpu intensive, and if he wants to use it just to draw an arc at background and later darw a line on top of it to show a level meter for example the best is to use simply a bitmap.

Regards

User avatar
RangerBob
Posts: 152
Joined: Thu May 31, 2007 8:52 am
Location: Beds, UK

Post by RangerBob » Tue Feb 02, 2010 2:17 pm

Fair points,
octal wrote: 1- Avoiding Floating points is mandatory if you want it to be quick enough, so you can use integers and move your floating point accordingly when interpreting results.
Depends what you consider is quick enough really. In a typical application this was used with at an update rate of once per second on a 32mhz 4550, along with a bunch of other intensive operations and it barely taxed it (plenty of spare cycles left over). I could have avoided floats but maths is hard! ;)
octal wrote: and if he wants to use it just to draw an arc at background and later darw a line on top of it to show a level meter for example the best is to use simply a bitmap.
Depends how big you want the meter to be ;). I specifically wrote this originally for exactly this type of application. The customer wanted a *big* meter though and the bitmap was huge 6k, I wrote this to save space in comparison (plus for flexibility)! This code is 4k. Swings and roundabouts really.

Regards,

Nathan

Mast
Posts: 65
Joined: Wed Aug 29, 2007 6:24 am
Location: France

Post by Mast » Thu Mar 04, 2010 9:55 am

Thank you RangerBob :)

on my GLCD i want write a inclinometer ADXL

Image

User avatar
RangerBob
Posts: 152
Joined: Thu May 31, 2007 8:52 am
Location: Beds, UK

Post by RangerBob » Thu Mar 04, 2010 11:34 am

This might be Handy for you then:

Code: Select all

{
********************************************************************************
* Name    : DrawLineAngle                                                      *
* Purpose : Draws a line at given angle in pelorus                             *
********************************************************************************
} 
Public Sub DrawLineAngle(lineangle As Float, pencolor As Byte)

	Dim sinresult As Float
	Dim cosresult As Float
	Dim pointerxf As Byte
	Dim pointeryf As Byte
	Dim pointerxb As Byte
	Dim pointeryb As Byte

	lineangle = (lineangle * 3.14) / 180  
			
	sinresult = sin(lineangle)	
	cosresult = cos(lineangle)
	
	pointerxf = abs( PelCenterX - (PelRadOut - 4) * sinresult )	'fx - outer radius
	pointeryf = abs( PelCenterY + (PelRadOut - 4) * cosresult )	'fy + outer radius
	pointerxb = abs( PelCenterX - (PelRadIn + 2) * sinresult )	'fx - inner radius
	pointeryb = abs( PelCenterY + (PelRadIn + 2) * cosresult )  'fy + inner radius 
		
	// Draw New Line
	Pen.Color = pencolor
	Line(pointerxb,pointeryb,pointerxf,pointeryf)
		
End Sub
Have fun ;) No sense reinventing the wheel!

[edit] Fuzzy, lousy Pic of code in action; Darn you iPhone camera!
darker line is a trend line, brighter current. Couldn;t figure out how to do a quick and easy pointy top to line like yours!

Image

Post Reply