Example #1
0
def parse_rect(e):
    
    x = float(get_attribute(e, "x"))
    y = float(get_attribute(e, "y"))
    w = float(get_attribute(e, "width"))
    h = float(get_attribute(e, "height"))
    if w < 0:
        print >> sys.stderr, "Error: invalid negative value for <rect> attribute width=\"%s\"" % w
        w = 0
    if h < 0:
        print >> sys.stderr, "Error: invalid negative value for <rect> attribute height=\"%s\"" % h
        h = 0
    rx = float(get_attribute(e, "rx"))
    ry = float(get_attribute(e, "ry"))
    if rx < 0:
        print >> sys.stderr, "Error: invalid negative value for <rect> attribute rx=\"%s\"" % rx
        rx = 0
    if ry < 0:
        print >> sys.stderr, "Error: invalid negative value for <rect> attribute ry=\"%s\"" % ry
        ry = 0
    if not rx or not ry:
        rx = ry = max(rx, ry)
    if rx > w / 2.0: rx = w / 2.0
    if ry > h / 2.0: ry = h / 2.0
    p = Path()
    p.rect(x + w / 2.0, y + h / 2.0, w, h, rx, ry)
    return p
Example #2
0
def parse_rect(e):

    x = float(get_attribute(e, "x"))
    y = float(get_attribute(e, "y"))
    w = float(get_attribute(e, "width"))
    h = float(get_attribute(e, "height"))
    if w < 0:
        print >> sys.stderr, "Error: invalid negative value for <rect> attribute width=\"%s\"" % w
        w = 0
    if h < 0:
        print >> sys.stderr, "Error: invalid negative value for <rect> attribute height=\"%s\"" % h
        h = 0
    rx = float(get_attribute(e, "rx"))
    ry = float(get_attribute(e, "ry"))
    if rx < 0:
        print >> sys.stderr, "Error: invalid negative value for <rect> attribute rx=\"%s\"" % rx
        rx = 0
    if ry < 0:
        print >> sys.stderr, "Error: invalid negative value for <rect> attribute ry=\"%s\"" % ry
        ry = 0
    if not rx or not ry:
        rx = ry = max(rx, ry)
    if rx > w / 2.0: rx = w / 2.0
    if ry > h / 2.0: ry = h / 2.0
    p = Path()
    p.rect(x + w / 2.0, y + h / 2.0, w, h, rx, ry)
    return p
Example #3
0
def line_angle(position, angle, distance):
    p = Path()
    x1, y1 = coordinates(position.x, position.y, distance, angle)
    p.line(position.x, position.y, x1, y1)
    p.strokeColor = Color.BLACK
    p.strokeWidth = 1
    return p
Example #4
0
def text_on_path(text, shape, font_name, font_size, alignment, margin,
                 baseline_offset):
    if shape is None or shape.length <= 0: return None
    if text is None: return None

    text = unicode(text)

    if isinstance(shape, Path):
        shape = shape.asGeometry()

    p = Path()

    fm = get_font_metrics(font_name, font_size)
    string_width = textwidth(text, fm)
    dw = string_width / shape.length

    if alignment == "trailing":
        first = True

        for char in text:
            char_width = textwidth(char, fm)
            if first:
                t = (99.9 - margin) / 100.0
                first = False
            else:
                t -= char_width / string_width * dw
            t = t % 1.0

        margin = t * 100

    first = True

    for char in text:
        char_width = textwidth(char, fm)

        if first:
            t = margin / 100.0
            first = False
        else:
            t += char_width / string_width * dw

        # Always loop (the other behavior is weird)
        t = t % 1.0

        pt1 = shape.pointAt(t)
        pt2 = shape.pointAt(t + 0.0000001)
        a = angle(pt2.x, pt2.y, pt1.x, pt1.y)

        tp = Text(char, -char_width, -baseline_offset)
        tp.align = Text.Align.LEFT
        tp.fontName = font_name
        tp.fontSize = font_size
        tp.translate(pt1.x, pt1.y)
        tp.rotate(a - 180)

        for contour in tp.path.contours:
            p.add(contour)

    return p
