Newer
Older
####################################################################################################
#
# PyValentina - A Python implementation of Valentina Pattern Drafting Software
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
144
145
146
147
148
149
150
151
152
153
154
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
####################################################################################################
####################################################################################################
from .Vector2D import Vector2D
from Valentina.Tools.IterTools import pairwise
####################################################################################################
class Line2D(object):
""" 2D Line """
#######################################
@staticmethod
def from_two_points(p0, p1):
""" Construct a :class:`Line2D` from two points. """
return Line2D(p0, p1 - p0)
#######################################
def __init__(self, point, vector):
""" Construct a :class:`Line2D` from a point and a vector. """
self.p = point
self.v = vector
#######################################
def __str__(self):
text = '''Line
Point %s
Vector %s
magnitude %g
'''
return text % (str(self.p), str(self.v), self.v.magnitude())
#######################################
def point_at_s(self, s):
""" Return the Point corresponding to the curvilinear abscissa s """
return self.p + (self.v * s)
#######################################
def compute_distance_between_abscissae(self, s0, s1):
""" Compute distance between two abscissae """
return abs(s1 - s0) * self.v.magnitude()
#######################################
def compute_distance(self, s_list):
""" Compute distance between a set of abscissae """
# Fixme: ?
# s_list_sorted = copy.deepcopy(s_list)
# s_list_sorted.sort()
return [self.compute_distance_between_abscissae(s0, s1) for s0, s1 in pairwise(s_list)]
#######################################
def get_y_from_x(self, x):
""" Return y corresponding to x """
return self.v.tan() * (x - self.p.x) + self.p.y
#######################################
def get_x_from_y(self, y):
""" Return x corresponding to y """
return self.v.inverse_tan() * (y - self.p.y) + self.p.x
#######################################
# Fixme: is_parallel_to
def is_parallel(self, other):
""" Self is parallel to other """
return self.v.is_parallel(other.v)
#######################################
def is_orthogonal(self, other):
""" Self is orthogonal to other """
return self.v.is_orthogonal(other.v)
#######################################
def shifted_parallel_line(self, shift):
""" Return the shifted parallel line """
n = self.v.rotate_counter_clockwise_90()
n.normalise()
point = self.p + n*shift
return self.__class__(point, self.v)
#######################################
def orthogonal_line_at_abscissa(self, s):
""" Return the orthogonal line at abscissa s """
point = self.point_at_s(s)
vector = self.v.rotate_counter_clockwise_90()
return self.__class__(point, vector)
#######################################
def intersection_abscissae(l1, l2):
""" Return the intersection abscissae between l1 and l2 """
# l1 = p1 + s1*v1
# l2 = p2 + s2*v2
# delta = p2 - p1 = s2*v2 - s1*v1
# delta x v1 = s2*v2 x v1 = s2 * - v1 x v2
# delta x v2 = s1*v1 x v2 = s1 * v1 x v2
if l1.is_parallel(l2):
return (None, None)
else:
s1 = delta.cross(l2.v) * denominator
s2 = delta.cross(l1.v) * -denominator
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
return (s1, s2)
#######################################
def intersection(self, other):
""" Return the intersection Point between self and other """
s0, s1 = self.intersection_abscissae(other)
if s0 is None:
return None
else:
return self.point_at_s(s0)
#######################################
def projected_abscissa(self, point):
""" Return the abscissa corresponding to the perpendicular projection of a point to the line
"""
delta = point - self.p
s = delta.projection_on(self.v)
return s
#######################################
def distance_to_line(self, point):
""" Return the distance of a point to the line """
delta = point - self.p
d = delta.deviation_with(self.v)
return d
#######################################
def distance_and_abscissa_to_line(self, point):
""" Return the distance of a point to the line """
delta = point - self.p
d = delta.deviation_with(self.v)
s = delta.projection_on(self.v)
return (d, s) # distance to line, abscissa
#######################################
def get_x_y_from_bounding_box(self, interval):
""" Return the bounding box build on the intersection of the input bounding box with the
line
"""
left, bottom, right, top = interval.bounding_box()
vb = Vector2D(interval.size())
if abs(self.v.tan()) > vb.tan():
x_min, y_min = self.get_x_from_y(bottom), bottom
x_max, y_max = self.get_x_from_y(top), top
else:
x_min, y_min = left, self.get_y_from_x(left)
x_max, y_max = right, self.get_y_from_x(right)
return Vector2D(x_min, y_min), Vector2D(x_max, y_max)