Esempio n. 1
0
 def _update_path(self):
     x, y = self.mouse()
     path = Path()
     if len(self._points) > 0:
         first = True
         for i in range(len(self._points)):
             
             # Construct the path.
             pt = self._points[i]
             if first:
                 path.moveto(pt.x, pt.y)
                 first = False
             else:
                 if pt.cmd == CLOSE:
                     path.close()
                 elif pt.cmd == MOVETO:
                     path.moveto(pt.x, pt.y)
                 elif pt.cmd == LINETO:
                     path.lineto(pt.x, pt.y)
                 elif pt.cmd == CURVETO:
                     path.curveto(pt.ctrl1.x, pt.ctrl1.y, 
                                  pt.ctrl2.x, pt.ctrl2.y, 
                                  pt.x, pt.y)
     # Set the current path,
     self.path = path
Esempio n. 2
0
def parse_circle(e):
    
    x = float(get_attribute(e, "cx"))
    y = float(get_attribute(e, "cy"))
    r = float(get_attribute(e, "r"))
    p = Path()
    p.ellipse(x, y, r*2, r*2)
    p.close()
    return p
Esempio n. 3
0
def parse_circle(e):

    x = float(get_attribute(e, "cx"))
    y = float(get_attribute(e, "cy"))
    r = float(get_attribute(e, "r"))
    p = Path()
    p.ellipse(x, y, r * 2, r * 2)
    p.close()
    return p
Esempio n. 4
0
def parse_oval(e):

    x = float(get_attribute(e, "cx"))
    y = float(get_attribute(e, "cy"))
    w = float(get_attribute(e, "rx")) * 2
    h = float(get_attribute(e, "ry")) * 2
    p = Path()
    p.ellipse(x, y, w, h)
    p.close()
    return p
Esempio n. 5
0
def parse_oval(e):
    
    x = float(get_attribute(e, "cx"))
    y = float(get_attribute(e, "cy"))
    w = float(get_attribute(e, "rx"))*2
    h = float(get_attribute(e, "ry"))*2
    p = Path()
    p.ellipse(x, y, w, h)
    p.close()
    return p
Esempio n. 6
0
def parse_circle(e):
    
    cx = float(get_attribute(e, "cx"))
    cy = float(get_attribute(e, "cy"))
    r = float(get_attribute(e, "r"))
    if r < 0:
        print >> sys.stderr, "Error: invalid negative value for <circle> attribute r=\"%s\"" % r
        r = 0
    p = Path()
    p.ellipse(cx, cy, r*2, r*2)
    p.close()
    return p
Esempio n. 7
0
def parse_circle(e):

    cx = float(get_attribute(e, "cx"))
    cy = float(get_attribute(e, "cy"))
    r = float(get_attribute(e, "r"))
    if r < 0:
        print >> sys.stderr, "Error: invalid negative value for <circle> attribute r=\"%s\"" % r
        r = 0
    p = Path()
    p.ellipse(cx, cy, r * 2, r * 2)
    p.close()
    return p
Esempio n. 8
0
def star(position, points, outer, inner):
    p = Path()
    p.moveto(position.x, position.y + outer / 2)
    # Calculate the points of the star.
    for i in xrange(1, points * 2):
        angle = i * pi / points
        radius = i % 2 and inner / 2 or outer / 2
        x = position.x + radius * sin(angle)
        y = position.y + radius * cos(angle)
        p.lineto(x, y)
    p.close()
    return p
Esempio n. 9
0
def star(position, points, outer, inner):
    p = Path()
    p.moveto(position.x, position.y + outer / 2)
    # Calculate the points of the star.
    for i in xrange(1, points * 2):
        angle = i * pi / points
        radius = i % 2 and inner / 2 or outer / 2
        x = position.x + radius * sin(angle)
        y = position.y + radius * cos(angle)
        p.lineto(x, y)
    p.close()
    return p
