-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpolyline.py
More file actions
135 lines (122 loc) · 4.48 KB
/
polyline.py
File metadata and controls
135 lines (122 loc) · 4.48 KB
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
from typing import List
from nose.tools import assert_raises
from GoodToolPython.vector3d import Vector3D, Line3D
import matplotlib.pyplot as plt
import numpy as np
class Polylines2D:
"""
平面多段线 x递增
"""
points_list: List[Vector3D]
tol = 1e-15 # 判断相等的误差
def __init__(self, name: str = ''):
self.name = name # 名称
self.points_list = []
def append(self, pt: Vector3D) -> None:
assert isinstance(pt, Vector3D)
if self.num_of_points > 0:
assert pt.x > self.points_list[-1].x, '要求x坐标递增'
self.points_list.append(pt)
@property
def num_of_points(self): # 点的个数
return len(self.points_list)
@property
def num_of_lines(self): # 线的个数
return len(self.points_list) - 1
def get_slope_by_line_id(self, id_line=0) -> float:
"""
返回斜率 通过线的编号
:param id_line:线编号
:return: 斜率 正无穷时返回'inf'
"""
assert self.num_of_lines >= id_line, '线的编号越界'
p1 = self.points_list[id_line]
p2 = self.points_list[id_line + 1]
if abs(p1.y - p2.y) < self.tol:
slope = 'inf' # 此时斜率为正无穷
else:
slope = (p1.y - p2.y) / (p1.x - p2.x)
return slope
def get_slope(self, x: float = 0., side='left') -> float:
"""
通过x坐标 返回该处的斜率
如果为无穷大 返回'inf'
:param x:
:param side: 指定当遇到中间节点 返回的值'left' 'right' 'stop'
:return:
"""
assert isinstance(x, (int, float))
if side == 'left':
offset = -1
elif side == 'right':
offset = 0
elif side == 'stop': # 设定 如果遇到中间点就抛出错误
offset = -2
else:
raise Exception("参数错误")
if x < self.points_list[0].x:
raise Exception("x小于最小x值,不在多段线段上")
for id, pt in enumerate(self.points_list):
if x == pt.x: # 在端点上
if id == 0: # 起点 返回第一条的斜率
return self.get_slope_by_line_id(0)
elif id == self.num_of_points: # 终点 返回最后一条的斜率
return self.get_slope_by_line_id(id - 1)
else: # 中间点
if offset == -2:
raise Exception("遇到中间点")
return self.get_slope_by_line_id(id + offset)
elif x < pt.x: # 在线段内部
return self.get_slope_by_line_id(id - 1)
def get_value(self, x: float = 0.) -> float:
"""
获取横坐标为x时,y的值
:param x:
:return:
"""
assert isinstance(x, (int, float))
if x < self.points_list[0].x:
raise Exception("x小于最小x值,不在多段线段上")
for id, pt in enumerate(self.points_list):
if pt.x >= x: # 找到了
elo = Line3D.make_line_by_2_points(self.points_list[id - 1], pt)
return elo.get_point('x', x).y
raise Exception("x大于最大x值,不在多段线上")
def show(self):
#使用matplot显示
x,y=self.get_array()
plt.plot(x,y)
plt.show()
pass
def get_array(self):
x_list=[x.x for x in self.points_list]
y_list = [x.y for x in self.points_list]
x=np.array(x_list)
y=np.array(y_list)
return x,y
if __name__ == '__main__':
pl = Polylines2D()
pl.append(Vector3D())
pl.append(Vector3D(1, 1))
assert_raises(Exception, pl.append, Vector3D(1, 1))
assert_raises(Exception, pl.append, Vector3D(0.5, 0))
assert 1. == pl.get_value(1)
assert 0.5 == pl.get_value(0.5)
assert_raises(Exception, pl.get_value, 1.1)
assert_raises(Exception, pl.get_value, -1.1)
pl.append(Vector3D(2, 3))
assert pl.get_slope(0.5) == 1.
assert pl.get_slope(1.1) == 2.
assert pl.get_slope(1) == 1.
assert pl.get_slope(1, side='right') == 2.
assert pl.get_slope(0, side='left') == 1.
assert pl.get_slope(0, side='right') == 1.
assert pl.get_slope(2, side='left') == 2.
assert_raises(Exception, pl.get_value, -1.1)
assert_raises(Exception, pl.get_value, 2.1)
assert_raises(Exception,pl.get_slope,1,'stop')
pl.show()
pl.show()
pl = Polylines2D()
pl.append(Vector3D())
pl.show()