从 G 代码计算拱的 X 轴极限

Calculate the X -aixes Limmets of a arch from G-Code

几天来,我一直在尝试确定拱门的极限,但没有多少 successes.I 知道这更像是一个几何类型的问题,而不是编程问题,但在这里 goes.Let 我首先展示这张图片详细说明了我试图在 C# 中实现的目标。

在上图中你可以看到一个绿色弧线,我试图确定“最左边”点在 X 轴上的位置(最终 'right most',但为了简单起见,我将专注于“最左边”的点) 这个图像在 X 轴“最左边”的答案是 5,注意:即使拱有更大的后掠角答案仍然是 5,但如果后掠角小于答案将大于 5。 我正在从一个基于文本的 G 代码文件中读取此信息,这里是在 G 代码文件中绘制的圆弧示例。

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

第一行表示拱的起点,在本例中是X 10和Y 15。第二行表示终点,拱中心点和旋转。 G3 表示足弓逆时针旋转(G2 表示顺时针旋转)。 X 和 Y 表示终点,I 和 J 是(分别为 X 和 Y)拱形中心点 values.The 我尝试的第一件事是看看我是否可以检测到拱形穿过 180 * 红线没有太多成功,主要是因为当我尝试处理不同类型的 coordinates.Here 时,我似乎无法正确计算角度 coordinates.Here 是我无法完成的代码示例:

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;
  }
}

上面的代码只适用于一些特定的弧。 我在谷歌上搜索了一下,发现主要是关于线相交和线与圆相交的主题,但只有一个专门关于线与弧相交的主题,答案太模糊,无法弄清楚这里应该发生什么是 Link

除此之外,还有一种类型的拱形我认为可能必须通过某种 Pathegorem 进行不同的处理,但我还没有开始研究如何做到这一点。但这是它的图像:

这是 G 代码:

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

而且我认为“最左边”的 X 值是 25.4

我想知道,如果您知道可以帮助解决这个问题的方法或库。谢谢

这应该计算弧的 X 和 Y 边界。可以进行很多优化以获得更好的性能,但我认为这更容易理解。

    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 (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);