Esempio n. 10
0
def parse_ellipse(e):
    
    cx = float(get_attribute(e, "cx"))
    cy = float(get_attribute(e, "cy"))
    rx = float(get_attribute(e, "rx"))
    ry = float(get_attribute(e, "ry"))
    if rx < 0:
        print >> sys.stderr, "Error: invalid negative value for <ellipse> attribute rx=\"%s\"" % rx
        rx = 0
    if ry < 0:
        print >> sys.stderr, "Error: invalid negative value for <ellipse> attribute ry=\"%s\"" % ry
        ry = 0
    p = Path()
    p.ellipse(cx, cy, rx * 2, ry * 2)
    p.close()
    return p
Esempio n. 11
0
def parse_ellipse(e):

    cx = float(get_attribute(e, "cx"))
    cy = float(get_attribute(e, "cy"))
    rx = float(get_attribute(e, "rx"))
    ry = float(get_attribute(e, "ry"))
    if rx < 0:
        print >> sys.stderr, "Error: invalid negative value for <ellipse> attribute rx=\"%s\"" % rx
        rx = 0
    if ry < 0:
        print >> sys.stderr, "Error: invalid negative value for <ellipse> attribute ry=\"%s\"" % ry
        ry = 0
    p = Path()
    p.ellipse(cx, cy, rx * 2, ry * 2)
    p.close()
    return p
Esempio n. 12
0
def connect(points, closed=True):
    """Connects all points in a path."""

    if points is None: return None
    if len(points) < 2: return None
    points = list(points)
    start = points[0]
    p = Path()
    p.moveto(start.x, start.y)
    for point in points[1:]:
        p.lineto(point.x, point.y)
    if closed:
        p.close()
    p.stroke = Color.BLACK
    p.strokeWidth = 1.0
    return p
Esempio n. 13
0
def connect(points, closed=True):
    """Connects all points in a path."""
    
    if points is None: return None
    if len(points) < 2: return None
    points = list(points)
    start = points[0]
    p = Path()
    p.moveto(start.x, start.y)
    for point in points[1:]:
        p.lineto(point.x, point.y)
    if closed:
        p.close()
    p.stroke = Color.BLACK
    p.strokeWidth = 1.0
    return p
Esempio n. 14
0
def polygon(position, radius, sides, align):
    """Draw a polygon."""
    p = Path()
    x, y, r = position.x, position.y, radius
    sides = max(sides, 3)
    a = 360.0 / sides
    da = 0
    if align:
        x0, y0 = coordinates(x, y, r, 0)
        x1, y1 = coordinates(x, y, r, a)
        da = -angle(x1, y1, x0, y0)
    for i in xrange(sides):
        x1, y1 = coordinates(x, y, r, (a*i) + da)
        if i == 0:
            p.moveto(x1, y1)
        else:
            p.lineto(x1, y1)
    p.close()
    return p
Esempio n. 15
0
def polygon(position, radius, sides, align):
    """Draw a polygon."""
    p = Path()
    x, y, r = position.x, position.y, radius
    sides = max(sides, 3)
    a = 360.0 / sides
    da = 0
    if align:
        x0, y0 = coordinates(x, y, r, 0)
        x1, y1 = coordinates(x, y, r, a)
        da = -angle(x1, y1, x0, y0)
    for i in xrange(sides):
        x1, y1 = coordinates(x, y, r, (a * i) + da)
        if i == 0:
            p.moveto(x1, y1)
        else:
            p.lineto(x1, y1)
    p.close()
    return p
Esempio n. 16
0
def parse_polygon(e):
    
    d = get_attribute(e, "points", default="")
    d = d.replace(" ", ",")
    d = d.replace("-", ",")
    d = d.split(",")
    points = []
    for x in d:
        if x != "": points.append(float(x))
    
    autoclosepath = True
    if (e.tagName == "polyline") :
        autoclosepath = False

    p = Path()
    p.moveto(points[0], points[1])
    for i in range(len(points)/2):
        p.lineto(points[i*2], points[i*2+1])
    if autoclosepath:
        p.close()
    return p
