Behdad Esfahbod | 1ae2959 | 2014-01-14 15:07:50 +0800 | [diff] [blame^] | 1 | from __future__ import print_function, division, absolute_import |
Behdad Esfahbod | 30e691e | 2013-11-27 17:27:45 -0500 | [diff] [blame] | 2 | from fontTools.misc.py23 import * |
jvr | b369ef3 | 2003-08-23 20:19:33 +0000 | [diff] [blame] | 3 | from fontTools.misc.arrayTools import updateBounds, pointInRect, unionRect |
| 4 | from fontTools.misc.bezierTools import calcCubicBounds, calcQuadraticBounds |
Behdad Esfahbod | 30e691e | 2013-11-27 17:27:45 -0500 | [diff] [blame] | 5 | from fontTools.pens.basePen import BasePen |
jvr | b369ef3 | 2003-08-23 20:19:33 +0000 | [diff] [blame] | 6 | |
| 7 | |
| 8 | __all__ = ["BoundsPen", "ControlBoundsPen"] |
| 9 | |
| 10 | |
| 11 | class ControlBoundsPen(BasePen): |
| 12 | |
| 13 | """Pen to calculate the "control bounds" of a shape. This is the |
| 14 | bounding box of all control points, so may be larger than the |
| 15 | actual bounding box if there are curves that don't have points |
| 16 | on their extremes. |
| 17 | |
| 18 | When the shape has been drawn, the bounds are available as the |
| 19 | 'bounds' attribute of the pen object. It's a 4-tuple: |
| 20 | (xMin, yMin, xMax, yMax) |
| 21 | """ |
| 22 | |
| 23 | def __init__(self, glyphSet): |
| 24 | BasePen.__init__(self, glyphSet) |
| 25 | self.bounds = None |
| 26 | |
| 27 | def _moveTo(self, pt): |
| 28 | bounds = self.bounds |
| 29 | if bounds: |
| 30 | self.bounds = updateBounds(bounds, pt) |
| 31 | else: |
| 32 | x, y = pt |
| 33 | self.bounds = (x, y, x, y) |
| 34 | |
| 35 | def _lineTo(self, pt): |
| 36 | self.bounds = updateBounds(self.bounds, pt) |
| 37 | |
| 38 | def _curveToOne(self, bcp1, bcp2, pt): |
| 39 | bounds = self.bounds |
| 40 | bounds = updateBounds(bounds, bcp1) |
| 41 | bounds = updateBounds(bounds, bcp2) |
| 42 | bounds = updateBounds(bounds, pt) |
| 43 | self.bounds = bounds |
| 44 | |
| 45 | def _qCurveToOne(self, bcp, pt): |
| 46 | bounds = self.bounds |
| 47 | bounds = updateBounds(bounds, bcp) |
| 48 | bounds = updateBounds(bounds, pt) |
| 49 | self.bounds = bounds |
| 50 | |
| 51 | |
| 52 | class BoundsPen(ControlBoundsPen): |
| 53 | |
| 54 | """Pen to calculate the bounds of a shape. It calculates the |
| 55 | correct bounds even when the shape contains curves that don't |
| 56 | have points on their extremes. This is somewhat slower to compute |
| 57 | than the "control bounds". |
| 58 | |
| 59 | When the shape has been drawn, the bounds are available as the |
| 60 | 'bounds' attribute of the pen object. It's a 4-tuple: |
| 61 | (xMin, yMin, xMax, yMax) |
| 62 | """ |
| 63 | |
| 64 | def _curveToOne(self, bcp1, bcp2, pt): |
| 65 | bounds = self.bounds |
| 66 | bounds = updateBounds(bounds, pt) |
| 67 | if not pointInRect(bcp1, bounds) or not pointInRect(bcp2, bounds): |
jvr | 82ef2a5 | 2003-08-23 20:24:42 +0000 | [diff] [blame] | 68 | bounds = unionRect(bounds, calcCubicBounds( |
| 69 | self._getCurrentPoint(), bcp1, bcp2, pt)) |
jvr | b369ef3 | 2003-08-23 20:19:33 +0000 | [diff] [blame] | 70 | self.bounds = bounds |
| 71 | |
| 72 | def _qCurveToOne(self, bcp, pt): |
| 73 | bounds = self.bounds |
| 74 | bounds = updateBounds(bounds, pt) |
| 75 | if not pointInRect(bcp, bounds): |
jvr | 82ef2a5 | 2003-08-23 20:24:42 +0000 | [diff] [blame] | 76 | bounds = unionRect(bounds, calcQuadraticBounds( |
| 77 | self._getCurrentPoint(), bcp, pt)) |
jvr | b369ef3 | 2003-08-23 20:19:33 +0000 | [diff] [blame] | 78 | self.bounds = bounds |
| 79 | |
| 80 | |
| 81 | if __name__ == "__main__": |
| 82 | def draw(pen): |
| 83 | pen.moveTo((0, 0)) |
| 84 | pen.lineTo((0, 100)) |
| 85 | pen.qCurveTo((50, 75), (60, 50), (50, 25), (0, 0)) |
| 86 | pen.curveTo((-50, 25), (-60, 50), (-50, 75), (0, 100)) |
| 87 | pen.closePath() |
| 88 | |
| 89 | pen = ControlBoundsPen(None) |
| 90 | draw(pen) |
Behdad Esfahbod | 3ec6a25 | 2013-11-27 04:57:33 -0500 | [diff] [blame] | 91 | print(pen.bounds) |
jvr | b369ef3 | 2003-08-23 20:19:33 +0000 | [diff] [blame] | 92 | |
| 93 | pen = BoundsPen(None) |
| 94 | draw(pen) |
Behdad Esfahbod | 3ec6a25 | 2013-11-27 04:57:33 -0500 | [diff] [blame] | 95 | print(pen.bounds) |