Esempio n. 1
0
def parse_transform(e, path):
    """ Transform the path according to a defined matrix.
    
    Attempts to extract a transform="matrix()|translate()" attribute.
    Transforms the path accordingly.
    
    """

    t = get_attribute(e, "transform", default="")

    for mode in ("matrix", "translate"):
        if t.startswith(mode):
            v = t.replace(mode, "").lstrip("(").rstrip(")")
            v = v.replace(", ", ",").replace(" ", ",")
            v = [float(x) for x in v.split(",")]
            from nodebox.graphics import Transform
            if mode == "matrix":
                t = Transform(*v)
            elif mode == "translate":
                t = Transform()
                t.translate(*v)
            path = t.map(path)
            break

    # Transformations can also be defined as <g transform="matrix()"><path /><g>
    # instead of <g><path transform="matrix() /></g>.
    e = e.parentNode
    if e and e.tagName == "g":
        path = parse_transform(e, path)

    return path
Esempio n. 2
0
def copy(shape,
         copies,
         transform_order='tsr',
         translate=Point.ZERO,
         rotate=0,
         scale=Point.ZERO):
    """Create multiple copies of a shape."""
    if shape is None: return None
    if isinstance(shape, Path):
        shape = shape.asGeometry()
    g = Geometry()
    tx = ty = r = 0.0
    sx = sy = 1.0
    for i in xrange(copies):
        t = Transform()
        # Each letter of the order describes an operation.
        for op in transform_order:
            if op == 't':
                t.translate(tx, ty)
            elif op == 'r':
                t.rotate(r)
            elif op == 's':
                t.scale(sx, sy)
        g.extend(t.map(shape))
        tx += translate.x
        ty += translate.y
        r += rotate
        sx += scale.x / 100.0
        sy += scale.y / 100.0
    return g
Esempio n. 3
0
def align(shape, position, halign="center", valign="middle"):
    """Align a shape in relation to the origin."""
    if shape is None: return None
    x, y = position.x, position.y
    bounds = shape.bounds
    if halign == "left":
        dx = x - bounds.x
    elif halign == "right":
        dx = x - bounds.x - bounds.width
    elif halign == "center":
        dx = x - bounds.x - bounds.width / 2
    else:
        dx = 0
    if valign == "top":
        dy = y - bounds.y
    elif valign == "bottom":
        dy = y - bounds.y - bounds.height
    elif valign == "middle":
        dy = y - bounds.y - bounds.height / 2
    else:
        dy = 0

    t = Transform()
    t.translate(dx, dy)
    return t.map(shape)
Esempio n. 4
0
def fit(shape, position, width, height, keep_proportions):
    """Fit a shape within bounds."""
    if shape is None: return None

    px, py, pw, ph = list(shape.bounds)

    # Make sure pw and ph aren't infinitely small numbers.
    # This will lead to incorrect transformations with for examples lines.
    if 0 < pw <= 0.000000000001: pw = 0
    if 0 < ph <= 0.000000000001: ph = 0

    t = Transform()
    t.translate(position.x, position.y)
    if keep_proportions:
        # Don't scale widths or heights that are equal to zero.
        w = pw and width / pw or float("inf")
        h = ph and height / ph or float("inf")
        w = h = min(w, h)
    else:
        # Don't scale widths or heights that are equal to zero.
        w = pw and width / pw or 1
        h = ph and height / ph or 1
    t.scale(w, h)
    t.translate(-pw / 2 - px, -ph / 2 - py)

    return t.map(shape)
Esempio n. 5
0
def rotate(shape, angle, origin=Point.ZERO):
    """Rotate the given shape."""
    if shape is None: return None
    t = Transform()
    t.translate(origin)
    t.rotate(angle)
    t.translate(Point(-origin.x, -origin.y))
    return t.map(shape)
Esempio n. 6
0
def scale(shape, scale, origin=Point.ZERO):
    """Scale the given shape."""
    if shape is None: return None
    t = Transform()
    t.translate(origin)
    t.scale(scale.x / 100.0, scale.y / 100.0)
    t.translate(Point(-origin.x, -origin.y))
    return t.map(shape)