Esempio n. 17
0
def parse_polygon(e):

    d = get_attribute(e, "points", default="")
    d = d.replace(" ", ",")
    d = d.replace("-", ",")
    d = d.split(",")
    points = []
    for x in d:
        if x != "": points.append(float(x))

    autoclosepath = True
    if (e.tagName == "polyline"):
        autoclosepath = False

    p = Path()
    p.moveto(points[0], points[1])
    for i in range(len(points) / 2):
        p.lineto(points[i * 2], points[i * 2 + 1])
    if autoclosepath:
        p.close()
    return p
Esempio n. 18
0
def parse_path(e):

    d = get_attribute(e, "d", default="")
    
    # Divide the path data string into segments.
    # Each segment starts with a path command,
    # usually followed by coordinates.
    segments = []
    i = 0
    for j in range(len(d)):
        commands = ["M", "m", "Z", "z", "L", "l", "H", "h", "V", "v", "C","c", "S", "s", "A"]
        if d[j] in commands:
            segments.append(d[i:j].strip())
            i = j
    segments.append(d[i:].strip())
    segments.remove("")
    
    previous_command = ""
    
    # Path origin (moved by MOVETO).
    x0 = 0
    y0 = 0
    
    # The current point in the path.
    dx = 0
    dy = 0
    
    # The previous second control handle.
    dhx = 0
    dhy = 0
    
    path = Path()

    for segment in segments:
        
        command = segment[0]

        if command in ["Z", "z"]:
            path.close()
        else:
            # The command is a pen move, line or curve.
            # Get the coordinates.
            points = segment[1:].strip()
            points = points.replace("-", ",-")
            points = points.replace(" ", ",")
            points = re.sub(",+", ",", points)
            points = points.strip(",")
            points = [float(i) for i in points.split(",")]
        
        # Absolute MOVETO.
        # Move the current point to the new coordinates.
        if command == "M":
            for i in range(len(points)/2):
                path.moveto(points[i*2], points[i*2+1])
                dx = points[i*2]
                dy = points[i*2+1]
                x0 = dx
                y0 = dy

        # Relative MOVETO.
        # Offset from the current point.
        elif command == "m":
            for i in range(len(points)/2):
                path.moveto(dx+points[i*2], dy+points[i*2+1])
                dx += points[i*2]
                dy += points[i*2+1]
                x0 = dx
                y0 = dy
        
        # Absolute LINETO.
        # Draw a line from the current point to the new coordinate.
        elif command == "L":
            for i in range(len(points)/2):
                path.lineto(points[i*2], points[i*2+1])
                dx = points[i*2]
                dy = points[i*2+1]

        # Relative LINETO.
        # Offset from the current point.
        elif command == "l":
            for i in range(len(points)/2):
                path.lineto(dx+points[i*2], dy+points[i*2+1])
                dx += points[i*2]
                dy += points[i*2+1]

        # Absolute horizontal LINETO.
        # Only the vertical coordinate is supplied.
        elif command == "H":
            for i in range(len(points)):
                path.lineto(points[i], dy)
                dx = points[i]

        # Relative horizontal LINETO.
        # Offset from the current point.
        elif command == "h":
            for i in range(len(points)):
                path.lineto(dx+points[i], dy)
                dx += points[i]

        # Absolute vertical LINETO.
        # Only the horizontal coordinate is supplied.
        if command == "V":
            for i in range(len(points)):
                path.lineto(dx, points[i])
                dy = points[i]

        # Relative vertical LINETO.
        # Offset from the current point.
        elif command == "v":
            for i in range(len(points)):
                path.lineto(dx, dy+points[i])
                dy += points[i]

        # Absolute CURVETO.
        # Draw a bezier with given control handles and destination.
        elif command == "C":
            for i in range(len(points)/6):
                path.curveto(points[i*6],   points[i*6+1], 
                             points[i*6+2], points[i*6+3], 
                             points[i*6+4], points[i*6+5])
                dhx = points[i*6+2]
                dhy = points[i*6+3]
                dx = points[i*6+4]
                dy = points[i*6+5]
        
        # Relative CURVETO.
        # Offset from the current point.
        elif command == "c":
            for i in range(len(points)/6):
                path.curveto(dx+points[i*6],   dy+points[i*6+1], 
                             dx+points[i*6+2], dy+points[i*6+3], 
                             dx+points[i*6+4], dy+points[i*6+5])
                dhx = dx+points[i*6+2]
                dhy = dy+points[i*6+3]
                dx += points[i*6+4]
                dy += points[i*6+5]

        # Absolute reflexive CURVETO.
        # Only the second control handle is given,
        # the first is the reflexion of the previous handle.
        elif command == "S":
            for i in range(len(points)/4):
                if previous_command not in ["C", "c", "S", "s"]:
                    dhx = dx
                    dhy = dy
                else:
                    dhx = dx-dhx
                    dhy = dy-dhy
                path.curveto(dx+dhx, dy+dhy, 
                             points[i*4],   points[i*4+1], 
                             points[i*4+2], points[i*4+3])
                dhx = points[i*4]
                dhy = points[i*4+1]
                dx = points[i*4+2]
                dy = points[i*4+3]
                
        # Relative reflexive CURVETO.
        # Offset from the current point.
        elif command == "s":
            for i in range(len(points)/4):
                if previous_command not in ["C", "c", "S", "s"]:
                    dhx = dx
                    dhy = dy
                else:
                    dhx = dx-dhx
                    dhy = dy-dhy
                path.curveto(dx+dhx, dy+dhy, 
                             dx+points[i*4],   dy+points[i*4+1], 
                             dx+points[i*4+2], dy+points[i*4+3])
                dhx = dx+points[i*4]
                dhy = dy+points[i*4+1]
                dx += points[i*4+2]
                dy += points[i*4+3]
        
        # Absolute elliptical arc.
        elif command == "A":
            rx, ry, phi, large_arc_flag, sweep_flag, x2, y2 = points
            for p in arc.elliptical_arc_to(dx, dy, rx, ry, phi, large_arc_flag, sweep_flag, x2, y2):
                if len(p) == 2: 
                    path.lineto(*p)
                elif len(p) == 6: 
                    path.curveto(*p)
            dx = p[-2]
            dy = p[-1]

        previous_command = command
        
    return path
