diff --git a/svgelements/svgelements.py b/svgelements/svgelements.py
index 1fd0eced..34c797ec 100644
--- a/svgelements/svgelements.py
+++ b/svgelements/svgelements.py
@@ -7584,33 +7584,18 @@ def union_bbox(elements, transformed=True, with_stroke=False):
:param with_stroke: should the stroke-width be included in the bounds of the elements
:return: union of all bounding boxes of elements within the iterable.
"""
- boundary_points = []
+ boxes = []
for e in elements:
- if not hasattr(e, "bbox"):
+ if not hasattr(e, "bbox") or isinstance(e, (Group, Use)):
continue
- box = e.bbox(transformed=False, with_stroke=with_stroke)
+ box = e.bbox(transformed=transformed, with_stroke=with_stroke)
if box is None:
continue
- top_left = (box[0], box[1])
- top_right = (box[2], box[1])
- bottom_left = (box[0], box[3])
- bottom_right = (box[2], box[3])
- if transformed:
- top_left = e.transform.point_in_matrix_space(top_left)
- top_right = e.transform.point_in_matrix_space(top_right)
- bottom_left = e.transform.point_in_matrix_space(bottom_left)
- bottom_right = e.transform.point_in_matrix_space(bottom_right)
- boundary_points.append(top_left)
- boundary_points.append(top_right)
- boundary_points.append(bottom_left)
- boundary_points.append(bottom_right)
- if len(boundary_points) == 0:
+ boxes.append(box)
+ if len(boxes) == 0:
return None
- xmin = min([e[0] for e in boundary_points])
- ymin = min([e[1] for e in boundary_points])
- xmax = max([e[0] for e in boundary_points])
- ymax = max([e[1] for e in boundary_points])
- return xmin, ymin, xmax, ymax
+ (xmins, ymins, xmaxs, ymaxs) = zip(*boxes)
+ return (min(xmins), min(ymins), max(xmaxs), max(ymaxs))
def bbox(self, transformed=True, with_stroke=False):
"""
diff --git a/test/test_bbox.py b/test/test_bbox.py
index 292b8812..92f2061b 100644
--- a/test/test_bbox.py
+++ b/test/test_bbox.py
@@ -275,6 +275,58 @@ def test_bbox_subpath_stroke(self):
61 + (5. / 2.)
))
+ def test_bbox_rotated_circle(self):
+ # Rotation of circle must not affect it's bounding box
+ c = Circle(cx=0, cy=0, r=1, transform="rotate(45)")
+ (xmin, ymin, xmax, ymax) = c.bbox()
+ self.assertAlmostEqual(-1, xmin)
+ self.assertAlmostEqual(-1, ymin)
+ self.assertAlmostEqual( 1, xmax)
+ self.assertAlmostEqual( 1, ymax)
+
+ def test_bbox_svg_with_rotated_circle(self):
+ # Rotation of circle within group must not affect it's bounding box
+ q = io.StringIO(
+ u'''
+
+ '''
+ )
+ svg = SVG.parse(q)
+ (xmin, ymin, xmax, ymax) = svg.bbox()
+ self.assertAlmostEqual(-1, xmin)
+ self.assertAlmostEqual(-1, ymin)
+ self.assertAlmostEqual( 1, xmax)
+ self.assertAlmostEqual( 1, ymax)
+
+ def test_bbox_translated_circle(self):
+ c = Circle(cx=0, cy=0, r=1, transform="translate(-1,-1)")
+ (xmin, ymin, xmax, ymax) = c.bbox()
+ self.assertAlmostEqual(-2, xmin)
+ self.assertAlmostEqual(-2, ymin)
+ self.assertAlmostEqual( 0, xmax)
+ self.assertAlmostEqual( 0, ymax)
+
+ def test_bbox_svg_with_translated_group_with_circle(self):
+ # Translation of nested group must be applied correctly
+ q = io.StringIO(
+ u'''
+
+ '''
+ )
+ svg = SVG.parse(q)
+ (xmin, ymin, xmax, ymax) = svg.bbox()
+ self.assertAlmostEqual(-2, xmin)
+ self.assertAlmostEqual(-2, ymin)
+ self.assertAlmostEqual( 0, xmax)
+ self.assertAlmostEqual( 0, ymax)
+
+
def test_issue_104(self):
"""Testing Issue 104 rotated bbox"""
rect = Rect(10,10,10,10)