PDA

View Full Version : Finding arc angles



fantasy2
07-24-2010, 08:37 AM
I'm writing a program to read dxf files and send them directly to my lasercutter. Most of the entities from autocad's DXF are already working but I'm having difficulties with the bulge of LWPOLYLINE and POLYLINE.

From the given start x,y, end x,y and bulge factor I can already calculate centerpoint of the circle, radius and the distance between the 2 points.

The thing I need to know is the start and end angle. Some simple trigonometry I guess but I can't get it working!


This is what it currently draws:
http://photo.protoart.net/circle_wrong.png

This is what it should be:
http://photo.protoart.net/circle_right.png

Does anyone have some hints what I should look for? I think the problem is near the point where x and y go negative or something..

ger21
07-24-2010, 09:54 AM
Here's how I do it in AutoCAD VBA. Red and green are comments

' Find Center of Arc

If BulgeN <> 0 Then 'If Bulge is NOT zero BulgeN is the bulge

' First find chord of arc

ChordL = Sqr((RetCoord(X) - RetCoord(X - 2)) ^ 2 + (RetCoord(y) - RetCoord(y - 2)) ^ 2)

RetCoord(X)= X end of arc
RetCoord(X-2)= X start of arc
RetCoord(Y)= Y end of arc
RetCoord(Y-2)= Y start of arc

' Set Start point of Arc as pt1 and End Point as pt2

Pt1(0) = RetCoord(X - 2): Pt1(1) = RetCoord(y - 2): Pt1(2) = 0
Pt2(0) = RetCoord(X): Pt2(1) = RetCoord(y): Pt2(2) = 0

BulgeAngle = (4 * Atn(BulgeN)) * 180 / pi ' included angle

r = Abs(ChordL / (2 * Sin((4 * Atn(BulgeN)) / 2))) ' Find Radius of Arc

ReturnAngle = ThisDrawing.Utility.AngleFromXAxis(Pt1, Pt2) 'This is an AutoCAD VBA function. You'll need to use trig to get this angle


' Find angle from Start point to Center Point

AngleToCenter = ReturnAngle + (pi / 2 - (2 * Atn(BulgeN)))

' Find Center Point

CenterPt = ThisDrawing.Utility.PolarPoint(Pt1, AngleToCenter, r) Another AutoCAD VBA function = more trig for you

If GWord = "G3" Then
ILoc = CStr(FormatNumber(Round(CenterPt(0) - RetCoord(X - 2), Precision), Precision, -1, 0, 0))
JLoc = CStr(FormatNumber(Round(CenterPt(1) - RetCoord(y - 2), Precision), Precision, -1, 0, 0))
Else
ILoc = CStr(FormatNumber(Round(RetCoord(X - 2) - CenterPt(0), Precision), Precision, -1, 0, 0))
JLoc = CStr(FormatNumber(Round(RetCoord(y - 2) - CenterPt(1), Precision), Precision, -1, 0, 0))
End If

fantasy2
07-24-2010, 10:55 AM
Thanks for the code. The chord length and radius are calculated in a similar way. But I'm unable to figure out how to calculate the start and end angles... at least, I did some calculations that turned out to be working. But in this specific drawing it doesn't. That sounds to me like there is a certain condition at which the code goes wrong.

Here is my code:


function LWBulgeCalc($xs, $xe, $ys, $ye, $bulge)
{
$result = array();

$dx = $xe - $xs;
$dy = $ye - $ys;
$xmid = $dx/2 + $xs;
$ymid = $dy/2 + $ys;

$l = sqrt(pow($dx,2) + pow($dy,2)); //linelength from point 1 to point 2
$r = abs($l*(($bulge*$bulge)+1)/$bulge/4); //Radius circle
// $r = abs($l/(2* sin((4*atan($bulge))/2))); //another way of calculating the radius.

$a = abs($bulge*$l/2);
$sb = $bulge/abs($bulge);
$theta_p = 4*atan($bulge);

if($dx != 0) $theta_c = atan($dy/$dx);
else $theta_c = pi()/2;

if ($dx > 0) $sb *= -1;


$cx = $xmid + $sb*($r-$a)*sin($theta_c); //centerpoint X
$cy = $ymid - $sb*($r-$a)*cos($theta_c); //centerpoint Y

$angle1 = asin(($ye-$cy)/$r); //angle 1
$angle2 = asin(($cy-$ys)/$r); //angle 2


if($cx > $xe) $angle1 = pi() - $angle1;
else $angle1 = 2*pi() + $angle1;


if($bulge < 0) //CW
{
$arcst = $angle1;
$arcend = pi() + $angle2;
}
else //CCW
{
$arcend = $angle1;
$arcst = pi() + $angle2;
}

$arcst = rad2deg($arcst);
$arcend = rad2deg($arcend);



$result[0] = $cx;
$result[1] = $cy;
$result[2] = $r;
$result[3] = $arcst;
$result[4] = $arcend;

return $result;
}