Esempio n. 19
0
def parse_path(e):

    d = get_attribute(e, "d", default="")
    d = re.sub(r",", r" ", d)  # get rid of all commas
    d = re.sub(r"([MmZzLlHhVvCcSsQqTtAa])([MmZzLlHhVvCcSsQqTtAa])", r"\1 \2",
               d)  # separate commands from commands
    d = re.sub(r"([MmZzLlHhVvCcSsQqTtAa])([MmZzLlHhVvCcSsQqTtAa])", r"\1 \2",
               d)  # separate commands from commands
    d = re.sub(r"([MmZzLlHhVvCcSsQqTtAa])([^\s])", r"\1 \2",
               d)  # separate commands from points
    d = re.sub(r"([^\s])([MmZzLlHhVvCcSsQqTtAa])", r"\1 \2",
               d)  # separate commands from points
    d = re.sub(r"([0-9])([+\-])", r"\1 \2", d)  # separate digits when no comma
    d = re.sub(r"(\.[0-9]*)(\.)", r"\1 \2", d)  # separate digits when no comma
    d = re.sub(r"([Aa](\s+[0-9]+){3})\s+([01])\s*([01])", r"\1 \3 \4 ",
               d)  # shorthand elliptical arc path syntax
    d = re.sub(r"[\s\r\t\n]+", r" ", d)
    d = d.strip()

    path = Path()
    pp = PathParser(d)
    pp.reset()

    while not pp.isEnd():
        pp.nextCommand()
        command = pp.command.lower()
        if command == 'm':
            p = pp.getAsCurrentPoint()
            path.moveto(p.x, p.y)
            pp.start = pp.current
            while not pp.isCommandOrEnd():
                p = pp.getAsCurrentPoint()
                path.lineto(p.x, p.y)
        elif command == 'l':
            while not pp.isCommandOrEnd():
                p = pp.getAsCurrentPoint()
                path.lineto(p.x, p.y)
        elif command == 'h':
            while not pp.isCommandOrEnd():
                newP = Point((pp.isRelativeCommand() and pp.current.x or 0) +
                             pp.getScalar(), pp.current.y)
                pp.current = newP
                path.lineto(pp.current.x, pp.current.y)
        elif command == 'v':
            while not pp.isCommandOrEnd():
                newP = Point(pp.current.x,
                             (pp.isRelativeCommand() and pp.current.y or 0) +
                             pp.getScalar())
                pp.current = newP
                path.lineto(pp.current.x, pp.current.y)
        elif command == 'c':
            while not pp.isCommandOrEnd():
                curr = pp.current
                p1 = pp.getPoint()
                cntrl = pp.getAsControlPoint()
                cp = pp.getAsCurrentPoint()
                path.curveto(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y)
        elif command == 's':
            while not pp.isCommandOrEnd():
                curr = pp.current
                p1 = pp.getReflectedControlPoint()
                cntrl = pp.getAsControlPoint()
                cp = pp.getAsCurrentPoint()
                path.curveto(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y)
        elif command == 'q':
            while not pp.isCommandOrEnd():
                curr = pp.current
                cntrl = pp.getAsControlPoint()
                cp = pp.getAsCurrentPoint()
                cp1x = curr.x + 2 / 3.0 * (cntrl.x - curr.x
                                           )  # CP1 = QP0 + 2 / 3 *(QP1-QP0)
                cp1y = curr.y + 2 / 3.0 * (cntrl.y - curr.y
                                           )  # CP1 = QP0 + 2 / 3 *(QP1-QP0)
                cp2x = cp1x + 1 / 3.0 * (cp.x - curr.x
                                         )  # CP2 = CP1 + 1 / 3 *(QP2-QP0)
                cp2y = cp1y + 1 / 3.0 * (cp.y - curr.y
                                         )  # CP2 = CP1 + 1 / 3 *(QP2-QP0)
                g.curveto(cp1x, cp1y, cp2x, cp2y, cp.x, cp.y)
        elif command == 't':
            while not pp.isCommandOrEnd():
                curr = pp.current
                cntrl = pp.getReflectedControlPoint()
                pp.control = cntrl
                cp = pp.getAsCurrentPoint()
                cp1x = curr.x + 2 / 3.0 * (cntrl.x - curr.x
                                           )  # CP1 = QP0 + 2 / 3 *(QP1-QP0)
                cp1y = curr.y + 2 / 3.0 * (cntrl.y - curr.y
                                           )  # CP1 = QP0 + 2 / 3 *(QP1-QP0)
                cp2x = cp1x + 1 / 3.0 * (cp.x - curr.x
                                         )  # CP2 = CP1 + 1 / 3 *(QP2-QP0)
                cp2y = cp1y + 1 / 3.0 * (cp.y - curr.y
                                         )  # CP2 = CP1 + 1 / 3 *(QP2-QP0)
                path.curveto(cp1x, cp1y, cp2x, cp2y, cp.x, cp.y)
        elif command == 'a':
            while not pp.isCommandOrEnd():
                curr = pp.current
                rx = pp.getScalar()
                ry = pp.getScalar()
                rot = pp.getScalar()  # * (math.pi / 180.0)
                large = pp.getScalar()
                sweep = pp.getScalar()
                cp = pp.getAsCurrentPoint()
                ex = cp.x
                ey = cp.y
                segs = arcToSegments(ex, ey, rx, ry, large, sweep, rot, curr.x,
                                     curr.y)
                for seg in segs:
                    bez = segmentToBezier(*seg)
                    path.curveto(*bez)
        elif command == 'z':
            path.close()
            pp.current = pp.start
    return path
