Function G2(StartX, StartY, EndX, EndY, Radius)
Blitz3D Forums/Blitz3D Programming/Function G2(StartX, StartY, EndX, EndY, Radius)
| ||
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. |
| ||
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. |
| ||
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 |
| ||
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 |
| ||
Ok, my function doesn't work great. I th9ink i have given you the wrong info so i'm gonna work this out :o) |
| ||
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? |
| ||
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. |
| ||
I tried last night again, but, imagine this. Distance between the two points is 5. Radius is 1. This just wouldn't work? |
| ||
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 |
| ||
not this time matey. just bought a ps3 sofire in. you got a better math head than me anyway! |
| ||
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 ![]() |
| ||
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 |
| ||
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 |
| ||
Have you tried this in blitz yet? |
| ||
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 |
| ||
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). |
| ||
it has some odd problems near the -180 but it worksGraphics 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 |
| ||
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 |
| ||
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 |
| ||
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 |