Home | History | Annotate | Download | only in pens
      1 from __future__ import print_function, division, absolute_import
      2 from fontTools.misc.py23 import *
      3 from fontTools.misc.arrayTools import updateBounds, pointInRect, unionRect
      4 from fontTools.misc.bezierTools import calcCubicBounds, calcQuadraticBounds
      5 from fontTools.pens.basePen import BasePen
      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):
     68 			bounds = unionRect(bounds, calcCubicBounds(
     69 					self._getCurrentPoint(), bcp1, bcp2, pt))
     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):
     76 			bounds = unionRect(bounds, calcQuadraticBounds(
     77 					self._getCurrentPoint(), bcp, pt))
     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)
     91 	print(pen.bounds)
     92 
     93 	pen = BoundsPen(None)
     94 	draw(pen)
     95 	print(pen.bounds)
     96