Example #5
0
def transform(path, m, n1, n2, n3, scale=1.0, points=100, range=TWOPI):
    new_path = Path()
    for i in _range(points):
        pt = path.pointAt(float(i) / points)
        phi = i * range / points
        dx, dy = supercalc(m, n1, n2, n3, phi)
        new_path.addPoint(pt.x + dx * scale, pt.y + dy * scale)
    return new_path
Example #6
0
def transform(path, m, n1, n2, n3, scale=1.0, points=100, range=TWOPI):
    new_path = Path()
    for i in _range(points):
        pt = path.pointAt(float(i) / points)
        phi = i * range / points
        dx, dy = supercalc(m, n1, n2, n3, phi)
        new_path.addPoint(pt.x + dx * scale, pt.y + dy * scale)
    return new_path
Example #7
0
def text_on_path(text, shape, font_name, font_size, alignment, margin, baseline_offset):
    if shape is None or shape.length <= 0: return None
    if text is None: return None

    text = unicode(text)
    
    if isinstance(shape, Path):
        shape = shape.asGeometry()
    
    p = Path()

    fm = get_font_metrics(font_name, font_size)
    string_width = textwidth(text, fm)
    dw = string_width / shape.length
    
    if alignment == "trailing":
        first = True
        
        for char in text:
            char_width = textwidth(char, fm)
            if first:
                t = (99.9 - margin) / 100.0
                first = False
            else:
                t -= char_width / string_width * dw
            t = t % 1.0
        
        margin = t * 100

    first = True
    
    for char in text:
        char_width = textwidth(char, fm)
        
        if first:
            t = margin / 100.0
            first = False
        else:
            t += char_width / string_width * dw

        # Always loop (the other behavior is weird)
        t = t % 1.0

        pt1 = shape.pointAt(t)
        pt2 = shape.pointAt(t + 0.0000001)
        a = angle(pt2.x, pt2.y, pt1.x, pt1.y)
        
        tp = Text(char, -char_width, -baseline_offset)
        tp.align = Text.Align.LEFT
        tp.fontName = font_name
        tp.fontSize = font_size
        tp.translate(pt1.x, pt1.y)
        tp.rotate(a - 180)
        
        for contour in tp.path.contours:
            p.add(contour)
    
    return p
Example #8
0
def parse_rect(e):
    
    x = float(get_attribute(e, "x"))
    y = float(get_attribute(e, "y"))
    w = float(get_attribute(e, "width"))
    h = float(get_attribute(e, "height"))
    p = Path()
    p.rect(x+w/2, y+h/2, w, h)
    return p
Example #9
0
def parse_line(e):
    
    x1 = float(get_attribute(e, "x1"))
    y1 = float(get_attribute(e, "y1"))
    x2 = float(get_attribute(e, "x2"))
    y2 = float(get_attribute(e, "y2"))
    p = Path()
    p.line(x1, y1, x2, y2)
    return p
Example #10
0
def parse_line(e):

    x1 = float(get_attribute(e, "x1"))
    y1 = float(get_attribute(e, "y1"))
    x2 = float(get_attribute(e, "x2"))
    y2 = float(get_attribute(e, "y2"))
    p = Path()
    p.line(x1, y1, x2, y2)
    return p
Example #11
0
def parse_rect(e):

    x = float(get_attribute(e, "x"))
    y = float(get_attribute(e, "y"))
    w = float(get_attribute(e, "width"))
    h = float(get_attribute(e, "height"))
    p = Path()
    p.rect(x + w / 2, y + h / 2, w, h)
    return p
