@@ -18,7 +18,7 @@ def get_intersection(cx1, cy1, cos_t1, sin_t1,
18
18
cx2 , cy2 , cos_t2 , sin_t2 ):
19
19
"""
20
20
Return the intersection between the line through (*cx1*, *cy1*) at angle
21
- *t1* and the line through (*cx2, cy2) at angle *t2*.
21
+ *t1* and the line through (*cx2*, * cy2* ) at angle *t2*.
22
22
"""
23
23
24
24
# line1 => sin_t1 * (x - cx1) - cos_t1 * (y - cy1) = 0.
@@ -49,7 +49,7 @@ def get_intersection(cx1, cy1, cos_t1, sin_t1,
49
49
50
50
def get_normal_points (cx , cy , cos_t , sin_t , length ):
51
51
"""
52
- For a line passing through (*cx*, *cy*) and having a angle *t*, return
52
+ For a line passing through (*cx*, *cy*) and having an angle *t*, return
53
53
locations of the two points located along its perpendicular line at the
54
54
distance of *length*.
55
55
"""
@@ -99,21 +99,41 @@ def split_de_casteljau(beta, t):
99
99
def find_bezier_t_intersecting_with_closedpath (
100
100
bezier_point_at_t , inside_closedpath , t0 = 0. , t1 = 1. , tolerance = 0.01 ):
101
101
"""
102
- Find a parameter t0 and t1 of the given bezier path which
103
- bounds the intersecting points with a provided closed
104
- path(*inside_closedpath*). Search starts from *t0* and *t1* and it
105
- uses a simple bisecting algorithm therefore one of the end point
106
- must be inside the path while the other doesn't. The search stop
107
- when |t0-t1| gets smaller than the given tolerance.
108
- value for
102
+ Find the intersection of the bezier curve with a closed path.
109
103
110
- - bezier_point_at_t : a function which returns x, y coordinates at *t*
104
+ The intersection point *t* is approximated by two parameters *t0*, *t1*
105
+ such that *t0* <= *t* <= *t1*.
111
106
112
- - inside_closedpath : return True if the point is inside the path
107
+ Search starts from *t0* and *t1* and it uses a simple bisecting algorithm
108
+ therefore one of the end points must be inside the path while the other
109
+ doesn't. The search stops when the distance of the points parametrized by
110
+ *t0* and *t1* gets smaller than the given *tolerance*.
113
111
114
- """
115
- # inside_closedpath : function
112
+ Parameters
113
+ ----------
114
+ bezier_point_at_t : callable
115
+ A function returning x, y coordinates of the bezier at parameter *t*.
116
+ it must have the signature::
117
+
118
+ bezier_point_at_t(t: float) -> Tuple[float, float]
119
+
120
+ inside_closedpath : callable
121
+ A function returning True if a given point (x, y) is inside the
122
+ closed path. It must have the signature::
123
+
124
+ inside_closedpath(point: Tuple[float, float]) -> bool
116
125
126
+ t0, t1 : float
127
+ Start parameters for the search.
128
+
129
+ tolerance : float
130
+ Maximal allowed distance between the final points.
131
+
132
+ Returns
133
+ -------
134
+ t0, t1 : float
135
+ The bezier path parameters.
136
+ """
117
137
start = bezier_point_at_t (t0 )
118
138
end = bezier_point_at_t (t1 )
119
139
@@ -147,21 +167,22 @@ def find_bezier_t_intersecting_with_closedpath(
147
167
148
168
class BezierSegment :
149
169
"""
150
- A simple class of a 2-dimensional bezier segment
170
+ A 2-dimensional bezier segment.
171
+
172
+ Parameters
173
+ ----------
174
+ control_points : array-like (N, 2)
175
+ A list of the (x, y) positions of contol points of the bezier line.
176
+ This must contain N points ,where N is the order of the bezier line.
177
+ 1<= N <= 3 is supported.
151
178
"""
152
-
153
179
# Higher order bezier lines can be supported by simplying adding
154
180
# corresponding values.
155
181
_binom_coeff = {1 : np .array ([1. , 1. ]),
156
182
2 : np .array ([1. , 2. , 1. ]),
157
183
3 : np .array ([1. , 3. , 3. , 1. ])}
158
184
159
185
def __init__ (self , control_points ):
160
- """
161
- *control_points* : location of contol points. It needs have a
162
- shape of n * 2, where n is the order of the bezier line. 1<=
163
- n <= 3 is supported.
164
- """
165
186
_o = len (control_points )
166
187
self ._orders = np .arange (_o )
167
188
@@ -171,7 +192,7 @@ def __init__(self, control_points):
171
192
self ._py = yy * _coeff
172
193
173
194
def point_at_t (self , t ):
174
- "evaluate a point at t "
195
+ """Return the point (x, y) at parameter *t*."" "
175
196
tt = ((1 - t ) ** self ._orders )[::- 1 ] * t ** self ._orders
176
197
_x = np .dot (tt , self ._px )
177
198
_y = np .dot (tt , self ._py )
@@ -182,9 +203,23 @@ def point_at_t(self, t):
182
203
def split_bezier_intersecting_with_closedpath (
183
204
bezier , inside_closedpath , tolerance = 0.01 ):
184
205
"""
185
- bezier : control points of the bezier segment
186
- inside_closedpath : a function which returns true if the point is inside
187
- the path
206
+ Split a bezier curve into two at the intersection with a closed path.
207
+
208
+ Parameters
209
+ ----------
210
+ bezier : array-like(N, 2)
211
+ Control points of the bezier segment. See `.BezierSegment`.
212
+ inside_closedpath : callable
213
+ A function returning True if a given point (x, y) is inside the
214
+ closed path. See also `.find_bezier_t_intersecting_with_closedpath`.
215
+ tolerance : float
216
+ The tolerance for the intersection. See also
217
+ `.find_bezier_t_intersecting_with_closedpath`.
218
+
219
+ Returns
220
+ -------
221
+ left, right
222
+ Lists of control points for the two bezier segments.
188
223
"""
189
224
190
225
bz = BezierSegment (bezier )
@@ -205,12 +240,18 @@ def find_r_to_boundary_of_closedpath(
205
240
Find a radius r (centered at *xy*) between *rmin* and *rmax* at
206
241
which it intersect with the path.
207
242
208
- inside_closedpath : function
209
- cx, cy : center
210
- cos_t, sin_t : cosine and sine for the angle
211
- rmin, rmax :
243
+ Parameters
244
+ ----------
245
+ inside_closedpath : callable
246
+ A function returning True if a given point (x, y) is inside the
247
+ closed path.
248
+ xy : float, float
249
+ The center of the radius.
250
+ cos_t, sin_t : float
251
+ Cosine and sine for the angle.
252
+ rmin, rmax : float
253
+ Starting parameters for the radius search.
212
254
"""
213
-
214
255
cx , cy = xy
215
256
216
257
def _f (r ):
@@ -228,7 +269,6 @@ def split_path_inout(path, inside, tolerance=0.01, reorder_inout=False):
228
269
Divide a path into two segments at the point where ``inside(x, y)`` becomes
229
270
False.
230
271
"""
231
-
232
272
path_iter = path .iter_segments ()
233
273
234
274
ctl_points , command = next (path_iter )
@@ -287,6 +327,14 @@ def split_path_inout(path, inside, tolerance=0.01, reorder_inout=False):
287
327
288
328
289
329
def inside_circle (cx , cy , r ):
330
+ """
331
+ Return a function that checks whether a point is in a circle with center
332
+ (*cx*, *cy*) and radius *r*.
333
+
334
+ The returned function has the signature::
335
+
336
+ f(xy: Tuple[float, float]) -> bool
337
+ """
290
338
r2 = r ** 2
291
339
292
340
def _f (xy ):
@@ -309,8 +357,22 @@ def get_cos_sin(x0, y0, x1, y1):
309
357
@cbook ._rename_parameter ("3.1" , "tolerence" , "tolerance" )
310
358
def check_if_parallel (dx1 , dy1 , dx2 , dy2 , tolerance = 1.e-5 ):
311
359
"""
312
- Return 1 if two lines are parallel in same direction, -1 if two lines are
313
- parallel in opposite direction, 0 otherwise.
360
+ Check if two lines are parallel.
361
+
362
+ Parameters
363
+ ----------
364
+ dx1, dy1, dx2, dy2 : float
365
+ The gradients *dy*/*dx* of the two lines.
366
+ tolerance : float
367
+ The angular tolerange in rad up to which the lines are considered
368
+ parallel.
369
+
370
+ Returns
371
+ -------
372
+ is_parallel
373
+ - 1 if two lines are parallel in same direction.
374
+ - -1 if two lines are parallel in opposite direction.
375
+ - False otherwise.
314
376
"""
315
377
theta1 = np .arctan2 (dx1 , dy1 )
316
378
theta2 = np .arctan2 (dx2 , dy2 )
0 commit comments