起因

在上一片文章中,其实已经将逐点比较法的直线插补写得差不多了,但是因为象限问题,代码比较抽象。
所以我使用面向对象的思路重写了一遍。

关于数字

在所有的编程语言中,基本只用到整型和浮点数两种数字类型,但是面对这个数控编程,如果采用整型则无法满足精度要求,而浮点数因为其保留精度的特性,使用起来也较为不便(主要是需要重写判断两数相等),因此我使用了定点数来解决这一问题,所有与精度相关的数字都将其转换为了定点数。
具体如何使用定点数可以参考 Python decimal 模块使用方法详解和官方文档 decimal—— 十进制定点和浮点运算,我的代码中基本只用了如下两个方法。

1
2
3
4
5
6
7
8

from decimal import *

# 将整型或浮点数x转换为定点数x
Decimal(str(x))

# 结果保留3位小数(四舍五入)
num.quantize(Decimal('0.000'))

初始化实例

想要确定一条线段,必须有起点坐标以及三选一 —— 终点坐标、终点增量、直线长和角度,再转为起点和终点绝对坐标。

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
# 直线类
class Line(object):
def __init__(self, start=(0, 0), enda=0, endd=0, angle=0, length=0):
"""
start 起点,默认(0,0)
enda 终点绝对值 (x,y)
endd 终点增量值 (x,y)
angle 直线角度 (-180,180]
length 直线长度
"""
self.start = tuple(
map(lambda x: Decimal(str(x)).quantize(Decimal("0.000")), start))

# 计算终点绝对坐标
if enda:
self.end = tuple(
map(lambda n: Decimal(str(n)).quantize(Decimal("0.000")), enda))
elif endd:
self.end = tuple(
map(lambda n: Decimal(str(n)).quantize(Decimal("0.000")), endd))
elif angle and length:
angle = Decimal(str(math.radians(angle)))
length = Decimal(str(length))
self.end = (
start[0] + Decimal(str(math.cos(angle))) * length,
start[1] + Decimal(str(math.sin(angle))) * length,)
self.end = tuple(
map(lambda n: Decimal(str(n)).quantize(Decimal("0.000")), self.end))
else:
self.end = (Decimal("0"), Decimal("0"))

插补思路

思路
思路

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

完整代码

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
# Python3
from decimal import *
import math
import time

# 直线类
class Line(object):
def __init__(self, start=(0, 0), enda=0, endd=0, angle=0, length=0):
"""
start 起点,默认(0,0)
enda 终点绝对值 (x,y)
endd 终点增量值 (x,y)
angle 直线角度 (-180,180]
length 直线长度
"""
self.start = tuple(
map(lambda x: Decimal(str(x)).quantize(Decimal("0.000")), start))

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

# 计算终点绝对坐标
if enda:
self.end = tuple(
map(lambda n: Decimal(str(n)).quantize(Decimal("0.000")), enda))
elif endd:
self.end = tuple(
map(lambda n: Decimal(str(n)).quantize(Decimal("0.000")), endd))
elif angle and length:
angle = Decimal(str(math.radians(angle)))
length = Decimal(str(length))
self.end = (
start[0] + Decimal(str(math.cos(angle))) * length,
start[1] + Decimal(str(math.sin(angle))) * length,)
self.end = tuple(
map(lambda n: Decimal(str(n)).quantize(Decimal("0.000")), self.end))
else:
self.end = (Decimal("0"), Decimal("0"))

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

# 直线起点平移到原点
def __offset(self) -> None:
xe = self.end[0] - self.start[0]
ye = self.end[1] - self.start[1]
self.end = (xe, ye)
self.f = 0
# 步长
self.step = abs(xe) + abs(ye)
self.step = self.step * self.zoom
# 象限系数
self.kx = int(math.copysign(1, xe))
self.ky = int(math.copysign(1, ye))

# 直线补偿☆
def __compensation(self) -> None:
# 偏差判别
if self.f >= 0:
# 终点在Y轴上
if self.end[0] == 0:
self.y = self.y + self.delta * self.ky
self.f = self.f
else:
self.x = self.x + self.delta * self.kx
self.f = self.f - abs(self.end[1])
else:
self.y = self.y + self.delta * self.ky
self.f = self.f + abs(self.end[0])

# 迭代器
def __iter__(self):
self.__offset()
# 当前点坐标
self.x = Decimal(0)
self.y = Decimal(0)
return self

def __next__(self):
# 循环数=总步长
if self.step:
self.__compensation()
self.step = self.step - 1
return (float(self.x + self.start[0]), float(self.y + self.start[1]))
else:
raise StopIteration

试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
l1 = Line((0, 0), angle=30, length=2)

print(l1)
# Output: start=(0.000,0.000); end=(1.732,1.000)

for i in l1:
print(i)
# Output:
# (0.001, 0.0)
# (0.001, 0.001)
# (0.002, 0.001)
# ...
# (1.731, 0.999)
# (1.731, 1.0)
# (1.732, 1.0)

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