Example #12
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
Example #13
0
def _flatten(geo):
    compound = Path()
    first = True
    for path in geo.paths:
        if first:
             compound = path
             first = False
        else:
             compound = compound.united(path)
    return compound
Example #14
0
def _flatten(geo):
    compound = Path()
    first = True
    for path in geo.paths:
        if first:
            compound = path
            first = False
        else:
            compound = compound.united(path)
    return compound
Example #15
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
Example #16
0
def path(position, width, height, m, n1, n2, n3, points=1000, percentage=1.0, range=TWOPI):
    path = Path()
    for i in _range(points):
        if i > points*percentage:
            continue
        phi = i * range / points
        dx, dy = supercalc(m, n1, n2, n3, phi)
        dx = (dx * width / 2) + position.x
        dy = (dy * height / 2) + position.y
        path.addPoint(dx, dy)
    return path
Example #17
0
def delete_points(path, bounding, delete_selected=True):
    if path is None or bounding is None: return None
    new_path = Path(path, False) # cloneContours = False
    for old_contour in path.contours:
        new_contour = Contour()
        for point in old_contour.points:
            if bounding.contains(point) == delete_selected:
                new_contour.addPoint(Point(point.x, point.y, point.type))
        new_contour.closed = old_contour.closed
        new_path.add(new_contour)
    return new_path
Example #18
0
def makecurve(pt1, pt2, c1, c2):
    p = Path()
    p.moveto(pt1.x, pt1.y)
    p.curveto(c1.x, c1.y, c2.x, c2.y, pt2.x, pt2.y)
    p.fill = None
    p.stroke = Color.BLACK
    p.strokeWidth = 1.0
    return p
Example #19
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
Example #20
0
def transform(path, m, n1, n2, n3, points=100, range=TWOPI):
    first = True
    for i in _range(points):
        pt = path.getPoints#(float(i)/points)
        phi = i * range / points
        dx, dy = supercalc(m, n1, n2, n3, phi)
        if first:
            p = Path()
            p.moveto(pt.x+dx, pt.y+dy)
            first = False
        else:
            _ctx.lineto(pt.x+dx, pt.y+dy)
            p.lineto(pt.x+dx, pt.y+dy)
    return p
Example #21
0
 def shape_intersects(distance):
     tx, ty = coordinates(0, 0, distance, angle)
     t = Transform()
     t.translate(tx, ty)
     translated_shape = t.map(shape)
     if use_bounding_box:
         b = Path()
         b.cornerRect(translated_shape.bounds)
     else:
         b = translated_shape
     # If the shape intersects it is too close (the distance is too low).
     if bounding_path.intersects(b):
         return -1
     return 1
Example #22
0
 def _function(shape, *args, **kwargs):
     from java.util import List
     if isinstance(shape, (list, tuple, List)):
         return fn(shape, *args, **kwargs)
     elif isinstance(shape, Path):
         new_path = Path(shape, False)
         for c in shape.contours:
             new_path.add(Contour(fn(c.points, *args, **kwargs), c.closed))
         return new_path
     elif isinstance(shape, Geometry):
         new_geo = Geometry()
         for path in shape.paths:
             new_geo.add(_map_geo_to_points(fn)(path, *args, **kwargs))
         return new_geo
     return None
Example #23
0
 def _function(shape, *args, **kwargs):
     from java.util import List
     if isinstance(shape, (list, tuple, List)):
         return fn(shape, *args, **kwargs)
     elif isinstance(shape, Path):
         new_path = Path(shape, False)
         for c in shape.contours:
             new_path.add(Contour(fn(c.points, *args, **kwargs), c.closed))
         return new_path
     elif isinstance(shape, Geometry):
         new_geo = Geometry()
         for path in shape.paths:
             new_geo.add(_map_geo_to_points(fn)(path, *args, **kwargs))
         return new_geo
     return None
