Function G2(StartX, StartY, EndX, EndY, Radius)

Blitz3D Forums/Blitz3D Programming/Function G2(StartX, StartY, EndX, EndY, Radius)

Staton_Richardson(Posted 2008) [#1]
I'm trying to wrap my head around a function to draw and arc
I'm working on a simple drawing program for my CNC machine

The G-codes I'm trying to work out are G2 and G3
Function G2(StartX#, StartY#, EndX#, EndY#, Radius#)

It draws an arc from start to end based on the radius.
I'm thinking about using the mouse wheel to change radius
after I draw a line.

What I'm doing is trying to trace an image by drawing lines
and arcs to generate the GCode for the CNC machine.


Ross C(Posted 2008) [#2]
Well, what your function fails to do it determine what side of the arc the raduis is on. From that information you have given, it could be either side.

Now, once you have figured which side the arc should bend away from, you need to find the centre point of the start and end co-ords. Very easy to do.

MiddleX = StartX + ((EndX - StartX)/2)
MiddleY = StartY + ((EndY - StartY)/2)


That will give you the middle co-ords. You now need to find the angle the line above is going at. I believe the ATan2 function gives you this angle.

http://www.blitzbasic.com/b3ddocs/command.php?name=ATan2&ref=2d_a-z

Once you have the angle, work out the perpendicular (90 degree) angle to that. Call it "perp_angle" just for example sake. Then from the middle co-ords you worked out, pull away from the mid point at the "perp_angle", to give you your point to start to draw the arc from, draw_x, and draw_y for examples sake.

From the point you worked out above, you will need to work out the start angle and end angle. You do this by working out the angle between the draw_x and draw_y. From these points:

for loop = start_angle to end_angle

plot cos(loop)*raduis,sin(loop)*raduis

next

that should draw your curve :o)

I may have messed up the order of sin and cos, but the theory should work fine.


Staton_Richardson(Posted 2008) [#3]
Thanks Ross. That looks like the math I was looking for. I'll see if I can work out the code and post it here.
There are two instructions in Gcode for cutting an arc one is
G2 Clockwise and and G3 Counter Clockwise. those commands
take even less parameters than the function I was looking
at. They would look something like this.
G2 5 5 2.5
what it does is takes the current position of the cutter and
cuts and arc to coord 5,5 with a circle radius of 2.5

This cuts a circle

G01 Z 0.2 F5 (retract)
G01 X1.5 Y1.135 (move to starting point)
G01 Z-0.5 F5 (plung)
G03 X 1.865 Y 1.500 R 0.365 F10 (quadrant 1)
G03 X 1.500 Y 1.865 R 0.365 F10 (quadrant 2)
G03 X 1.135 Y 1.500 R 0.365 F10 (quadrant 3)
G03 X 1.500 Y 1.135 R 0.365 F10 (quadrant 4)
G00 Z 0.2 (retract)

http://xdobs.com/cnc/gcode-introduction.html

Thanks again


Ross C(Posted 2008) [#4]
You'll need to wait till i get back from work, as i don't have access to blitz here so i can't test what i think ;o) Usually a bad thing :o)

Should be home in 3 hours


Ross C(Posted 2008) [#5]
Ok, my function doesn't work great. I th9ink i have given you the wrong info so i'm gonna work this out :o)


Ross C(Posted 2008) [#6]
Ok, i'm a bit baffled here. I take it the larger the radius, the more it curves? Reason being, i initially thought the radius was the radius of the circle the curve was being drawn from, but it can't be. That would be impossible.

So, is the radius how far out the curve peaks from the line that joins the two points?


Staton_Richardson(Posted 2008) [#7]
It's the greater the radius the flatter the curve.
If the distance between the two points is 5 and the
radius is set to 2.5 then it's a half circle. angle is 180
if the radius is 5 then it's 1/4th of a circle. angle is 90
if the radius is 10 then it's 1/8th of a circle. angle is 45
20 1/16th angle 22.5
40 1/32 angle 11.25

you were right in your first assumption.
The most I could figure out was finding a point
on a perpendicular from the midpoint of the line
and then finding where the radius length hit the line from
each endpoint. then doing a sweep from there.


Ross C(Posted 2008) [#8]
I tried last night again, but, imagine this.

Distance between the two points is 5. Radius is 1. This just wouldn't work?


Stevie G(Posted 2008) [#9]
Don't you need to know the direction that the cutter travelled to get to the first point to do this properly. Logically, this will have a big influence on the curve. Do you have that information?

I'm guessing that the radius cannot be less a 1/4 of the distance between the two points, since ...

Angle = 90 * ( DistanceBetweenPoints / Radius )

... would be greater than 360 degrees.

It seems like a bizarre way of drawing to me but then again I know nothing about cutting machines. Can you explain all this in more detail or show a mock drawing? I should be able to help if I can visualise it - unless Ross beats me to it - which is par for the course these days.

Stevie


Ross C(Posted 2008) [#10]
not this time matey. just bought a ps3 sofire in. you got a better math head than me anyway!


Staton_Richardson(Posted 2008) [#11]
The Radius can't be less than half the distance between the
two points.
I tried using a smaller number in Mach3 and it kept it at
the possible radius.

PC= Start
PT = End
R = Radius

[img ]


Ross C(Posted 2008) [#12]
AH, that's cool then, because that had me scratching my head, and produced some funny results in blitz when the radius was set to less than half of LC.

That way i see it, is the curve is part of a perfect circle, and for that, it should be easy to draw :o) Notice from point PC to the point halfway across LC, to the radius start point, it's a right angled triangle.

You know the length of the radius, one side of the triangle, and you know the length of the other side, half of LC.

From that you should be able to calculate the length of the line stretching from the centre point of LC, to the start point of the radius. Now you know this, you have a start point to begin your curve. Work out the angle from the start draw point to PC and PT. From there, simple plot a line of points from those two angles.

for loop = start_angle to end_angle

plot cos(loop)*raduis,sin(loop)*raduis

next


Should do the trick. I'm at work again, so maybe i'll get home before stevie and beat him to it again :oP


Staton_Richardson(Posted 2008) [#13]
a^2+b^2=c^2
c=radius
a=1/2 distance from start and end
b= the length perpendicular from the midpoint

translation on the points gets the radius point

then as you said plot cos sin angle radius


Ross C(Posted 2008) [#14]
Have you tried this in blitz yet?


Staton_Richardson(Posted 2008) [#15]
Here's my start
it's very flawed but the math should be all there
Mouse wheel adjusts the radius and I haven't got the
angles to the start and end point from the center
the curve also doesn't follow the mouse from the center
like it should

Graphics 640, 480, 32, 2
SetBuffer BackBuffer()
startx=320
starty=240
Radius=100
While Not KeyHit(1)
	LockBuffer()
	ms = MilliSecs()
	mx = MouseX()
	my = MouseY()
	radius = MouseZ()*10
	
	chord = Sqr( ((startx - mx)*(startx - mx)) + ((starty - my)*(starty - endy)))
	MidX=Sqr((startx - mx)*(startx - mx))
	MidY=Sqr((starty - my)*(starty - my))
	MidChord= chord/2
	sideB=Sqr((Radius*Radius)-(MidChord*Midchord))
	angleToCenter = ATan2(mx,my)-90
	RadX=Sin(angleToCenter)*Radius+MidX
	RadY=Cos(angleToCenter)*Radius+MidY
	;angleToStart=atan2() Radx and rady need to be transformed to center and startx and starty transformed
	;angleToEnd=atan2()Radx and rady need to be transformed to center and mx and my transformed
	;For i = angleToStart to angleToEnd
	For i = angleToCenter-30 To angletocenter+30
		WritePixel RadX+Sin(i)*Radius,RadY+Cos(i)*Radius,$FFFFFF
	Next
	ms = MilliSecs() - ms
	UnlockBuffer()

	Flip 0
	Cls
Wend
End



Ross C(Posted 2008) [#16]
I don't think that's the way ATan2 works :o) Isn't it the y component first? Accroding to the docs anyway. I'll post my code for this later. I got the curve going correctly, and managed to cap the radius so it doesn't go below half the length from start (x,y) to end(x,y).


Staton_Richardson(Posted 2008) [#17]
it has some odd problems near the -180 but it works



Graphics 640, 480, 32, 2
SetBuffer BackBuffer()
x1#=320
y1#=240
r#=100
While Not KeyHit(1)
	LockBuffer()
	
	x2# = MouseX()
	y2# = MouseY()
	r# = Abs(MouseZ()*3)+rf#
	q# = Sqr( ((x1 - x2)*(x1 -x2)) + ((y1 - y2)*(y1 - y2)))

	rf#=q#*.5

	x3#=(x1+x2)/2
	y3#=(y1+y2)/2
		
	x# = x3 + Sqr(r^2-(q/2)^2)*(y1-y2)/q
	y# = y3 + Sqr(r^2-(q/2)^2)*(x2-x1)/q  

	angleToStart#=ATan2(y1#-y#,x1#-x#) 
	angleToEnd#=ATan2(y2#-y#,x2#-x#)
	
	For i = angletostart# To angletoend#
		ii#=Float(i)
		WritePixel x+Cos(ii)*r,y+Sin(ii)*r,$FFFFFF
	Next

	UnlockBuffer()
	Text 10,10,x
	Text 10,20,y
	Text 10,30,"Start Angle: "+angletostart
	Text 10,40,"End Angle: "+angletoend
	Text 10,50,"radius: " + r

	Flip 0
	Cls
Wend
End



Stevie G(Posted 2008) [#18]
Is this what your looking for ?

Graphics 640, 480, 32, 2
SetBuffer BackBuffer()
x1#=320
y1#=240
r#=100
While Not KeyHit(1)

	x2# = MouseX()
	y2# = MouseY()
	r# = Abs(MouseZ()*3)+rf#
	q# = Sqr( ((x1 - x2)*(x1 -x2)) + ((y1 - y2)*(y1 - y2)))

	rf#=q#*.5

	x3#=(x1+x2)/2
	y3#=(y1+y2)/2
		
	x# = x3 + Sqr(r^2-(q/2)^2)*(y1-y2)/q
	y# = y3 + Sqr(r^2-(q/2)^2)*(x2-x1)/q  

	angleToStart#=ATan2(y1#-y#,x1#-x#) 
	angleToEnd#=ATan2(y2#-y#,x2#-x#)
	
	LockBuffer()
	For t# = 0 To 1 Step .01
		angle# = angleToStart + ( angleToEnd - angleToStart ) * t
		WritePixel x + Cos( angle ) * r , y + Sin( angle ) * r , $FFFFFF
	Next	
	UnlockBuffer()

	Text 10,10,x
	Text 10,20,y
	Text 10,30,"Start Angle: "+angletostart
	Text 10,40,"End Angle: "+angletoend
	Text 10,50,"radius: " + r

	Flip 0
	Cls
Wend
End



Staton_Richardson(Posted 2008) [#19]
Yes that reveals more of what the problem is
at the -180 you get an arc with the radius on the
wrong side of the line. It makes almost a full circle
this is what you would get if you had a negative
radius greater than the inverse of the lowest radius
that would also explain why it disappears I'll have to
look at the math again.

I think i'll also try the eponymous Bresenham's circle algorithm
to draw the circle
http://en.wikipedia.org/wiki/Midpoint_circle_algorithm


I just said eponymous cause it fit and it's fun to say :p

Thanks for the input


Ice9(Posted 2008) [#20]
I stared at this a dozen times this weekend and it dawned
on me this morning what the problem was. I'm humbled

Thanks Ross C and Stevie G for your help and my brother for
remembering the slope algorithm


Graphics 640, 480, 32, 2
SetBuffer BackBuffer()
x1#=320
y1#=240
r#=100
While Not KeyHit(1)

	x2# = MouseX()
	y2# = MouseY()
	r# = Abs(MouseZ()*3)+rf#
	q# = Sqr( ((x1 - x2)*(x1 -x2)) + ((y1 - y2)*(y1 - y2)))

	rf#=q#*.5

	x3#=(x1+x2)/2
	y3#=(y1+y2)/2
		
	x# = x3 + Sqr(r^2-(q/2)^2)*(y1-y2)/q
	y# = y3 + Sqr(r^2-(q/2)^2)*(x2-x1)/q  

	angleToStart#=NAngle(ATan2(y1#-y#,x1#-x#)) 
	angleToEnd#=NAngle(ATan2(y2#-y#,x2#-x#))
	
	LockBuffer()
	
	If angleToEnd>angletoStart
		For angle# = angleToStart To angleToEnd Step 0.05  
			WritePixel x + Cos( angle ) * r , y + Sin( angle ) * r , $FFFFFF
			plotpath=1
		Next
	Else
		For angle# = angleToStart To 360 Step 0.05 
			WritePixel x + Cos( angle ) * r , y + Sin( angle ) * r , $FFFFFF
			plotpath=0
		Next
		For angle# = 0 To angleToEnd Step 0.05 
			WritePixel x + Cos( angle ) * r , y + Sin( angle ) * r , $FFFFFF
			plotpath=0
		Next
	EndIf	
	
	UnlockBuffer()
	Oval(x-2,y-2,4,4)
	Text 10,0,plotpath
	Text 10,10,x+" "+ y +" radius: " + r
	Text 10,20,x1 + " " + y1+"  Start Angle: "+angletostart
	Text 10,30,x2+" "+y2+" End Angle: "+angletoend
	

	Flip 0
	Cls
Wend

Function NAngle#(angle#)
	If angle#<0 Then angle#=180+(180+angle#)
	Return angle#
End Function