前言

和直线插补不同,圆弧插补则困难得多,原因是会涉及到四个象限,十分复杂。在这我先只处理单个象限的情况,即圆弧≤90 度的情况。
数字部分请参考从零开始写数控系统 0.5:【重写】直线插补吧,这里用的也是 Python 自带的定点数模块。

初始化实例

想要初始化一段圆弧,需要输入顺圆 / 逆圆、起点坐标、终点坐标、偏移量和半径。但这并非都需要输入,实际上后三者只需要一个就够了。
之所以会要这么多参数,是因为数控编程的圆弧可以接受圆心法和半径法两种字段,这里做了兼容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 圆弧类
class Circle(object):
def __init__(self, g=3, start=(0, 0), end=(0, 0), offset=(0, 0), r=0):
"""
g 顺圆=1,逆圆=0
start 圆弧起点(xs,ys)
end 终点(xe,ye)
offset 偏移量(i,j)
r 圆弧半径,r>=0劣弧,r<0优弧
"""
self.start = tuple(
map(lambda x: Decimal(str(x)).quantize(Decimal("0.000")), start)
)
self.end = tuple(map(lambda n: Decimal(str(n)).quantize(Decimal("0.000")), end))
self.g = g

# 圆心法
if offset != (0, 0):
self.offset = tuple(
map(lambda x: Decimal(str(x)).quantize(Decimal("0.000")), offset)
)
# 半径法
else:
self.r = Decimal(str(r))

# 放大系数&增量
self.zoom = Decimal(1000)
self.delta = Decimal(1) / self.zoom

# 获取圆心坐标
self.__getCenter()

为了简化计算,一律以输入的圆弧圆心为坐标系原点,输出时平移回去。

1
2
3
4
5
6
7
8
9
10
# 圆心平移到原点
def __offset(self):
self.__xs = self.start[0] - self.x0
self.__ys = self.start[1] - self.y0
self.__xe = self.end[0] - self.x0
self.__ye = self.end[1] - self.y0
self.f = 0
# 步长
self.step = abs(self.__xs - self.__xe) + abs(self.__ys - self.__ye)
self.step = self.step * self.zoom

插补思路

思路其实和直线的差不多。

思路
思路

从性能角度考虑,我使用了迭代器输出插补的中间点。

插补判别

总结
总结

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# Python3
from decimal import *
import math

# 圆弧类
class Circle(object):
def __init__(self, g=3, start=(0, 0), end=(0, 0), offset=(0, 0), r=0) -> None:
"""
g 顺圆=1,逆圆=0
start 圆弧起点(xs,ys)
end 终点(xe,ye)
offset 偏移量(i,j)
r 圆弧半径,r>=0劣弧,r<0优弧
"""
self.start = tuple(
map(lambda x: Decimal(str(x)).quantize(Decimal("0.000")), start)
)
self.end = tuple(map(lambda n: Decimal(str(n)).quantize(Decimal("0.000")), end))
self.g = g

# 圆心法
if offset != (0, 0):
self.offset = tuple(
map(lambda x: Decimal(str(x)).quantize(Decimal("0.000")), offset)
)
# 半径法
else:
self.r = Decimal(str(r))

# 放大系数&增量
self.zoom = Decimal(1000)
self.delta = Decimal(1) / self.zoom

# 获取圆心坐标
self.__getCenter()

# 重写字符串
def __str__(self) -> str:
return "start=({:,.3f},{:,.3f}); end=({:,.3f},{:,.3f}); center=({:,.3f},{:,.3f}); radius={:,.3f}".format(
float(self.start[0]),
float(self.start[1]),
float(self.end[0]),
float(self.end[1]),
float(self.x0),
float(self.y0),
float(self.r),
)