Example #24
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
Example #25
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
Example #26
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
Example #27
0
def arc(position, width, height, start_angle, degrees, arc_type):
    """Create an arc."""
    if arc_type == "chord":
        awt_type = Arc2D.CHORD
    elif arc_type == "pie":
        awt_type = Arc2D.PIE
    else:
        awt_type = Arc2D.OPEN
    p = Path(Arc2D.Double(position.x-width/2, position.y-height/2, width, height, -start_angle, -degrees, awt_type))
    return p
Example #28
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
Example #29
0
def path(position,
         width,
         height,
         m,
         n1,
         n2,
         n3,
         points=1000,
         percentage=1.0,
         range=TWOPI):
    path = Path()
    for i in _range(points):
        if i > points * percentage:
            continue
        phi = i * range / points
        dx, dy = supercalc(m, n1, n2, n3, phi)
        dx = (dx * width / 2) + position.x
        dy = (dy * height / 2) + position.y
        path.addPoint(dx, dy)
    return path
Example #30
0
def lpath(x, y, angle, angleScale, length, thicknessScale, lengthScale,
          full_rule):

    p = Path()
    p.rect(0, -length / 2, 2, length)
    segment = p.asGeometry()

    # Now run the simulation
    g = Geometry()
    stack = []
    angleStack = []
    t = Transform()
    t.translate(x, y)
    for letter in full_rule:
        if re.search('[a-zA-Z]', letter):  # Move forward and draw
            newShape = t.map(segment)
            g.extend(newShape)
            t.translate(0, -length)
        elif letter == '+':  # Rotate right
            t.rotate(angle)
        elif letter == '-':  # Rotate left
            t.rotate(-angle)
        elif letter == '[':  # Push state (start branch)
            stack.append(Transform(t))
            angleStack.append(angle)
        elif letter == ']':  # Pop state (end branch)
            t = stack.pop()
            angle = angleStack.pop()
        elif letter == '"':  # Multiply length
            t.scale(1.0, lengthScale / 100.0)
        elif letter == '!':  # Multiply thickness
            t.scale(thicknessScale / 100.0, 1.0)
        elif letter == ';':  # Multiply angle
            angle *= angleScale / 100.0
        elif letter == '_':  # Divide length
            t.scale(1.0, 1.0 / (lengthScale / 100.0))
        elif letter == '?':  # Divide thickness
            t.scale(1.0 / (thicknessScale / 100.0), 1.0)
        elif letter == '@':  # Divide angle
            angle /= angleScale / 100.0
    return g
Example #31
0
def line_angle(position, angle, distance):
    p = Path()
    x1, y1 = coordinates(position.x, position.y, distance, angle)
    p.line(position.x, position.y, x1, y1)
    p.strokeColor = Color.BLACK
    p.strokeWidth = 1
    return p
Example #32
0
def quad_curve(pt1, pt2, t, distance):
    t /= 100.0
    cx = pt1.x + t * (pt2.x - pt1.x)
    cy = pt1.y + t * (pt2.y - pt1.y)
    a = angle(pt1.x, pt1.y, pt2.x, pt2.y) + 90
    qx, qy = coordinates(cx, cy, distance, a)

    p = Path()
    p.moveto(pt1.x, pt1.y)
    c1x = pt1.x + 2 / 3.0 * (qx - pt1.x)
    c1y = pt1.y + 2 / 3.0 * (qy - pt1.y)
    c2x = pt2.x + 2 / 3.0 * (qx - pt2.x)
    c2y = pt2.y + 2 / 3.0 * (qy - pt2.y)
    p.curveto(c1x, c1y, c2x, c2y, pt2.x, pt2.y)
    p.fill = None
    p.stroke = Color.BLACK
    p.strokeWidth = 1.0
    return p
