1

I am trying to determine the limits of an arch for a couple of days now without much successes.I know this is more of a geometry type question than programming but here it goes.Let me first show this image to elaborate on what I am trying to achieve in C#. enter image description here

In the image above you can see a Green Arc, I am trying to determine where the ‘Left Most’ point is on the X axis (and the 'right most' eventually, but for the sake of simplicity I will focus on the ‘left most’ point) The answer of this image ‘left most’ in the X axis is 5,note: even if the arch has a greater sweep angle the answer is still 5, but if the sweep angle is less than the answer will be more than 5. I am reading this information from a text based G-code file and here is a sample of the arc drawn in the G-code file.

G1 X10. Y15.
G3 X5. Y10. I10. J10.

The first line indicates the starting-point of the arch, witch is in this case X 10 and Y 15. The second line indicates the end-point, arch-center-point and rotation. The G3 indicates a Counter-Clockwise rotation of the arch (G2 indicates a Clockwise Rotation). The X & Y indicates the End-Point and the I & J is the (X & Y respectively) arch-center-point values.The first thing that I have tried is to see if I can detect the arch crosses the 180* red line without much successes mainly because I cannot seem to get angle calculations working correctly when I try to process different types of coordinates.Here is a sample of code I’m unable to finish:

else if (Gval == 3)
{
  //Values read from G-Code File
  double startX = Convert.ToDouble(oldXval);
  double startY = Convert.ToDouble(oldYval);
  double endX = Convert.ToDouble(Xval);
  double endY = Convert.ToDouble(Yval);
  double midX = Convert.ToDouble(Ival);
  double midY = Convert.ToDouble(Jval);

  //Get Start angle of Line
  double startAngle = Math.Atan2(startY - midY, startX - midX);
  startAngle = Math.Round(startAngle * (180.0 / Math.PI), 5);//Radiants to Degrees 
  startAngle = ((startAngle % 360) + 360) % 360;//Normalise

  //Get End angle of line
  double EndAngle = Math.Atan2(endY - midY, endX - midX);
  EndAngle = Math.Round(EndAngle * (180.0 / Math.PI), 5);//Radiants to Degrees 
  EndAngle = ((EndAngle % 360) + 360) % 360;//Normalise
  if (EndAngle == 0) EndAngle = 360;

  //Get Raiduis
  double raduis = Math.Round((Math.Sqrt(Math.Pow(Math.Abs(startX - midX), 2) + Math.Pow(Math.Abs(startY - midY), 2))),5);

  double deltaY = (midY) - (startX);
  double deltaX = (midX) - (startY);
  double angleInDegrees = Math.Atan(deltaY / deltaX)*180/Math.PI;

  if (startAngle <= 180 && EndAngle >= 180)
  {
     double LeftValue = midX - raduis;
  }
}

The code above only works for some specific arcs. I have Googled around and found mainly topics on Lines intersections and line and circle intersections but only one specifically about lines intersecting arcs, the answer is too vague to make out what is supposed to happen here is the Link

In addition to that there is also a type of arch that I think will have to be processed differently probably by some sort of Pathegorem, but I have not started on how I can do that one. But here is an image of it:

enter image description here

Here is the G-code :

  G1 X30. Y15.
  G3 X25.4 Y11.96 I30. J10.

And I think the ‘Left most’ X value is 25.4

I would like to know, if you know of a Method or a Library that can help out with this one .Thanks

Community
  • 1
  • 1
DarkPh03n1X
  • 600
  • 1
  • 7
  • 17

1 Answers1

0

This should calculate the X and Y bounds of an arc. There are many optimizations that could be made for better performance, but I think this is easier to understand.

    class Bounds
    {
        public double MinX, MinY, MaxX, MaxY;
    }

    Bounds GetArcBounds(float cx, float cy, float x1, float y1, float x2, float y2)
    {
        var a1 = GetAngle(y1 - cy, x1 - cx);
        var a2 = GetAngle(y2 - cy, x2 - cx);
        var r = (float)Math.Sqrt(Math.Pow(y1 - cy, 2) + Math.Pow(x1 - cx, 2));

        var bounds = new Bounds();
        bounds.MinX = double.MaxValue;
        bounds.MinY = double.MaxValue;
        bounds.MaxX = double.MinValue;
        bounds.MaxY = double.MinValue;

        ExpandBounds(bounds, x1, y1);
        ExpandBounds(bounds, x2, y2);

        if (IsAngleInArc(a1, a2, 0)) 
            ExpandBounds(bounds, cx + r, cy);
        if (IsAngleInArc(a1, a2, (float)Math.PI * 0.5f)) 
            ExpandBounds(bounds, cx, cy + r);
        if (IsAngleInArc(a1, a2, (float)Math.PI)) 
            ExpandBounds(bounds, cx - r, cy);
        if (IsAngleInArc(a1, a2, (float)Math.PI * 1.5f)) 
            ExpandBounds(bounds, cx, cy - r);

        return bounds;
    }

    float GetAngle(float dy, float dx)
    {
        var a = (float)Math.Atan2(dy, dx);
        if (a < 0) a += (float)Math.PI * 2.0f;
        return a;
    }

    void ExpandBounds(Bounds bounds, float x, float y)
    {
        if (x < bounds.MinX) bounds.MinX = x;
        if (y < bounds.MinY) bounds.MinY = y;
        if (x > bounds.MaxX) bounds.MaxX = x;
        if (y > bounds.MaxY) bounds.MaxY = y;
    }

    bool IsAngleInArc(float a1, float a2, float test)
    {
        if (a2 < a1)
        {
            a2 += (float)Math.PI * 2.0f;
        }
        if (test < a1)
        {
            test += (float)Math.PI * 2.0f;
        }
        return a1 <= test && test <= a2;
    }

If you wanted to be able to do both counter-clockwise and clockwise, I believe you could change the logic to the following, although I have not tested this yet.

    if (IsAngleInArc(a1, a2, 0) ^ clockwise) 
        ExpandBounds(bounds, cx + r, cy);
    if (IsAngleInArc(a1, a2, (float)Math.PI * 0.5f) ^ clockwise) 
        ExpandBounds(bounds, cx, cy + r);
    if (IsAngleInArc(a1, a2, (float)Math.PI) ^ clockwise) 
        ExpandBounds(bounds, cx - r, cy);
    if (IsAngleInArc(a1, a2, (float)Math.PI * 1.5f) ^ clockwise) 
        ExpandBounds(bounds, cx, cy - r);