# 获取圆心坐标
def __getCenter(self) -> tuple:
if "offset" in dir(self):
self.x0 = self.start[0] + self.offset[0]
self.y0 = self.start[1] + self.offset[1]
self.r = math.sqrt(
(self.end[0] - self.x0) ** 2 + (self.end[1] - self.y0) ** 2
)
self.r = Decimal(str(self.r))
else:
xs, ys = self.start[0], self.start[1]
xe, ye = self.end[0], self.end[1]
# 判断象限1234
match (self.g, xs > xe, ys > ye):
case (3, 1, 0) | (2, 0, 1):
self.__qd = 1
case (3, 1, 1) | (2, 0, 0):
self.__qd = 2
case (3, 0, 1) | (2, 1, 0):
self.__qd = 3
case (3, 0, 0) | (2, 1, 1):
self.__qd = 4

c1 = (xs**2 - xe**2 + ys**2 - ye**2) / (2 * xs - 2 * xe)
c2 = (ys - ye) / (xs - xe)
a = 1 + c2**2
b = 2 * (xe - c1) * c2 - 2 * ye
c = (xe - c1) ** 2 + ye**2 - self.r**2
y0 = (-b + Decimal(str(math.sqrt(b**2 - 4 * a * c)))) / (2 * a)
x0 = c1 - c2 * y0
# 根据象限顺逆圆确定圆心
xm = (xs + xe) / 2
ym = (ys + ye) / 2
if self.__qd == 1 and xm > x0 and ym > y0:
self.y0 = y0
self.x0 = x0
elif self.__qd == 2 and xm < x0 and ym > y0:
self.y0 = y0
self.x0 = x0
elif self.__qd == 3 and xm < x0 and ym < y0:
self.y0 = y0
self.x0 = x0
elif self.__qd == 4 and xm > x0 and ym < y0:
self.y0 = y0
self.x0 = x0
else:
self.y0 = (-b - Decimal(str(math.sqrt(b**2 - 4 * a * c)))) / (2 * a)
self.x0 = c1 - c2 * self.y0

# 圆心平移到原点
def __offset(self) -> None:
self.__xs = self.start[0] - self.x0
self.__ys = self.start[1] - self.y0
self.__xe = self.end[0] - self.x0
self.__ye = self.end[1] - self.y0
self.f = 0
# 步长
self.step = abs(self.__xs - self.__xe) + abs(self.__ys - self.__ye)
self.step = self.step * self.zoom

# 圆弧补偿☆
def __compensation(self) -> None:
# 进给方向(顺逆圆,偏差函数,象限)
match (self.g, self.f >= 0, self.__qd):
case (3, 1, 1) | (3, 0, 2) | (2, 0, 3) | (2, 1, 4):
self.f = self.f - 2 * self.__x + self.delta
self.__x -= self.delta
case (3, 0, 1) | (3, 1, 4) | (2, 0, 2) | (2, 1, 3):
self.f = self.f + 2 * self.__y + self.delta
self.__y += self.delta
case (3, 1, 3) | (3, 0, 4) | (2, 1, 2) | (2, 0, 1):
self.f = self.f + 2 * self.__x + self.delta
self.__x += self.delta
case (3, 0, 3) | (3, 1, 2) | (2, 1, 1) | (2, 0, 4):
self.f = self.f - 2 * self.__y + self.delta
self.__y -= self.delta

# 迭代器
def __iter__(self):
self.__offset()
# 当前点坐标
self.__x = self.__xs
self.__y = self.__ys
return self

def __next__(self):
# 循环数=总步长
if self.step:
self.__compensation()
self.step -= 1
return (float(self.__x + self.x0), float(self.__y + self.y0))
else:
if self.__x + self.x0 != self.end[0] or self.__y + self.y0 != self.end[1]:
print("圆弧错误,请检查输入代码")
raise StopIteration

试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
c1 = Circle(g=2, start=(-4, 0), end=(0, 4), r=4)
print(c1)

# Output: start=(-4.000,0.000); end=(0.000,4.000); center=(-0.000,0.000); radius=4.000

for i in l1:
print(i)
# Output:
# (-3.999, 0.0)
# (-3.999, 0.001)
# (-3.999, 0.002)
# ...
# (-0.002, 4.0)
# (-0.001, 4.0)
# (0.0, 4.0)

网站地图 | 状态监测 | 图片加密&解密 | File Server | 博友圈 | 博客说
Copyright 2022-2025 | Powered by Hexo 7.3.0 & Stellar 1.29.1
总访问量次 |