From: Just van Rossum <jvr@us...>  20030907 09:41:32

Update of /cvsroot/fonttools/fonttools/Lib/fontTools/pens In directory sc8prcvs1:/tmp/cvsserv29637 Modified Files: basePen.py Log Message: Factored out the SuperBezier and TTimpliedpoint algorithms, as the may be useful separately from pens. Index: basePen.py =================================================================== RCS file: /cvsroot/fonttools/fonttools/Lib/fontTools/pens/basePen.py,v retrieving revision 1.6 retrieving revision 1.7 diff C2 d r1.6 r1.7 *** basePen.py 6 Sep 2003 16:00:03 0000 1.6  basePen.py 7 Sep 2003 09:41:28 0000 1.7 *************** *** 38,42 **** ! __all__ = ["AbstractPen", "BasePen"]  38,43  ! __all__ = ["AbstractPen", "BasePen", ! "decomposeSuperBezierSegment", "decomposeQuadraticSegment"] *************** *** 66,74 **** if n==0 we draw a straight line. It gets interesting when n>2: n1 PostScriptstyle cubic segments will be drawn as if it were ! one curve. The conversion algorithm used for n>2 is inspired by NURB splines, and is conceptually equivalent to the TrueType "implied ! points" principle. See also qCurveTo(). """ raise NotImplementedError  67,75  if n==0 we draw a straight line. It gets interesting when n>2: n1 PostScriptstyle cubic segments will be drawn as if it were ! one curve. See decomposeSuperBezierSegment(). The conversion algorithm used for n>2 is inspired by NURB splines, and is conceptually equivalent to the TrueType "implied ! points" principle. See also decomposeQuadraticSegment(). """ raise NotImplementedError *************** *** 82,86 **** This method implements TrueTypestyle curves, breaking up curves using 'implied points': between each two consequtive offcurve points, ! there is one implied point exactly in the middle between them. The last argument (normally the oncurve point) may be None.  83,88  This method implements TrueTypestyle curves, breaking up curves using 'implied points': between each two consequtive offcurve points, ! there is one implied point exactly in the middle between them. See ! also decomposeQuadraticSegment(). The last argument (normally the oncurve point) may be None. *************** *** 193,197 **** if n == 2: # The common case, we have exactly two BCP's, so this is a standard ! # cubic bezier. self._curveToOne(*points) self.__currentPoint = points[1]  195,201  if n == 2: # The common case, we have exactly two BCP's, so this is a standard ! # cubic bezier. Even though decomposeSuperBezierSegment() handles ! # this case just fine, we specialcase it anyway since it's so ! # common. self._curveToOne(*points) self.__currentPoint = points[1] *************** *** 204,228 **** # allows one to construct multiple bezier segments with a much # smaller amount of points. ! pt1, pt2, pt3 = points[0], None, None ! for i in range(2, n+1): ! # calculate points in between control points. ! nDivisions = min(i, 3, ni+2) ! d = float(nDivisions) ! for j in range(1, nDivisions): ! factor = j / d ! temp1 = points[i1] ! temp2 = points[i2] ! temp = (temp2[0] + factor * (temp1[0]  temp2[0]), ! temp2[1] + factor * (temp1[1]  temp2[1])) ! if pt2 is None: ! pt2 = temp ! else: ! pt3 = (0.5 * (pt2[0] + temp[0]), ! 0.5 * (pt2[1] + temp[1])) ! self._curveToOne(pt1, pt2, pt3) ! self.__currentPoint = pt3 ! pt1, pt2, pt3 = temp, None, None ! self._curveToOne(pt1, points[2], points[1]) ! self.__currentPoint = points[1] elif n == 1: self.qCurveTo(*points)  208,215  # allows one to construct multiple bezier segments with a much # smaller amount of points. ! _curveToOne = self._curveToOne ! for pt1, pt2, pt3 in decomposeSuperBezierSegment(points): ! _curveToOne(pt1, pt2, pt3) ! self.__currentPoint = pt3 elif n == 1: self.qCurveTo(*points) *************** *** 254,269 **** # This is where the segment splits. _qCurveToOne = self._qCurveToOne ! for i in range(n  1): ! x, y = points[i] ! nx, ny = points[i+1] ! impliedPt = (0.5 * (x + nx), 0.5 * (y + ny)) ! _qCurveToOne(points[i], impliedPt) ! self.__currentPoint = impliedPt ! _qCurveToOne(points[2], points[1]) ! self.__currentPoint = points[1] else: self.lineTo(points[0]) class _TestPen(BasePen): """Test class that prints PostScript to stdout."""  241,308  # This is where the segment splits. _qCurveToOne = self._qCurveToOne ! for pt1, pt2 in decomposeQuadraticSegment(points): ! _qCurveToOne(pt1, pt2) ! self.__currentPoint = pt2 else: self.lineTo(points[0]) + def decomposeSuperBezierSegment(points): + """Split the SuperBezier described by 'points' into a list of regular + bezier segments. The 'points' argument must be a sequence with length + 3 or greater, containing (x, y) coordinates. The last point is the + destination oncurve point, the rest of the points are offcurve points. + The start point should not be supplied. + + This function returns a list of (pt1, pt2, pt3) tuples, which each + specify a regular curvetostyle bezier segment. + """ + n = len(points)  1 + assert n > 1 + bezierSegments = [] + pt1, pt2, pt3 = points[0], None, None + for i in range(2, n+1): + # calculate points in between control points. + nDivisions = min(i, 3, ni+2) + d = float(nDivisions) + for j in range(1, nDivisions): + factor = j / d + temp1 = points[i1] + temp2 = points[i2] + temp = (temp2[0] + factor * (temp1[0]  temp2[0]), + temp2[1] + factor * (temp1[1]  temp2[1])) + if pt2 is None: + pt2 = temp + else: + pt3 = (0.5 * (pt2[0] + temp[0]), + 0.5 * (pt2[1] + temp[1])) + bezierSegments.append((pt1, pt2, pt3)) + pt1, pt2, pt3 = temp, None, None + bezierSegments.append((pt1, points[2], points[1])) + return bezierSegments + + + def decomposeQuadraticSegment(points): + """Split the quadratic curve segment described by 'points' into a list + of "atomic" quadratic segments. The 'points' argument must be a sequence + with length 2 or greater, containing (x, y) coordinates. The last point + is the destination oncurve point, the rest of the points are offcurve + points. The start point should not be supplied. + + This function returns a list of (pt1, pt2) tuples, which each specify a + plain quadratic bezier segment. + """ + n = len(points)  1 + assert n > 0 + quadSegments = [] + for i in range(n  1): + x, y = points[i] + nx, ny = points[i+1] + impliedPt = (0.5 * (x + nx), 0.5 * (y + ny)) + quadSegments.append((points[i], impliedPt)) + quadSegments.append((points[2], points[1])) + return quadSegments + + class _TestPen(BasePen): """Test class that prints PostScript to stdout.""" *************** *** 283,287 **** pen.moveTo((0, 0)) pen.lineTo((0, 100)) ! pen.qCurveTo((50, 75), (60, 50), (50, 25), (0, 0)) pen.closePath()  322,326  pen.moveTo((0, 0)) pen.lineTo((0, 100)) ! pen.curveTo((50, 75), (60, 50), (50, 25), (0, 0)) pen.closePath() 