Feeds:
Posts
Comments

Archive for January, 2011

Johnsprogram asks,

I’m having a math-related crisis that one man (me) can not do alone. I’m trying to figure out a way to calculate the radius of the ellipse on the same angle as the light blue line; in other words, the length of the “mystery line.”

He attached a picture which didn’t do too much to help explain matters, but what he wanted to know was the distance from the centre of the ellipse to the edge, at a given angle.

We can assume that the ellipse is oriented vertically. TheĀ locus of the edge of the ellipse is, in this case,

(\frac{x}{r_x})^2 + (\frac{y}{r_y})^2 = 1,

where r_x and r_y are the horizontal and vertical radii.

We want to know the length of the line heading at an angle \theta from the vertical to the edge of the ellipse. Call the length L, so the co-ordinates of the end are given by

x = L \sin(\theta),

y = L \cos(\theta).

Substitute those into the first equation:

(L \frac{\sin(\theta)}{r_x})^2 + (L \frac{\cos(\theta)}{r_y})^2 = 1.

Take a factor of L^2 out:

L^2 ( \left ( \frac{\sin(\theta)}{r_x} \right )^2 + \left ( \frac{\cos(\theta)}{r_y} \right )^2) = 1,

and rearrange:

L = \sqrt{ \frac{1}{\left ( \frac{\sin(\theta)}{r_x} \right )^2 + \left ( \frac{\cos(\theta)}{r_y} \right )^2}}.

Here’s some code:

Graphics 600,600,0

an = 60
While Not (KeyHit(KEY_ESCAPE) Or AppTerminate())

	ew# = MouseX()-300
	eh# = MouseY()-300
	
	SetColor 100,100,100
	DrawOval 300-ew,300-eh,ew*2,eh*2
	
	an:+1
	
	l# = Sqr( 1/( (Sin(an)/ew)^2 + (Cos(an)/eh)^2) )
	
	lx# = 300+l*Sin(an)
	ly# = 300-l*Cos(an)
	
	SetColor 0,0,255
	DrawLine 300,300,lx,ly
	
	Flip
	Cls
Wend

Read Full Post »

Drawing dotted lines

Suppose you’ve got a set of points you want to join up with dotted lines, spaced a certain distance apart.

Bresenham isn’t the right algorithm for this – the gaps between the dots are bound to be a lot bigger than single pixels, so ‘stupid’ linear interpolation should do the job satisfactorily.

However, if you want to make sure you definitely draw the start and end points of a line, as well as dots in between, or if you want to draw a line made up of several segments, it gets a bit more complicated.

Here are two methods:

The first tries to draw each line segment so that its start and end points get a dot, and then it changes the size of the gaps slightly so that all the dots are evenly spaced right up to the end.

The second goes along between the points, drawing dots at the given distance apart from each other. It might not draw dots exactly on the given points, but the dots are always exactly the right distance apart.

Strict

'this method will draw each line segment individually
'it will change the gap slightly so that the dots are spread evenly along each segment
'it always draws a dot on each corner and endpoint
Function drawdots1(points#[], gap#)
	If Len(points)<4 Return	'need at least two pairs of co-ordinates
	
	Local sx#,sy#,ex#,ey#
	Local dx#,dy#,d#,steps,tgap#
	Local x#,y#
	
	DrawDot points[0],points[1]	'draw a dot at the start of the line
	
	For Local i=0 To Len(points)-3 Step 2		'draw each line segment
	
		sx=points[i]			'get start and end of this segment
		sy=points[i+1]
		ex=points[i+2]
		ey=points[i+3]
				
		dx# = ex-sx			'calculate a vector in the direction of the line, so we can get the distance
		dy# = ey-sy
		d# = Sqr(dx*dx+dy*dy)
		
		steps = round(d/gap)	'work out how many dots to draw (distance between the points, divide by the desired gap size). Round to nearest whole number
		tgap# = d/steps		'work out what the gap needs to be to space the calculated number of needed dots evenly
		
		dx:*tgap/d			'work out the vector between each dot
		dy:*tgap/d
		
		For Local j=1 To steps
			x# = sx+j*dx	'calculate the dot's position by adding the gap vector to the position of the start of the line
			y# = sy+j*dy
			DrawDot x,y	'draw a dot
		Next
	Next
End Function

'this method will draw dots evenly spaced along the whole set of lines
'it might not draw dots on the corners.
Function drawdots2(points#[],gap#)
	If Len(points)<4 Return	'need at least two pairs of co-ordinates

	Local sx#,sy#,ex#,ey#
	Local dx#,dy#,d#,tstep#
	Local x#,y#
	
	Local t#=0	't will keep track of how far along each line segment we are - 0 for at the start, 1 for at the end
	
	For Local i=0 To Len(points)-3 Step 2	'go through the line segments
	
		sx=points[i]			'get start and end of this segment
		sy=points[i+1]
		ex=points[i+2]
		ey=points[i+3]
	
		dx = ex-sx			'work out a vector in the direction of the line
		dy = ey-sy
		d = Sqr(dx*dx+dy*dy)	'work out the length of the line
		
		tstep# = gap/d		'work out what fraction of the line each gap represents
		
		While t<1		'draw dots until we reach the end of the line
		
			x = sx+dx*t	'work out the position of the dot by multiplying the vector by t
			y = sy+dy*t
			DrawDot x,y	'draw the dot
			t:+tstep		'increase t by the amount corresponding to a gap
		Wend
		
		t:-1				'when we reach the end of the line, t might be more than 1, meaning we didn't manage to get a whole gap in at the end
						'subtract 1 from t, and carry over the remainder to the next line segment
	Next
	
	DrawDot ex,ey			'draw the end point of the line. 
End Function

Function DrawDot(x#,y#)
	DrawOval x-2,y-2,4,4
End Function

Function Round(f#)	'round a floating point number to the nearest whole number
	Local i = Floor(f)
	If f-i>=.5
		Return i+1
	Else
		Return i
	EndIf
End Function


Graphics 800,600,0
Local points#[]
Local mode=0
Local gapsize#=20

While Not (KeyHit(KEY_ESCAPE) Or AppTerminate())
	DrawText "Click the mouse!",0,0
	DrawText "Right-click to change methods",0,15
	DrawText "Press up/down to change gap size",0,30

	If MouseHit(1)
		points :+ [Float(MouseX()),Float(MouseY())]
		If Len(points)>16
			points=points[2..]
		EndIf
	EndIf
	
	If MouseHit(2)
		mode=1-mode
	EndIf
	
	gapsize :+ (KeyDown(KEY_UP)-KeyDown(KEY_DOWN))*.25
	If gapsize<1 gapsize=1
	DrawText "Gap Size: "+gapsize,400,15
	
	If mode=0
		drawdots1(points,gapsize)
		DrawText "Using Method 1",400,0
	Else
		drawdots2(points,gapsize)
		DrawText "Using Method 2",400,0
	EndIf
	Flip
	Cls
Wend

Edited on 4/5/2011: anubis pointed out that the posted code was all mangled. I think I’ve fixed it, but in case I haven’t, here’s a link to the bmx file.

Read Full Post »