Example #33
0
def angle_pack(shapes, seed, limit, maximum_radius, angle_tries=1, use_bounding_box=False):
    if shapes is None: return None
    _seed(seed)

    def center_and_translate(shape, tx=0, ty=0):
        bx, by, bw, bh = list(shape.bounds)
        t = Transform()
        t.translate(-bw / 2 - bx, -bh / 2 - by)
        return t.map(shape)

    geo = Geometry()
    bounding_path = Path()

    # Center first shape
    first_shape = center_and_translate(shapes[0])
    geo.add(first_shape)
    bounding_path.cornerRect(first_shape.bounds)

    for shape in shapes[1:]:
        centered_shape = center_and_translate(shape)

        angles = []
        for i in range(angle_tries):
            a = uniform(0, 360)
            if use_bounding_box:
                d = try_angle(bounding_path, centered_shape, a, limit, maximum_radius, use_bounding_box)
            else:
                d = try_angle(geo, centered_shape, a, limit, maximum_radius, use_bounding_box)
            angles.append([d, a])
        chosen_distance, chosen_angle = sorted(angles)[0]

        tx, ty = coordinates(0, 0, chosen_distance, chosen_angle)
        t = Transform()
        t.translate(tx, ty)
        translated_shape = t.map(centered_shape)
        bounding_path.cornerRect(translated_shape.bounds)
        geo.add(translated_shape)

    return geo
Example #34
0
def rect(position, width, height, roundness):
    """Create a rectangle or rounded rectangle."""
    p = Path()
    if roundness == Point.ZERO:
        p.rect(position.x, position.y, width, height)
    else:
        p.roundedRect(position.x, position.y, width, height, roundness.x, roundness.y)
    return p
Example #35
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
Example #36
0
def _str_to_path(s):
    # Utility function to convert a string containing a list of points to a Path
    # The letter M marks the start of a new curve.
    p = Path()
    
    for curve_str in s.strip().split("M"):
        curve_str = curve_str.strip()
        if curve_str:
            coords = []
            for coord in curve_str.split(" "):
                try:
                    coords.append(float(coord))
                except:
                    pass
            coords = len(coords) % 2 and coords[:-1] or coords
            for i in range(0, len(coords), 2):
                x = coords[i]
                y = coords[i+1]
                if i == 0:
                    p.moveto(x, y)
                else:
                    p.lineto(x, y)
    return p
Example #37
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
Example #38
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
Example #39
0
def quad_curve(pt1, pt2, t, distance):
    t /= 100.0
    cx = pt1.x + t * (pt2.x - pt1.x)
    cy = pt1.y + t * (pt2.y - pt1.y)
    a = angle(pt1.x, pt1.y, pt2.x, pt2.y) + 90
    qx, qy = coordinates(cx, cy, distance, a)

    p = Path()
    p.moveto(pt1.x, pt1.y)
    c1x = pt1.x + 2/3.0 * (qx - pt1.x)
    c1y = pt1.y + 2/3.0 * (qy - pt1.y)
    c2x = pt2.x + 2/3.0 * (qx - pt2.x)
    c2y = pt2.y + 2/3.0 * (qy - pt2.y)
    p.curveto(c1x, c1y, c2x, c2y, pt2.x, pt2.y)
    p.fill = None
    p.stroke = Color.BLACK
    p.strokeWidth = 1.0
    return p
Example #40
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
Example #41
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
Example #42
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
Example #43
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
Example #44
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
Example #45
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
Example #46
0
def _str_to_path(s):
    # Utility function to convert a string containing a list of points to a Path
    # The letter M marks the start of a new curve.
    p = Path()

    for curve_str in s.strip().split("M"):
        curve_str = curve_str.strip()
        if curve_str:
            coords = []
            for coord in curve_str.split(" "):
                try:
                    coords.append(float(coord))
                except:
                    pass
            coords = len(coords) % 2 and coords[:-1] or coords
            for i in range(0, len(coords), 2):
                x = coords[i]
                y = coords[i + 1]
                if i == 0:
                    p.moveto(x, y)
                else:
                    p.lineto(x, y)
    return p