Esempio n. 20
0
def parse_path(e):

    d = get_attribute(e, "d", default="")
    d = re.sub(r",", r" ", d) # get rid of all commas
    d = re.sub(r"([MmZzLlHhVvCcSsQqTtAa])([MmZzLlHhVvCcSsQqTtAa])", r"\1 \2", d) # separate commands from commands
    d = re.sub(r"([MmZzLlHhVvCcSsQqTtAa])([MmZzLlHhVvCcSsQqTtAa])", r"\1 \2", d) # separate commands from commands
    d = re.sub(r"([MmZzLlHhVvCcSsQqTtAa])([^\s])", r"\1 \2", d) # separate commands from points
    d = re.sub(r"([^\s])([MmZzLlHhVvCcSsQqTtAa])", r"\1 \2", d) # separate commands from points
    d = re.sub(r"([0-9])([+\-])", r"\1 \2", d) # separate digits when no comma
    d = re.sub(r"(\.[0-9]*)(\.)", r"\1 \2", d) # separate digits when no comma
    d = re.sub(r"([Aa](\s+[0-9]+){3})\s+([01])\s*([01])", r"\1 \3 \4 ", d) # shorthand elliptical arc path syntax
    d = re.sub(r"[\s\r\t\n]+", r" ", d)
    d = d.strip()

    path = Path()
    pp = PathParser(d)
    pp.reset()

    while not pp.isEnd():
        pp.nextCommand()
        command = pp.command.lower()
        if command == 'm':
            p = pp.getAsCurrentPoint()
            path.moveto(p.x, p.y)
            pp.start = pp.current
            while not pp.isCommandOrEnd():
                p = pp.getAsCurrentPoint()
                path.lineto(p.x, p.y)
        elif command == 'l':
            while not pp.isCommandOrEnd():
                p = pp.getAsCurrentPoint()
                path.lineto(p.x, p.y)
        elif command == 'h':
            while not pp.isCommandOrEnd():
                newP = Point((pp.isRelativeCommand() and pp.current.x or 0) + pp.getScalar(), pp.current.y)
                pp.current = newP
                path.lineto(pp.current.x, pp.current.y)
        elif command == 'v':
            while not pp.isCommandOrEnd():
                newP = Point(pp.current.x, (pp.isRelativeCommand() and pp.current.y or 0) + pp.getScalar())
                pp.current = newP
                path.lineto(pp.current.x, pp.current.y)
        elif command == 'c':
            while not pp.isCommandOrEnd():
                curr = pp.current
                p1 = pp.getPoint()
                cntrl = pp.getAsControlPoint()
                cp = pp.getAsCurrentPoint()
                path.curveto(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y)
        elif command == 's':
            while not pp.isCommandOrEnd():
                curr = pp.current
                p1 = pp.getReflectedControlPoint()
                cntrl = pp.getAsControlPoint()
                cp = pp.getAsCurrentPoint()
                path.curveto(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y)
        elif command == 'q':
            while not pp.isCommandOrEnd():
                curr = pp.current
                cntrl = pp.getAsControlPoint()
                cp = pp.getAsCurrentPoint()
                cp1x = curr.x + 2 / 3.0 * (cntrl.x - curr.x) # CP1 = QP0 + 2 / 3 *(QP1-QP0)
                cp1y = curr.y + 2 / 3.0 * (cntrl.y - curr.y) # CP1 = QP0 + 2 / 3 *(QP1-QP0)
                cp2x = cp1x + 1 / 3.0 * (cp.x - curr.x) # CP2 = CP1 + 1 / 3 *(QP2-QP0)
                cp2y = cp1y + 1 / 3.0 * (cp.y - curr.y) # CP2 = CP1 + 1 / 3 *(QP2-QP0)
                g.curveto(cp1x, cp1y, cp2x, cp2y, cp.x, cp.y)
        elif command == 't':
            while not pp.isCommandOrEnd():
                curr = pp.current
                cntrl = pp.getReflectedControlPoint()
                pp.control = cntrl
                cp = pp.getAsCurrentPoint()
                cp1x = curr.x + 2 / 3.0 * (cntrl.x - curr.x) # CP1 = QP0 + 2 / 3 *(QP1-QP0)
                cp1y = curr.y + 2 / 3.0 * (cntrl.y - curr.y) # CP1 = QP0 + 2 / 3 *(QP1-QP0)
                cp2x = cp1x + 1 / 3.0 * (cp.x - curr.x) # CP2 = CP1 + 1 / 3 *(QP2-QP0)
                cp2y = cp1y + 1 / 3.0 * (cp.y - curr.y) # CP2 = CP1 + 1 / 3 *(QP2-QP0)
                path.curveto(cp1x, cp1y, cp2x, cp2y, cp.x, cp.y)
        elif command == 'a':
            while not pp.isCommandOrEnd():
                curr = pp.current
                rx = pp.getScalar()
                ry = pp.getScalar()
                rot = pp.getScalar() # * (math.pi / 180.0)
                large = pp.getScalar()
                sweep = pp.getScalar()
                cp = pp.getAsCurrentPoint()
                ex = cp.x
                ey = cp.y
                segs = arcToSegments(ex, ey, rx, ry, large, sweep, rot, curr.x, curr.y)
                for seg in segs:
                    bez = segmentToBezier(*seg)
                    path.curveto(*bez)
        elif command == 'z':
            path.close()
            pp.current = pp.start
    return path
