从 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);
几天来,我一直在尝试确定拱门的极限,但没有多少 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);