def contours(path): """ Returns a list of contours in the path, as BezierPath objects. A contour is a sequence of lines and curves separated from the next contour by a MOVETO. For example, the glyph "o" has two contours: the inner circle and the outer circle. """ contours = [] current_contour = None empty = True for i, el in enumerate(path): if el.cmd == MOVETO: if not empty: contours.append(current_contour) current_contour = BezierPath() current_contour.moveto(el.x, el.y) empty = True elif el.cmd == LINETO: empty = False current_contour.lineto(el.x, el.y) elif el.cmd == CURVETO: empty = False current_contour.curveto(el.ctrl1.x, el.ctrl1.y, el.ctrl2.x, el.ctrl2.y, el.x, el.y) elif el.cmd == CLOSE: current_contour.closepath() if not empty: contours.append(current_contour) return contours
def insert_point(path, t): """ Returns a path copy with an extra point at t. """ # Find the points before and after t on the path. i, t, closeto = _locate(path, t) x0 = path[i].x y0 = path[i].y p1 = path[i+1] p1cmd, x3, y3, x1, y1, x2, y2 = p1.cmd, p1.x, p1.y, p1.ctrl1.x, p1.ctrl1.y, p1.ctrl2.x, p1.ctrl2.y # Construct the new point at t. if p1cmd == CLOSE: pt_cmd = LINETO pt_x, pt_y = linepoint(t, x0, y0, closeto.x, closeto.y) elif p1cmd == LINETO: pt_cmd = LINETO pt_x, pt_y = linepoint(t, x0, y0, x3, y3) elif p1cmd == CURVETO: pt_cmd = CURVETO pt_x, pt_y, pt_c1x, pt_c1y, pt_c2x, pt_c2y, pt_h1x, pt_h1y, pt_h2x, pt_h2y = \ curvepoint(t, x0, y0, x1, y1, x2, y2, x3, y3, True) else: raise PathError, "Locate should not return a MOVETO" new_path = BezierPath(None) new_path.moveto(path[0].x, path[0].y) for j in range(1, len(path)): if j == i+1: if pt_cmd == CURVETO: new_path.curveto(pt_h1x, pt_h1y, pt_c1x, pt_c1y, pt_x, pt_y) new_path.curveto(pt_c2x, pt_c2y, pt_h2x, pt_h2y, path[j].x, path[j].y) elif pt_cmd == LINETO: new_path.lineto(pt_x, pt_y) if path[j].cmd != CLOSE: new_path.lineto(path[j].x, path[j].y) else: new_path.closepath() else: raise PathError, "Didn't expect pt_cmd %s here" % pt_cmd else: if path[j].cmd == MOVETO: new_path.moveto(path[j].x, path[j].y) if path[j].cmd == LINETO: new_path.lineto(path[j].x, path[j].y) if path[j].cmd == CURVETO: new_path.curveto(path[j].ctrl1.x, path[j].ctrl1.y, path[j].ctrl2.x, path[j].ctrl2.y, path[j].x, path[j].y) if path[j].cmd == CLOSE: new_path.closepath() return new_path
def findpath(points, curvature=1.0): """ Constructs a smooth BezierPath from the given list of points. The curvature parameter offers some control on how separate segments are stitched together: from straight angles to smooth curves. Curvature is only useful if the path has more than three points. """ # The list of points consists of Point objects, # but it shouldn't crash on something straightforward # as someone supplying a list of (x,y)-tuples. from types import TupleType for i, pt in enumerate(points): if type(pt) == TupleType: points[i] = Point(pt[0], pt[1]) # No points: return nothing. if len(points) == 0: return None # One point: return a path with a single MOVETO-point. if len(points) == 1: path = BezierPath(None) path.moveto(points[0].x, points[0].y) return path # Two points: path with a single straight line. if len(points) == 2: path = BezierPath(None) path.moveto(points[0].x, points[0].y) path.lineto(points[1].x, points[1].y) return path # Zero curvature means path with straight lines. curvature = max(0, min(1, curvature)) if curvature == 0: path = BezierPath(None) path.moveto(points[0].x, points[0].y) for i in range(len(points)): path.lineto(points[i].x, points[i].y) return path # Construct the path with curves. curvature = 4 + (1.0 - curvature) * 40 # The first point's ctrl1 and ctrl2 and last point's ctrl2 # will be the same as that point's location; # we cannot infer how the path curvature started or will continue. dx = {0: 0, len(points) - 1: 0} dy = {0: 0, len(points) - 1: 0} bi = {1: -0.25} ax = {1: (points[2].x - points[0].x - dx[0]) / 4} ay = {1: (points[2].y - points[0].y - dy[0]) / 4} for i in range(2, len(points) - 1): bi[i] = -1 / (curvature + bi[i - 1]) ax[i] = -(points[i + 1].x - points[i - 1].x - ax[i - 1]) * bi[i] ay[i] = -(points[i + 1].y - points[i - 1].y - ay[i - 1]) * bi[i] r = range(1, len(points) - 1) r.reverse() for i in r: dx[i] = ax[i] + dx[i + 1] * bi[i] dy[i] = ay[i] + dy[i + 1] * bi[i] path = BezierPath(None) path.moveto(points[0].x, points[0].y) for i in range(len(points) - 1): path.curveto(points[i].x + dx[i], points[i].y + dy[i], points[i + 1].x - dx[i + 1], points[i + 1].y - dy[i + 1], points[i + 1].x, points[i + 1].y) return path
def findpath(points, curvature=1.0): """ Constructs a smooth BezierPath from the given list of points. The curvature parameter offers some control on how separate segments are stitched together: from straight angles to smooth curves. Curvature is only useful if the path has more than three points. """ # The list of points consists of Point objects, # but it shouldn't crash on something straightforward # as someone supplying a list of (x,y)-tuples. from types import TupleType for i, pt in enumerate(points): if type(pt) == TupleType: points[i] = Point(pt[0], pt[1]) # No points: return nothing. if len(points) == 0: return None # One point: return a path with a single MOVETO-point. if len(points) == 1: path = BezierPath(None) path.moveto(points[0].x, points[0].y) return path # Two points: path with a single straight line. if len(points) == 2: path = BezierPath(None) path.moveto(points[0].x, points[0].y) path.lineto(points[1].x, points[1].y) return path # Zero curvature means path with straight lines. curvature = max(0, min(1, curvature)) if curvature == 0: path = BezierPath(None) path.moveto(points[0].x, points[0].y) for i in range(len(points)): path.lineto(points[i].x, points[i].y) return path # Construct the path with curves. curvature = 4 + (1.0-curvature)*40 # The first point's ctrl1 and ctrl2 and last point's ctrl2 # will be the same as that point's location; # we cannot infer how the path curvature started or will continue. dx = {0: 0, len(points)-1: 0} dy = {0: 0, len(points)-1: 0} bi = {1: -0.25} ax = {1: (points[2].x-points[0].x-dx[0]) / 4} ay = {1: (points[2].y-points[0].y-dy[0]) / 4} for i in range(2, len(points)-1): bi[i] = -1 / (curvature + bi[i-1]) ax[i] = -(points[i+1].x-points[i-1].x-ax[i-1]) * bi[i] ay[i] = -(points[i+1].y-points[i-1].y-ay[i-1]) * bi[i] r = range(1, len(points)-1) r.reverse() for i in r: dx[i] = ax[i] + dx[i+1] * bi[i] dy[i] = ay[i] + dy[i+1] * bi[i] path = BezierPath(None) path.moveto(points[0].x, points[0].y) for i in range(len(points)-1): path.curveto(points[i].x + dx[i], points[i].y + dy[i], points[i+1].x - dx[i+1], points[i+1].y - dy[i+1], points[i+1].x, points[i+1].y) return path