예제 #1
0
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
예제 #2
0
파일: bezier.py 프로젝트: est/nodebox-gl
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
예제 #3
0
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
예제 #4
0
파일: bezier.py 프로젝트: est/nodebox-gl
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
예제 #5
0
파일: bezier.py 프로젝트: est/nodebox-gl
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