Example #47
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
Example #48
0
def ellipse(position, width, height):
    p = Path()
    p.ellipse(position.x, position.y, width, height)
    return p
Example #49
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
Example #50
0
def line(point1, point2):
    p = Path()
    p.line(point1.x, point1.y, point2.x, point2.y)
    p.strokeColor = Color.BLACK
    p.strokeWidth = 1
    return p
Example #51
0
def ellipse(position, width, height):
    p = Path()
    p.ellipse(position.x, position.y, width, height)
    return p
Example #52
0
def line(point1, point2):
    p = Path()
    p.line(point1.x, point1.y, point2.x, point2.y)
    p.strokeColor = Color.BLACK
    p.strokeWidth = 1
    return p
Example #53
0
def link(shape1, shape2, orientation):
    if shape1 is None or shape2 is None: return None
    p = Path()
    ax, ay, aw, ah = shape1.bounds
    bx, by, bw, bh = shape2.bounds
    if orientation == "horizontal":
        hw = (bx - (ax + aw)) / 2
        p.moveto(ax + aw, ay)
        p.curveto(ax + aw + hw, ay, bx - hw, by, bx, by)
        p.lineto(bx, by + bh)
        p.curveto(bx - hw, by + bh, ax + aw + hw, ay + ah, ax + aw, ay + ah)
    else:
        hh = (by - (ay + ah)) / 2
        p.moveto(ax, ay + ah)
        p.curveto(ax, ay + ah + hh, bx, by - hh, bx, by)
        p.lineto(bx + bw, by)
        p.curveto(bx + bw, by - hh, ax + aw, ay + ah + hh, ax + aw, ay + ah)
    return p
Example #54
0
def generator():
    """Serve as a template for future functions that generate geometry"""
    p = Path()
    p.rect(0, 0, 100, 100)
    return p
Example #55
0
def link(shape1, shape2, orientation):
    if shape1 is None or shape2 is None: return None
    p = Path()
    ax, ay, aw, ah = shape1.bounds
    bx, by, bw, bh = shape2.bounds
    if orientation == "horizontal":
        hw = (bx - (ax + aw)) / 2
        p.moveto(ax + aw, ay)
        p.curveto(ax + aw + hw, ay, bx - hw, by, bx, by)
        p.lineto(bx, by + bh)
        p.curveto(bx - hw, by + bh, ax + aw + hw, ay + ah, ax + aw, ay + ah)
    else:
        hh = (by - (ay + ah)) / 2
        p.moveto(ax, ay + ah)
        p.curveto(ax, ay + ah + hh, bx, by - hh, bx, by)
        p.lineto(bx + bw, by)
        p.curveto(bx + bw, by - hh, ax + aw, ay + ah + hh, ax + aw, ay + ah)
    return p
Example #56
0
def generator():
    """Serve as a template for future functions that generate geometry"""
    p = Path()
    p.rect(0, 0, 100, 100)
    return p