Esempio n. 7
0
def stack(shapes, direction, margin):
    if shapes is None:
        return []
    if len(shapes) <= 1:
        return shapes
    first_bounds = shapes[0].bounds
    new_shapes = []
    if direction == 'e':
        tx = first_bounds.x
        for shape in shapes:
            bounds = shape.bounds
            t = Transform()
            t.translate(tx - bounds.x, 0)
            new_shapes.append(t.map(shape))
            tx += bounds.width + margin
        return new_shapes
    elif direction == 'w':
        tx = first_bounds.x + first_bounds.width
        for shape in shapes:
            bounds = shape.bounds
            t = Transform()
            t.translate(tx - (bounds.x + bounds.width), 0)
            new_shapes.append(t.map(shape))
            tx -= bounds.width + margin
        return new_shapes
    elif direction == 'n':
        ty = first_bounds.y + first_bounds.height
        for shape in shapes:
            bounds = shape.bounds
            t = Transform()
            t.translate(0, ty - (bounds.y + bounds.height))
            new_shapes.append(t.map(shape))
            ty -= bounds.height + margin
        return new_shapes
    elif direction == 's':
        ty = first_bounds.y
        for shape in shapes:
            bounds = shape.bounds
            t = Transform()
            t.translate(0, ty - bounds.y)
            new_shapes.append(t.map(shape))
            ty += bounds.height + margin
        return new_shapes
    else:
        raise ValueError('Invalid direction "%s."' % direction)
Esempio n. 8
0
def wiggle_contours(contours, offset):
    new_contours = []
    for contour in contours:
        dx = (uniform(0, 1) - 0.5) * offset.x * 2
        dy = (uniform(0, 1) - 0.5) * offset.y * 2
        t = Transform()
        t.translate(dx, dy)
        new_contours.append(Contour(t.map(contour.points), contour.closed))
    return new_contours
Esempio n. 9
0
def wiggle_paths(paths, offset):
    new_paths = []
    for path in paths:
        dx = (uniform(0, 1) - 0.5) * offset.x * 2
        dy = (uniform(0, 1) - 0.5) * offset.y * 2
        t = Transform()
        t.translate(dx, dy)
        new_paths.append(t.map(path))
    return new_paths
Esempio n. 10
0
def stack(shapes, direction, margin):
    if shapes is None:
        return []
    if len(shapes) <= 1:
        return shapes
    first_bounds = shapes[0].bounds
    if direction == 'e':
        new_shapes = []
        tx = -(first_bounds.width / 2)
        for shape in shapes:
            t = Transform()
            t.translate(tx - shape.bounds.x, 0)
            new_shapes.append(t.map(shape))
            tx += shape.bounds.width + margin
        return new_shapes
    elif direction == 'w':
        new_shapes = []
        tx = first_bounds.width / 2
        for shape in shapes:
            t = Transform()
            t.translate(tx + shape.bounds.x, 0)
            new_shapes.append(t.map(shape))
            tx -= shape.bounds.width + margin
        return new_shapes
    elif direction == 'n':
        new_shapes = []
        ty = first_bounds.width / 2
        for shape in shapes:
            t = Transform()
            t.translate(0, ty + shape.bounds.y)
            new_shapes.append(t.map(shape))
            ty -= shape.bounds.height + margin
        return new_shapes
    elif direction == 's':
        new_shapes = []
        ty = -(first_bounds.height / 2)
        for shape in shapes:
            t = Transform()
            t.translate(0, ty - shape.bounds.y)
            new_shapes.append(t.map(shape))
            ty += shape.bounds.height + margin
        return new_shapes
    else:
        raise ValueError('Invalid direction "%s."' % direction)
Esempio n. 11
0
def get_svg_attributes(node, parent_attributes={}):
    if parent_attributes:
        attributes = dict(parent_attributes)
    else:
        attributes = dict()

    transform = parse_transform(node)
    if transform and not transform.equals(Transform()):
        if attributes.has_key("transform"):
            t = Transform(attributes["transform"])
            t.append(transform)
            attributes["transform"] = t
        else:
            attributes["transform"] = transform

    color_attrs = parse_color_info(node)
    attributes.update(color_attrs)

    return attributes
Esempio n. 12
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
Esempio n. 13
0
 def rotate(s):
     a = to_number_array(s)
     r = a[0]
     tx = 0
     ty = 0
     if len(a) > 1:
         tx = a[1]
     if len(a) > 2:
         ty = a[2]
     t = Transform()
     t.translate(tx, ty)
     t.rotate(r)
     t.translate(-tx, -ty)
     return t