Esempio n. 21
0
def parse_path(e):

    d = get_attribute(e, "d", default="")

    # Divide the path data string into segments.
    # Each segment starts with a path command,
    # usually followed by coordinates.
    segments = []
    i = 0
    for j in range(len(d)):
        commands = [
            "M", "m", "Z", "z", "L", "l", "H", "h", "V", "v", "C", "c", "S",
            "s", "A"
        ]
        if d[j] in commands:
            segments.append(d[i:j].strip())
            i = j
    segments.append(d[i:].strip())
    segments.remove("")

    previous_command = ""

    # Path origin (moved by MOVETO).
    x0 = 0
    y0 = 0

    # The current point in the path.
    dx = 0
    dy = 0

    # The previous second control handle.
    dhx = 0
    dhy = 0

    path = Path()

    for segment in segments:

        command = segment[0]

        if command in ["Z", "z"]:
            path.close()
        else:
            # The command is a pen move, line or curve.
            # Get the coordinates.
            points = segment[1:].strip()
            points = points.replace("-", ",-")
            points = points.replace(" ", ",")
            points = re.sub(",+", ",", points)
            points = points.strip(",")
            points = [float(i) for i in points.split(",")]

        # Absolute MOVETO.
        # Move the current point to the new coordinates.
        if command == "M":
            for i in range(len(points) / 2):
                path.moveto(points[i * 2], points[i * 2 + 1])
                dx = points[i * 2]
                dy = points[i * 2 + 1]
                x0 = dx
                y0 = dy

        # Relative MOVETO.
        # Offset from the current point.
        elif command == "m":
            for i in range(len(points) / 2):
                path.moveto(dx + points[i * 2], dy + points[i * 2 + 1])
                dx += points[i * 2]
                dy += points[i * 2 + 1]
                x0 = dx
                y0 = dy

        # Absolute LINETO.
        # Draw a line from the current point to the new coordinate.
        elif command == "L":
            for i in range(len(points) / 2):
                path.lineto(points[i * 2], points[i * 2 + 1])
                dx = points[i * 2]
                dy = points[i * 2 + 1]

        # Relative LINETO.
        # Offset from the current point.
        elif command == "l":
            for i in range(len(points) / 2):
                path.lineto(dx + points[i * 2], dy + points[i * 2 + 1])
                dx += points[i * 2]
                dy += points[i * 2 + 1]

        # Absolute horizontal LINETO.
        # Only the vertical coordinate is supplied.
        elif command == "H":
            for i in range(len(points)):
                path.lineto(points[i], dy)
                dx = points[i]

        # Relative horizontal LINETO.
        # Offset from the current point.
        elif command == "h":
            for i in range(len(points)):
                path.lineto(dx + points[i], dy)
                dx += points[i]

        # Absolute vertical LINETO.
        # Only the horizontal coordinate is supplied.
        if command == "V":
            for i in range(len(points)):
                path.lineto(dx, points[i])
                dy = points[i]

        # Relative vertical LINETO.
        # Offset from the current point.
        elif command == "v":
            for i in range(len(points)):
                path.lineto(dx, dy + points[i])
                dy += points[i]

        # Absolute CURVETO.
        # Draw a bezier with given control handles and destination.
        elif command == "C":
            for i in range(len(points) / 6):
                path.curveto(points[i * 6], points[i * 6 + 1],
                             points[i * 6 + 2], points[i * 6 + 3],
                             points[i * 6 + 4], points[i * 6 + 5])
                dhx = points[i * 6 + 2]
                dhy = points[i * 6 + 3]
                dx = points[i * 6 + 4]
                dy = points[i * 6 + 5]

        # Relative CURVETO.
        # Offset from the current point.
        elif command == "c":
            for i in range(len(points) / 6):
                path.curveto(dx + points[i * 6], dy + points[i * 6 + 1],
                             dx + points[i * 6 + 2], dy + points[i * 6 + 3],
                             dx + points[i * 6 + 4], dy + points[i * 6 + 5])
                dhx = dx + points[i * 6 + 2]
                dhy = dy + points[i * 6 + 3]
                dx += points[i * 6 + 4]
                dy += points[i * 6 + 5]

        # Absolute reflexive CURVETO.
        # Only the second control handle is given,
        # the first is the reflexion of the previous handle.
        elif command == "S":
            for i in range(len(points) / 4):
                if previous_command not in ["C", "c", "S", "s"]:
                    dhx = dx
                    dhy = dy
                else:
                    dhx = dx - dhx
                    dhy = dy - dhy
                path.curveto(dx + dhx, dy + dhy, points[i * 4],
                             points[i * 4 + 1], points[i * 4 + 2],
                             points[i * 4 + 3])
                dhx = points[i * 4]
                dhy = points[i * 4 + 1]
                dx = points[i * 4 + 2]
                dy = points[i * 4 + 3]

        # Relative reflexive CURVETO.
        # Offset from the current point.
        elif command == "s":
            for i in range(len(points) / 4):
                if previous_command not in ["C", "c", "S", "s"]:
                    dhx = dx
                    dhy = dy
                else:
                    dhx = dx - dhx
                    dhy = dy - dhy
                path.curveto(dx + dhx, dy + dhy, dx + points[i * 4],
                             dy + points[i * 4 + 1], dx + points[i * 4 + 2],
                             dy + points[i * 4 + 3])
                dhx = dx + points[i * 4]
                dhy = dy + points[i * 4 + 1]
                dx += points[i * 4 + 2]
                dy += points[i * 4 + 3]

        # Absolute elliptical arc.
        elif command == "A":
            rx, ry, phi, large_arc_flag, sweep_flag, x2, y2 = points
            for p in arc.elliptical_arc_to(dx, dy, rx, ry, phi, large_arc_flag,
                                           sweep_flag, x2, y2):
                if len(p) == 2:
                    path.lineto(*p)
                elif len(p) == 6:
                    path.curveto(*p)
            dx = p[-2]
            dy = p[-1]

        previous_command = command

    return path