def contours(path): """Returns a list of contours in the path. 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. >>> path = BezierPath(None) >>> path.moveto(0, 0) >>> path.lineto(100, 100) >>> len(contours(path)) 1 A new contour is defined as something that starts with a moveto: >>> path.moveto(50, 50) >>> path.curveto(150, 150, 50, 250, 80, 95) >>> len(contours(path)) 2 Empty moveto's don't do anything: >>> path.moveto(50, 50) >>> path.moveto(50, 50) >>> len(contours(path)) 2 It doesn't matter if the path is closed or open: >>> path.closepath() >>> len(contours(path)) 2 """ 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(path._ctx) 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 contours(path): """Returns a list of contours in the path. 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. >>> path = BezierPath(None) >>> path.moveto(0, 0) >>> path.lineto(100, 100) >>> len(contours(path)) 1 A new contour is defined as something that starts with a moveto: >>> path.moveto(50, 50) >>> path.curveto(150, 150, 50, 250, 80, 95) >>> len(contours(path)) 2 Empty moveto's don't do anything: >>> path.moveto(50, 50) >>> path.moveto(50, 50) >>> len(contours(path)) 2 It doesn't matter if the path is closed or open: >>> path.closepath() >>> len(contours(path)) 2 """ 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(path._ctx) 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. >>> path = BezierPath(None) >>> path.moveto(0, 0) >>> insert_point(path, 0.1) Traceback (most recent call last): ... NodeBoxError: The given path is empty >>> path.moveto(0, 0) >>> insert_point(path, 0.2) Traceback (most recent call last): ... NodeBoxError: The given path is empty >>> path.lineto(100, 50) >>> len(path) 2 >>> path = insert_point(path, 0.5) >>> len(path) 3 >>> path[1] PathElement(LINETO, ((50.0, 25.0),)) >>> path = BezierPath(None) >>> path.moveto(0, 100) >>> path.curveto(0, 50, 100, 50, 100, 100) >>> path = insert_point(path, 0.5) >>> path[1] PathElement(LINETO, ((25.0, 62.5), (0.0, 75.0), (50.0, 62.5)) """ 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 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 NodeBoxError, "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 NodeBoxError, "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 insert_point(path, t): """Returns a path copy with an extra point at t. >>> path = BezierPath(None) >>> path.moveto(0, 0) >>> insert_point(path, 0.1) Traceback (most recent call last): ... NodeBoxError: The given path is empty >>> path.moveto(0, 0) >>> insert_point(path, 0.2) Traceback (most recent call last): ... NodeBoxError: The given path is empty >>> path.lineto(100, 50) >>> len(path) 2 >>> path = insert_point(path, 0.5) >>> len(path) 3 >>> path[1] PathElement(LINETO, ((50.0, 25.0),)) >>> path = BezierPath(None) >>> path.moveto(0, 100) >>> path.curveto(0, 50, 100, 50, 100, 100) >>> path = insert_point(path, 0.5) >>> path[1] PathElement(LINETO, ((25.0, 62.5), (0.0, 75.0), (50.0, 62.5)) """ 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 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 NodeBoxError, "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 NodeBoxError, "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