Spaces:
Sleeping
Sleeping
| from fontTools.misc.arrayTools import updateBounds, pointInRect, unionRect | |
| from fontTools.misc.bezierTools import calcCubicBounds, calcQuadraticBounds | |
| from fontTools.pens.basePen import BasePen | |
| __all__ = ["BoundsPen", "ControlBoundsPen"] | |
| class ControlBoundsPen(BasePen): | |
| """Pen to calculate the "control bounds" of a shape. This is the | |
| bounding box of all control points, so may be larger than the | |
| actual bounding box if there are curves that don't have points | |
| on their extremes. | |
| When the shape has been drawn, the bounds are available as the | |
| ``bounds`` attribute of the pen object. It's a 4-tuple:: | |
| (xMin, yMin, xMax, yMax). | |
| If ``ignoreSinglePoints`` is True, single points are ignored. | |
| """ | |
| def __init__(self, glyphSet, ignoreSinglePoints=False): | |
| BasePen.__init__(self, glyphSet) | |
| self.ignoreSinglePoints = ignoreSinglePoints | |
| self.init() | |
| def init(self): | |
| self.bounds = None | |
| self._start = None | |
| def _moveTo(self, pt): | |
| self._start = pt | |
| if not self.ignoreSinglePoints: | |
| self._addMoveTo() | |
| def _addMoveTo(self): | |
| if self._start is None: | |
| return | |
| bounds = self.bounds | |
| if bounds: | |
| self.bounds = updateBounds(bounds, self._start) | |
| else: | |
| x, y = self._start | |
| self.bounds = (x, y, x, y) | |
| self._start = None | |
| def _lineTo(self, pt): | |
| self._addMoveTo() | |
| self.bounds = updateBounds(self.bounds, pt) | |
| def _curveToOne(self, bcp1, bcp2, pt): | |
| self._addMoveTo() | |
| bounds = self.bounds | |
| bounds = updateBounds(bounds, bcp1) | |
| bounds = updateBounds(bounds, bcp2) | |
| bounds = updateBounds(bounds, pt) | |
| self.bounds = bounds | |
| def _qCurveToOne(self, bcp, pt): | |
| self._addMoveTo() | |
| bounds = self.bounds | |
| bounds = updateBounds(bounds, bcp) | |
| bounds = updateBounds(bounds, pt) | |
| self.bounds = bounds | |
| class BoundsPen(ControlBoundsPen): | |
| """Pen to calculate the bounds of a shape. It calculates the | |
| correct bounds even when the shape contains curves that don't | |
| have points on their extremes. This is somewhat slower to compute | |
| than the "control bounds". | |
| When the shape has been drawn, the bounds are available as the | |
| ``bounds`` attribute of the pen object. It's a 4-tuple:: | |
| (xMin, yMin, xMax, yMax) | |
| """ | |
| def _curveToOne(self, bcp1, bcp2, pt): | |
| self._addMoveTo() | |
| bounds = self.bounds | |
| bounds = updateBounds(bounds, pt) | |
| if not pointInRect(bcp1, bounds) or not pointInRect(bcp2, bounds): | |
| bounds = unionRect( | |
| bounds, calcCubicBounds(self._getCurrentPoint(), bcp1, bcp2, pt) | |
| ) | |
| self.bounds = bounds | |
| def _qCurveToOne(self, bcp, pt): | |
| self._addMoveTo() | |
| bounds = self.bounds | |
| bounds = updateBounds(bounds, pt) | |
| if not pointInRect(bcp, bounds): | |
| bounds = unionRect( | |
| bounds, calcQuadraticBounds(self._getCurrentPoint(), bcp, pt) | |
| ) | |
| self.bounds = bounds | |