11"""
2- A module providing some utility functions regarding bezier path manipulation.
2+ A module providing some utility functions regarding Bezier path manipulation.
33"""
44
55import numpy as np
@@ -18,7 +18,7 @@ def get_intersection(cx1, cy1, cos_t1, sin_t1,
1818 cx2 , cy2 , cos_t2 , sin_t2 ):
1919 """
2020 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*.
2222 """
2323
2424 # line1 => sin_t1 * (x - cx1) - cos_t1 * (y - cy1) = 0.
@@ -49,7 +49,7 @@ def get_intersection(cx1, cy1, cos_t1, sin_t1,
4949
5050def get_normal_points (cx , cy , cos_t , sin_t , length ):
5151 """
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
5353 locations of the two points located along its perpendicular line at the
5454 distance of *length*.
5555 """
@@ -79,7 +79,7 @@ def _de_casteljau1(beta, t):
7979
8080def split_de_casteljau (beta , t ):
8181 """
82- Split a bezier segment defined by its control points *beta* into two
82+ Split a Bezier segment defined by its control points *beta* into two
8383 separate segments divided at *t* and return their control points.
8484 """
8585 beta = np .asarray (beta )
@@ -99,21 +99,41 @@ def split_de_casteljau(beta, t):
9999def find_bezier_t_intersecting_with_closedpath (
100100 bezier_point_at_t , inside_closedpath , t0 = 0. , t1 = 1. , tolerance = 0.01 ):
101101 """
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.
109103
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*.
111106
112- - inside_closedpath : return True if the point is inside the path
107+ Search starts from *t0* and *t1* and 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*.
113111
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
116125
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+ """
117137 start = bezier_point_at_t (t0 )
118138 end = bezier_point_at_t (t1 )
119139
@@ -147,21 +167,22 @@ def find_bezier_t_intersecting_with_closedpath(
147167
148168class BezierSegment :
149169 """
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 control 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.
151178 """
152-
153- # Higher order bezier lines can be supported by simplying adding
179+ # Higher order Bezier lines can be supported by simplying adding
154180 # corresponding values.
155181 _binom_coeff = {1 : np .array ([1. , 1. ]),
156182 2 : np .array ([1. , 2. , 1. ]),
157183 3 : np .array ([1. , 3. , 3. , 1. ])}
158184
159185 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- """
165186 _o = len (control_points )
166187 self ._orders = np .arange (_o )
167188
@@ -171,7 +192,7 @@ def __init__(self, control_points):
171192 self ._py = yy * _coeff
172193
173194 def point_at_t (self , t ):
174- "evaluate a point at t "
195+ """Return the point (x, y) at parameter *t*."" "
175196 tt = ((1 - t ) ** self ._orders )[::- 1 ] * t ** self ._orders
176197 _x = np .dot (tt , self ._px )
177198 _y = np .dot (tt , self ._py )
@@ -182,9 +203,23 @@ def point_at_t(self, t):
182203def split_bezier_intersecting_with_closedpath (
183204 bezier , inside_closedpath , tolerance = 0.01 ):
184205 """
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.
188223 """
189224
190225 bz = BezierSegment (bezier )
@@ -205,12 +240,18 @@ def find_r_to_boundary_of_closedpath(
205240 Find a radius r (centered at *xy*) between *rmin* and *rmax* at
206241 which it intersect with the path.
207242
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.
212254 """
213-
214255 cx , cy = xy
215256
216257 def _f (r ):
@@ -228,7 +269,6 @@ def split_path_inout(path, inside, tolerance=0.01, reorder_inout=False):
228269 Divide a path into two segments at the point where ``inside(x, y)`` becomes
229270 False.
230271 """
231-
232272 path_iter = path .iter_segments ()
233273
234274 ctl_points , command = next (path_iter )
@@ -287,6 +327,14 @@ def split_path_inout(path, inside, tolerance=0.01, reorder_inout=False):
287327
288328
289329def 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+ """
290338 r2 = r ** 2
291339
292340 def _f (xy ):
@@ -295,7 +343,7 @@ def _f(xy):
295343 return _f
296344
297345
298- # quadratic bezier lines
346+ # quadratic Bezier lines
299347
300348def get_cos_sin (x0 , y0 , x1 , y1 ):
301349 dx , dy = x1 - x0 , y1 - y0
@@ -309,8 +357,22 @@ def get_cos_sin(x0, y0, x1, y1):
309357@cbook ._rename_parameter ("3.1" , "tolerence" , "tolerance" )
310358def check_if_parallel (dx1 , dy1 , dx2 , dy2 , tolerance = 1.e-5 ):
311359 """
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 tolerance in radians 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.
314376 """
315377 theta1 = np .arctan2 (dx1 , dy1 )
316378 theta2 = np .arctan2 (dx2 , dy2 )
@@ -325,14 +387,14 @@ def check_if_parallel(dx1, dy1, dx2, dy2, tolerance=1.e-5):
325387
326388def get_parallels (bezier2 , width ):
327389 """
328- Given the quadratic bezier control points *bezier2*, returns
329- control points of quadratic bezier lines roughly parallel to given
390+ Given the quadratic Bezier control points *bezier2*, returns
391+ control points of quadratic Bezier lines roughly parallel to given
330392 one separated by *width*.
331393 """
332394
333- # The parallel bezier lines are constructed by following ways.
395+ # The parallel Bezier lines are constructed by following ways.
334396 # c1 and c2 are control points representing the begin and end of the
335- # bezier line.
397+ # Bezier line.
336398 # cm is the middle point
337399
338400 c1x , c1y = bezier2 [0 ]
@@ -355,7 +417,7 @@ def get_parallels(bezier2, width):
355417
356418 # find c1_left, c1_right which are located along the lines
357419 # through c1 and perpendicular to the tangential lines of the
358- # bezier path at a distance of width. Same thing for c2_left and
420+ # Bezier path at a distance of width. Same thing for c2_left and
359421 # c2_right with respect to c2.
360422 c1x_left , c1y_left , c1x_right , c1y_right = (
361423 get_normal_points (c1x , c1y , cos_t1 , sin_t1 , width )
@@ -385,7 +447,7 @@ def get_parallels(bezier2, width):
385447 sin_t1 , c2x_right , c2y_right ,
386448 cos_t2 , sin_t2 )
387449
388- # the parallel bezier lines are created with control points of
450+ # the parallel Bezier lines are created with control points of
389451 # [c1_left, cm_left, c2_left] and [c1_right, cm_right, c2_right]
390452 path_left = [(c1x_left , c1y_left ),
391453 (cmx_left , cmy_left ),
@@ -410,7 +472,7 @@ def find_control_points(c1x, c1y, mmx, mmy, c2x, c2y):
410472def make_wedged_bezier2 (bezier2 , width , w1 = 1. , wm = 0.5 , w2 = 0. ):
411473 """
412474 Being similar to get_parallels, returns control points of two quadratic
413- bezier lines having a width roughly parallel to given one separated by
475+ Bezier lines having a width roughly parallel to given one separated by
414476 *width*.
415477 """
416478
@@ -426,7 +488,7 @@ def make_wedged_bezier2(bezier2, width, w1=1., wm=0.5, w2=0.):
426488
427489 # find c1_left, c1_right which are located along the lines
428490 # through c1 and perpendicular to the tangential lines of the
429- # bezier path at a distance of width. Same thing for c3_left and
491+ # Bezier path at a distance of width. Same thing for c3_left and
430492 # c3_right with respect to c3.
431493 c1x_left , c1y_left , c1x_right , c1y_right = (
432494 get_normal_points (c1x , c1y , cos_t1 , sin_t1 , width * w1 )
0 commit comments