Esempio n. 14
0
def import_svg(file_name, centered=False, position=Point.ZERO):
    """Import geometry from a SVG file."""
    # We defer loading the SVG library until we need it.
    # This makes creating a node faster.
    import svg
    if not file_name: return None
    f = file(file_name, 'r')
    s = f.read()
    f.close()
    g = Geometry()
    paths = svg.parse(s, True)
    for path in paths:
        g.add(path)
    t = Transform()
    if centered:
        x, y, w, h = list(g.bounds)
        t.translate(-x - w / 2, -y - h / 2)
    t.translate(position)
    g = t.map(g)
    return g
Esempio n. 15
0
def add_transform_matrix(e, path):
    """ Transform the path according to a defined matrix.
    
    Attempts to extract a transform="matrix()" attribute.
    Transforms the path according to this matrix.
    
    """

    matrix = get_attribute(e, "transform", default="")
    if matrix.startswith("matrix("):

        matrix = matrix.replace("matrix(", "").rstrip(")")
        matrix = matrix.split(",")
        matrix = [float(v) for v in matrix]

        from nodebox.graphics import Transform
        t = Transform()
        t._set_matrix(matrix)
        path = t.transformBezierPath(path)

    return path
Esempio n. 16
0
def shape_on_path(shapes, path, amount, alignment, spacing, margin,
                  baseline_offset):
    if not shapes: return []
    if path is None: return []

    if alignment == "trailing":
        shapes = list(shapes)
        shapes.reverse()

    length = path.length - margin
    m = margin / path.length
    c = 0

    new_shapes = []
    for i in xrange(amount):
        for shape in shapes:
            if alignment == "distributed":
                p = length / ((amount * len(shapes)) - 1)
                pos = c * p / length
                pos = m + (pos * (1 - 2 * m))
            else:
                pos = ((c * spacing) % length) / length
                pos = m + (pos * (1 - m))

                if alignment == "trailing":
                    pos = 1 - pos

            p1 = path.pointAt(pos)
            p2 = path.pointAt(pos + 0.0000001)
            a = angle(p1.x, p1.y, p2.x, p2.y)
            if baseline_offset:
                coords = coordinates(p1.x, p1.y, baseline_offset, a - 90)
                p1 = Point(*coords)
            t = Transform()
            t.translate(p1)
            t.rotate(a)
            new_shapes.append(t.map(shape))
            c += 1

    return new_shapes
Esempio n. 17
0
def translateY(shape, y):
    t = Transform()
    t.translate(0, y)
    return t.map(shape)
Esempio n. 18
0
def translateX(shape, x):
    t = Transform()
    t.translate(x, 0)
    return t.map(shape)
Esempio n. 19
0
def filter(shape):
    """Serve as a template for future functions that filter geometry"""
    if shape is None: return None
    t = Transform()
    t.rotate(45)
    return t.map(shape)
Esempio n. 20
0
def parse_transform(e):
    """ Attempts to extract a transform="matrix()|translate()|scale()|rotate()" attribute.
    """

    from nodebox.graphics import Transform

    def translate(s):
        a = to_number_array(s)
        tx = a[0]
        ty = 0
        if len(a) > 1:
            ty = a[1]
        return Transform.translated(tx, ty)

    def scale(s):
        a = to_number_array(s)
        sx = a[0]
        sy = sx
        if len(a) > 1:
            sy = a[1]
        return Transform.scaled(sx, sy)

    def rotate(s):
        a = to_number_array(s)
        r = a[0]
        tx = 0
        ty = 0
        if len(a) > 1:
            tx = a[1]
        if len(a) > 2:
            ty = a[2]
        t = Transform()
        t.translate(tx, ty)
        t.rotate(r)
        t.translate(-tx, -ty)
        return t

    def matrix(s):
        m = to_number_array(s)
        return Transform(*m)

    types = {
        "translate": translate,
        "scale": scale,
        "rotate": rotate,
        "matrix": matrix
    }

    transforms = []
    t = get_attribute(e, "transform", default="")
    a = get_attribute(e, "id", None)
    if t:
        v = compress_spaces(t).lstrip().rstrip()
        v = re.split("\s(?=[a-z])", v)
        for el in v:
            type = el.split("(")[0].lstrip().rstrip()
            s = el.split("(")[1].replace(")", "")
            transform = types[type](s)
            transforms.append(transform)

    transform = Transform()
    if transforms:
        for t in transforms:
            transform.append(t)

    return transform
Esempio n. 21
0
 def matrix(s):
     m = to_number_array(s)
     return Transform(*m)
Esempio n. 22
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