Example #57
0
def l_system(shape, position, generations, length, length_scale, angle, angle_scale, thickness_scale, premise, *rules):
    if shape is None:
        p = Path()
        p.rect(0, -length/2, 2, length)
        shape = p.asGeometry()
    # Parse all rules
    rule_map = {}
    for rule_index, full_rule in enumerate(rules):
        if len(full_rule) > 0:
            if len(full_rule) < 3 or full_rule[1] != '=':
                raise ValueError("Rule %s should be in the format A=FFF" % (rule_index + 1))
            rule_key = full_rule[0]
            rule_value = full_rule[2:]
            rule_map[rule_key] = rule_value
    # Expand the rules up to the number of generations
    full_rule = premise
    for gen in xrange(int(round(generations))):
        tmp_rule = ""
        for letter in full_rule:
            if letter in rule_map:
                tmp_rule += rule_map[letter]
            else:
                tmp_rule += letter
        full_rule = tmp_rule
    # Now run the simulation
    g = Geometry()
    stack = []
    angleStack = []
    t = Transform()
    t.translate(position.x, position.y)
    angle = angle
    for letter in full_rule:
        if letter == 'F': # Move forward and draw
            transformed_shape = t.map(shape)
            if isinstance(transformed_shape, Geometry):
                g.extend(transformed_shape)
            elif isinstance(transformed_shape, Path):
                g.add(transformed_shape)
            t.translate(0, -length)
        elif letter == '+': # Rotate right
            t.rotate(angle)
        elif letter == '-': # Rotate left
            t.rotate(-angle)
        elif letter == '[': # Push state (start branch)
            stack.append(Transform(t))
            angleStack.append(angle)
        elif letter == ']': # Pop state (end branch)
            t = stack.pop()
            angle = angleStack.pop()
        elif letter == '"': # Multiply length
            t.scale(1.0, length_scale / 100.0)
        elif letter == '!': # Multiply thickness
            t.scale(thickness_scale / 100.0, 1.0)
        elif letter == ';': # Multiply angle
            angle *= angle_scale / 100.0
        elif letter == '_': # Divide length
            t.scale(1.0, 1.0/(length_scale / 100.0))
        elif letter == '?': # Divide thickness
            t.scale(1.0/(thickness_scale / 100.0), 1.0)
        elif letter == '@': # Divide angle
            angle /= angle_scale / 100.0
    return g
Example #58
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
Example #59
0
def cook(generations,x,y,angle,angleScale,length,thicknessScale,lengthScale,premise,rule1,rule2,rule3):
    #segment = self.segment
    #if segment is None:
    p = Path()
    p.rect(0, -length/2, 2, length)
    segment = p.asGeometry()
    # Parse all rules
    ruleArgs = [rule1,rule2,rule3]
    rules = {}
    #rulenum = 1
    #while hasattr(cook,"rule%i" % rulenum):
    for full_rule in ruleArgs:
        #full_rule = getattr("rule%i" % rulenum)
        if len(full_rule) > 0:
            if len(full_rule) < 3 or full_rule[1] != '=':
                raise ValueError("Rule %s should be in the format A=FFF" % full_rule)
            rule_key = full_rule[0]
            rule_value = full_rule[2:]
            rules[rule_key] = rule_value
        #rulenum += 1
    # Expand the rules up to the number of generations
    full_rule = premise
    for gen in xrange(int(round(generations))):
        tmp_rule = ""
        for letter in full_rule:
            if letter in rules:
                tmp_rule += rules[letter]
            else:
                tmp_rule += letter
        full_rule = tmp_rule
    # Now run the simulation
    g = Geometry()
    stack = []
    angleStack = []
    t = Transform()
    t.translate(x, y)
    angle = angle
    for letter in full_rule:
        if re.search('[a-zA-Z]',letter): # Move forward and draw
            newShape = t.map(segment)
            g.extend(newShape)
            t.translate(0, -length)
        elif letter == '+': # Rotate right
            t.rotate(angle)
        elif letter == '-': # Rotate left
            t.rotate(-angle)
        elif letter == '[': # Push state (start branch)
            stack.append(Transform(t))
            angleStack.append(angle)
        elif letter == ']': # Pop state (end branch)
            t = stack.pop()
            angle = angleStack.pop()
        elif letter == '"': # Multiply length
            t.scale(1.0, lengthScale/100.0)
        elif letter == '!': # Multiply thickness
            t.scale(thicknessScale/100.0, 1.0)
        elif letter == ';': # Multiply angle
            angle *= angleScale/100.0
        elif letter == '_': # Divide length
            t.scale(1.0, 1.0/(lengthScale/100.0))
        elif letter == '?': # Divide thickness
            t.scale(1.0/(thicknessScale/100.0), 1.0)
        elif letter == '@': # Divide angle
            angle /= angleScale/100.0
    return g