@@ -461,6 +461,53 @@ def iter_bezier(self, **kwargs):
461
461
raise ValueError ("Invalid Path.code_type: " + str (code ))
462
462
prev_vert = verts [- 2 :]
463
463
464
+ def _replace_bezier_control_points_with_extrema (self ):
465
+ """
466
+ Return a new version of this path, with any control points for Bezier
467
+ segments replaced with any extrema for that segment.
468
+
469
+ This is helpful when autoscaling. We don't want to include the control
470
+ points, which are often far away from the actual curve, but in order to
471
+ calculate a bounding box for the whole curve we need to include any
472
+ extrema as well as start and end points for each Bezier segment.
473
+
474
+ Notes
475
+ -----
476
+ If there are no curved Bezier segments, the current object is returned.
477
+ """
478
+ # Shortcut case where there are no curved segments
479
+ if not np .any (np .isin (self .codes , (Path .CURVE3 , Path .CURVE4 ))):
480
+ return self
481
+
482
+ vertices = np .array ([[], []]).T
483
+ codes = []
484
+ for bez_segment , code in self .iter_bezier ():
485
+ verts = bez_segment ._cpoints
486
+
487
+ # For low order segments (straight lines or points), just add
488
+ # the vertices
489
+ if code in (Path .MOVETO , Path .LINETO , Path .CLOSEPOLY ):
490
+ # Ignore the (already added) vertex at the start of this
491
+ # segment
492
+ if code in (Path .LINETO , Path .CLOSEPOLY ):
493
+ verts = verts [1 ]
494
+ codes += [code ] * self .NUM_VERTICES_FOR_CODE [code ]
495
+ # For higher order segments, calculate the extrema
496
+ elif code in (Path .CURVE3 , Path .CURVE4 ):
497
+ _ , t = bez_segment .axis_aligned_extrema ()
498
+ if len (t ):
499
+ extrema = bez_segment (t )
500
+ verts = np .vstack ((verts [0 ], extrema , verts [- 1 ]))
501
+ else :
502
+ verts = np .vstack ((verts [0 ], verts [- 1 ]))
503
+
504
+ # Add extrema to the start and end points
505
+ codes += [Path .LINETO ] * verts .shape [0 ]
506
+
507
+ vertices = np .vstack ((vertices , verts ))
508
+ # Construct path
509
+ return Path (vertices , codes )
510
+
464
511
@_api .delete_parameter ("3.3" , "quantize" )
465
512
def cleaned (self , transform = None , remove_nans = False , clip = None ,
466
513
quantize = False , simplify = False , curves = False ,
0 commit comments