Spaces:
Running
Running
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 | |