ger21
07-24-2010, 12:15 PM
So you're not creating g-code? I guess I didn't read your question correctly, because I don't need a start and end angle to create g-code.

If you have the center of the arc, the start and end angles should be 90° to a vector from the center to the start and end points, respectively. Right?

fantasy2
07-24-2010, 12:27 PM
No, I'm not converting to G-Code.

It is indeed possible to use sine/cosine/tan as I do have one 90 degree angle. The problem is that they only work with right angles but a circle is 360 degree.

When you compare the images, most of the arcs in the first image are similar to the second image, but some are not. So there must be a condition where the start and end angle are wrongly calculated and I can't figure out why.


I did find some code where they calculated the start and end angle but for some reason, that code doesn't work.
http://inkscape.modevia.com/doxygen/html/entities_8cpp_source.php#l00449

ger21
07-24-2010, 01:16 PM
Are these the angles you're trying to find?

fantasy2
07-24-2010, 01:29 PM
Well, indeed! How can I find those angles?

MrWild
07-24-2010, 02:04 PM
I'm assuming you have AutoCAD. The top tool br has a radio button titled "dimension." Left click it, click "angle" click on the arc. Sometimes you need a Negative angle input, or you end up with a circle when the machine interprets what you want.

ger21
07-24-2010, 02:08 PM
First, I don't know the trig, and don't have time to find it. :)

Keep in mind that the angles are referenced from horizontal, with 0° to the right.

First find the angles from the center point to the start and ends of the arc. The Start and End angles are 90° greater for a CCW arc, and 90° less for a CW arc.

I've spent 45 minutes in AutoCAD playing with arcs, and I think that's correct. Should be simple to get your angles form this.

fantasy2
07-24-2010, 02:11 PM
I'm assuming you have AutoCAD. The top tool br has a radio button titled "dimension." Left click it, click "angle" click on the arc. Sometimes you need a Negative angle input, or you end up with a circle when the machine interprets what you want.


I guess it won't show a formula right? I need a formula so I only have to select the dxf file and the written software can calculate the rest of the needed data(with 100 arcs it's a lot of work to do it all manually).

fantasy2
07-24-2010, 04:38 PM
I tried to figure everything out for the last 5 hours with the new information(already spent 3 days on this issue) but I can't find a solution. :(

Most of the arcs are drawn the correct way, except for a few! Very annoying.
The dynamically created image can be found here: http://www.protoart.net/test/ndex.php

YES! I guess this is my lucky evening!
I still don't know exactly what I changed but luck is on my side and I changed the right values. Except for closing the drawing, everything goes as planned!

ger21
07-24-2010, 05:57 PM
If it's any consolation, it took me a lot longer than 3 days to get to the code I posted before. :)

_Eduardo_
07-26-2010, 09:50 AM
Try this, is a modified version of your code.

Perhaps contain some bugs, because I could not verify.



function LWBulgeCalc($xs, $xe, $ys, $ye, $bulge)
{
$result = array();

$dx = ($xe - $xs)/2 ;
$dy = ($ye - $ys)/2 ;
$a = (1/$bulge-$bulge)/2 ;
$r = abs($bulge+1/$bulge)*sqrt($dx*$dx + $dy*$dy)/2 ; //Radius circle

$dr1x = $dy*$a - $dx ;
$dr1y = -$dx*$a - $dy ;

$theta_s = rad2deg(acos($dr1x/$r)) ;
if($dr1y < 0) $theta_s = 360 - $theta_s ;

$theta_e = $theta_s + 4*rad2deg(atan($bulge)) ;
if($theta_e < 0) $theta_e += 360 ;
if($theta_e >= 360) $theta_e -= 360 ;


$result[0] = $xe-$dr1x ;
$result[1] = $ye-$dr1y ;
$result[2] = $r ;
$result[3] = $theta_s ;
$result[4] = $theta_e ;

return $result;
}

odin205
01-18-2011, 05:35 PM
YES! I guess this is my lucky evening!
I still don't know exactly what I changed but luck is on my side and I changed the right values. Except for closing the drawing, everything goes as planned!

Can you please post your modified code, 'cause i am stuck in the same point, the start and end angles.

I can't find the right conditions to get always the right angles.

bradodarb
04-05-2012, 10:47 AM
Hello,

I use this in my geometry lib::



public static double GetAnglefromPoints(double x1, double y1, double x2, double y2)
{
double retval = 0;

retval = Math.Round(Math.Atan2((y2 - y1),
(x2 - x1)), 4);

retval = R2D(retval);

return retval;

}

public static double R2D(double iangle)
{
return iangle * (180.0 / Math.PI);
}



And with GetAnglefromPoints, the first X,Y is center point and the second will either be start or end.


HTH,
Brad Murry