55import functools
66import logging
77import math
8+ import itertools
89import weakref
910import numpy as np
1011from numbers import Real
@@ -31,6 +32,17 @@ def _rotate(theta):
3132 return Affine2D ().rotate (theta )
3233
3334
35+ def _rotate_point (rotation , x , y ):
36+ """
37+ Rotate point (x, y) by rotation angle in degrees
38+ """
39+ if rotation == 0 :
40+ return (x , y )
41+ rotation_rad = math .radians (rotation )
42+ cos , sin = math .cos (rotation_rad ), math .sin (rotation_rad )
43+ return (cos * x - sin * y , sin * x + cos * y )
44+
45+
3446def _get_textbox (text , renderer ):
3547 """
3648 Calculate the bounding box of the text.
@@ -516,19 +528,17 @@ def _get_layout(self, renderer):
516528 # the corners of the unrotated bounding box
517529 corners_horiz = [(xmin , ymin ), (xmin , ymax ), (xmax , ymax ), (xmax , ymin )]
518530
519- # now rotate the bbox (skip if no rotation for speed)
531+ # now rotate the bbox
520532 rotation = self .get_rotation ()
521- if rotation != 0 :
522- M = _rotate (math .radians (rotation ))
523- corners_rotated = M .transform (corners_horiz )
524- # compute the bounds of the rotated box (direct indexing for speed)
525- (x0 , y0 ), (x1 , y1 ), (x2 , y2 ), (x3 , y3 ) = corners_rotated .tolist ()
526- xmin = min (x0 , x1 , x2 , x3 )
527- xmax = max (x0 , x1 , x2 , x3 )
528- ymin = min (y0 , y1 , y2 , y3 )
529- ymax = max (y0 , y1 , y2 , y3 )
530- width = xmax - xmin
531- height = ymax - ymin
533+ rotate = functools .partial (_rotate_point , rotation )
534+ corners_rotated = [rotate (x , y ) for x , y in corners_horiz ]
535+
536+ # compute the bounds of the rotated box
537+ xs , ys = zip (* corners_rotated )
538+ xmin , xmax = min (xs ), max (xs )
539+ ymin , ymax = min (ys ), max (ys )
540+ width = xmax - xmin
541+ height = ymax - ymin
532542
533543 # Now move the box to the target position offset the display
534544 # bbox by alignment
@@ -582,22 +592,17 @@ def _get_layout(self, renderer):
582592 else :
583593 offsety = ymin1
584594
585- if rotation != 0 :
586- offsetx , offsety = M .transform ((offsetx , offsety ))
595+ offsetx , offsety = rotate (offsetx , offsety )
587596
588597 xmin -= offsetx
589598 ymin -= offsety
590599
591600 bbox = Bbox .from_bounds (xmin , ymin , width , height )
592601
593602 # now rotate the positions around the first (x, y) position
594- if rotation != 0 :
595- xys = (M .transform (offset_layout ) - (offsetx , offsety )).tolist ()
596- else :
597- xys = [(x - offsetx , y - offsety ) for x , y in offset_layout ]
598-
599- info = [(ln , (w , h ), xy [0 ], xy [1 ])
600- for ln , w , h , xy in zip (lines , ws , hs , xys )]
603+ xys = [(x - offsetx , y - offsety )
604+ for x , y in itertools .starmap (rotate , offset_layout )]
605+ info = [(ln , (w , h ), xy [0 ], xy [1 ]) for ln , w , h , xy in zip (lines , ws , hs , xys )]
601606 return bbox , info , descent
602607
603608 def set_bbox (self , rectprops ):
0 commit comments