示例#1
0
 def __init__(self,
              axiom,
              rules,
              tropism=Vector([0, -1, 0]),
              thickness=0.6,
              bendiness=0.5,
              leaf_shape=0,
              leaf_bend=0,
              leaf_scale=0.1,
              leaf_scale_x=1,
              blossom_rate=0,
              blossom_shape=0,
              blossom_scale=0):
     """initialise L-system with specified parameters"""
     self.data = axiom
     self.rules = rules
     self.tropism = tropism
     self.thickness = thickness
     self.bendiness = bendiness
     self.leaf_shape = leaf_shape
     self.leaf_bend = leaf_bend
     self.leaf_scale = leaf_scale
     self.leaf_scale_x = leaf_scale_x
     self.blossom_rate = blossom_rate
     self.blossom_shape = blossom_shape
     self.blossom_scale = blossom_scale
示例#2
0
def system():
    """initialize and iterate the system as appropriate"""
    l_sys = LSystem(axiom=[
        LSymbol("!", {"w": 0.2}),
        LSymbol("F", {"l": 0.6}),
        LSymbol("Q", {
            "w": 0.2,
            "bw": 0.05,
            "l": 0.5,
            "bl": 0.4
        })
    ],
                    rules={
                        "Q": q_prod,
                        "A": a_prod
                    },
                    tropism=Vector([0, 0, 0]),
                    thickness=0.5,
                    bendiness=0.5,
                    leaf_shape=2,
                    leaf_scale=0.15,
                    leaf_scale_x=0.3,
                    leaf_bend=0)
    l_sys.iterate_n(15)
    return l_sys
示例#3
0
 def __init__(self,
              axiom,
              rules,
              tropism=Vector([0, -1, 0]),
              thickness=0.6,
              bendiness=0.5,
              leaf_shape=0,
              leaf_bend=0,
              leaf_scale=0.1,
              leaf_scale_x=1,
              blossom_rate=0,
              blossom_shape=0,
              blossom_scale=0):
     """initialise L-system with specified parameters"""
     self.data = axiom
     self.rules = rules
     self.tropism = tropism
     self.thickness = thickness
     self.bendiness = bendiness
     self.leaf_shape = leaf_shape
     self.leaf_bend = leaf_bend
     self.leaf_scale = leaf_scale
     self.leaf_scale_x = leaf_scale_x
     self.blossom_rate = blossom_rate
     self.blossom_shape = blossom_shape
     self.blossom_scale = blossom_scale
     self.tree_obj = bpy.data.objects.new('Tree', None)
     bpy.context.scene.objects.link(self.tree_obj)
     bpy.context.scene.objects.active = self.tree_obj
示例#4
0
def calc_point_on_bezier(offset, start_point, end_point):
    """Evaluate Bezier curve at offset between bezier_spline_points start_point and end_point"""
    if offset < 0 or offset > 1:
        raise Exception('Offset out of range: %s not between 0 and 1' % offset)
    res = (1 - offset) ** 3 * start_point.co + 3 * (1 - offset) ** 2 * offset * start_point.handle_right + 3 * (
        1 - offset) * offset ** 2 * end_point.handle_left + offset ** 3 * end_point.co
    # initialize new vector to add subclassed methods
    return Vector([res.x, res.y, res.z])
示例#5
0
    def add_points_to_bez(self, line, point1, point2, width, trunk=False):
        """add point to specific bezier spline"""
        direction = (point2 - point1)
        handle_f = 0.3

        # if exists get middle point in branch
        if len(line.bezier_points) > 1:
            start_point = line.bezier_points[-1]
            # linearly interpolate branch width between start and end of branch
            start_point.radius = line.bezier_points[
                -2].radius * 0.5 + width * 0.5
            # add bendiness to branch by rotating direction about random axis by random angle
            if self.bendiness > 0:
                acc_dir = direction.rotated(
                    Quaternion(Vector.random(),
                               radians(self.bendiness * (random() * 35 - 20))))
            else:
                acc_dir = direction
            start_point.handle_right = point1 + handle_f * acc_dir
            start_point.handle_left = point1 - handle_f * acc_dir
        else:
            # scale initial handle to match branch length
            start_point = line.bezier_points[-1]
            if trunk:
                # if trunk we also need to set the start width
                start_point.radius = width
                start_point.handle_right = start_point.co + Vector(
                    [0, 0, direction.magnitude * handle_f])
            else:
                start_point.handle_right = start_point.co + (
                    start_point.handle_right -
                    start_point.co) * direction.magnitude * handle_f
                start_point.handle_left = start_point.co + (
                    start_point.handle_left -
                    start_point.co) * direction.magnitude * handle_f

        # add new point to line and set position, direction and width
        line.bezier_points.add()
        end_point = line.bezier_points[-1]
        end_point.co = point2
        end_point.handle_right = point2 + handle_f * direction
        end_point.handle_left = point2 - handle_f * direction
        end_point.radius = width
示例#6
0
def calc_tangent_to_bezier(offset, start_point, end_point):
    """Calculate tangent to Bezier curve at offset between bezier_spline_points start_point and
    end_point"""
    if offset < 0 or offset > 1:
        raise Exception('Offset out of range: %s not between 0 and 1' % offset)
    res = 3 * (1 - offset) ** 2 * (start_point.handle_right - start_point.co) + 6 * (
        1 - offset) * offset * (end_point.handle_left - start_point.handle_right) + 3 * offset ** 2 * (
        end_point.co - end_point.handle_left)
    # initialize new vector to add subclassed methods
    return Vector([res.x, res.y, res.z])
示例#7
0
    def get_mesh(self, bend, base_shape, index):
        """produce leaf mesh at position of this leaf given base mesh as input"""

        # calculate angles to transform mesh to align with desired direction
        trf = self.direction.to_track_quat('Z', 'Y')
        right_t = self.right.rotated(trf.inverted())
        spin_ang = pi - right_t.angle(Vector([1, 0, 0]))
        spin_ang_quat = Quaternion(Vector([0, 0, 1]), spin_ang)

        # calculate bend transform if needed
        if bend > 0:
            bend_trf_1, bend_trf_2 = self.calc_bend_trf(bend)
        else:
            bend_trf_1 = bend_trf_2 = None

        vertices = []
        for vertex in base_shape[0]:
            # rotate to correct direction
            n_vertex = vertex.copy()
            n_vertex.rotate(spin_ang_quat)
            n_vertex.rotate(trf)

            # apply bend if needed
            if bend > 0:
                n_vertex.rotate(bend_trf_1)
                n_vertex.rotate(bend_trf_2)

            # move to right position
            n_vertex += self.position

            # add to vertex array
            vertices.append(n_vertex)

        # set face to refer to vertices at correct offset in big vertex list
        index *= len(vertices)

        faces = [[elem + index for elem in face] for face in base_shape[1]]

        return vertices, faces
示例#8
0
    def calc_bend_trf(self, bend):
        """calculate the transformations required to 'bend' the leaf out/up from WP"""
        normal = self.direction.cross(self.right)
        theta_pos = atan2(self.position.y, self.position.x)
        theta_bend = theta_pos - atan2(normal.y, normal.x)
        bend_trf_1 = Quaternion(Vector([0, 0, 1]), theta_bend * bend)
        self.direction.rotate(bend_trf_1)
        self.right.rotate(bend_trf_1)
        normal = self.direction.cross(self.right)
        phi_bend = normal.declination()

        if phi_bend > pi / 2:
            phi_bend = phi_bend - pi

        bend_trf_2 = Quaternion(self.right, phi_bend * bend)

        return bend_trf_1, bend_trf_2
示例#9
0
def system():
    """initialize and iterate the system as appropriate"""
    axiom = []
    con = int(__base_length__ / 0.1)
    s = random() * 0.2 + 0.9
    for ind in range(con):
        axiom.append(LSymbol("!", {"w": s * (__base_width__ + ((con - ind) / con) ** 6 * 0.2)}))
        axiom.append(LSymbol("F", {"l": s * 0.1}))
    axiom.append(LSymbol("Q", {"w": s * __base_width__, "l": s * 0.1}))
    l_sys = LSystem(axiom=axiom,
                    rules={"Q": q_prod, "A": a_prod},
                    tropism=Vector([0, 0, 0.2]),
                    thickness=0.5,
                    bendiness=0,
                    leaf_shape=3,
                    leaf_scale=0.17,
                    leaf_bend=0.2)
    l_sys.iterate_n(12)
    return l_sys
示例#10
0
def system():
    """initialize and iterate the system as appropriate"""
    l_sys = LSystem(axiom=[
        LSymbol("!", {"w": 0.2}),
        LSymbol("/", {"a": random() * 360}),
        LSymbol("Q", {"t": 0})
    ],
                    rules={
                        "Q": q_prod,
                        "A": a_prod
                    },
                    tropism=Vector([0, 0, -1]),
                    thickness=0.2,
                    bendiness=0,
                    leaf_shape=10,
                    leaf_scale=1,
                    leaf_scale_x=0.1,
                    leaf_bend=0)
    l_sys.iterate_n(100)
    return l_sys
示例#11
0
def system():
    """initialize and iterate the system as appropriate"""
    l_sys = LSystem(axiom=[
        LSymbol("!", {"w": __base_width__}),
        LSymbol("/", {"a": 45}),
        LSymbol("Q", {
            "w": __base_width__,
            "l": 0.5
        })
    ],
                    rules={
                        "Q": q_prod,
                        "A": a_prod
                    },
                    tropism=Vector([0, 0, 0]),
                    thickness=0.5,
                    bendiness=0,
                    leaf_shape=0,
                    leaf_scale=0.3,
                    leaf_bend=0.7)
    l_sys.iterate_n(15)
    return l_sys
示例#12
0
def system():
    """initialize and iterate the system as appropriate"""
    l_sys = LSystem(axiom=[
        LSymbol("!", {"w": 0.7}),
        LSymbol("F", {"l": 0.5}),
        LSymbol("/", {"a": 45}),
        LSymbol("A", {
            "w": 0.4,
            "l": 2
        })
    ],
                    rules={
                        "A": a_prod,
                        "F": f_prod
                    },
                    tropism=Vector([0, 0, -1]),
                    thickness=0.5,
                    bendiness=2,
                    leaf_shape=5,
                    leaf_scale=0.2,
                    leaf_bend=0.2)
    l_sys.iterate_n(9)
    return l_sys
示例#13
0
class LSystem(object):
    """Simple L-System class"""
    rules = {}
    data = []
    iterations = 0
    tropism = Vector([0, -1, 0])
    thickness = 0.6
    bendiness = 0.5

    leaf_shape = 0
    leaf_bend = 0
    leaf_scale = 0.1
    leaf_scale_x = 1
    blossom_rate = 0
    blossom_shape = 0
    blossom_scale = 1

    tree_object = None

    def __init__(self,
                 axiom,
                 rules,
                 tropism=Vector([0, -1, 0]),
                 thickness=0.6,
                 bendiness=0.5,
                 leaf_shape=0,
                 leaf_bend=0,
                 leaf_scale=0.1,
                 leaf_scale_x=1,
                 blossom_rate=0,
                 blossom_shape=0,
                 blossom_scale=0):
        """initialise L-system with specified parameters"""
        self.data = axiom
        self.rules = rules
        self.tropism = tropism
        self.thickness = thickness
        self.bendiness = bendiness
        self.leaf_shape = leaf_shape
        self.leaf_bend = leaf_bend
        self.leaf_scale = leaf_scale
        self.leaf_scale_x = leaf_scale_x
        self.blossom_rate = blossom_rate
        self.blossom_shape = blossom_shape
        self.blossom_scale = blossom_scale

    def __str__(self):
        """return string representation of l-system"""
        return str(self.data)

    def iterate(self):
        """perform single iteration of l-system"""
        self.iterations += 1
        output = []
        for dat in self.data:
            if dat.letter in self.rules.keys():
                rule = self.rules.get(dat.letter)
                output.extend(rule(dat))
            else:
                output.append(dat)
        self.data = output
        update_log('\r-> {} iterations performed, {} symbols generated'.format(
            self.iterations, len(self.data)))

    def iterate_n(self, num):
        """perform n iterations of l-system"""
        start = time()
        if self.iterations == 0:
            update_log('\nIterating System\n')
        if num > 0:
            self.iterate()
            self.iterate_n(num - 1)
        else:
            update_log('\nMade %i symbols in %f seconds\n' %
                       (len(self.data), time() - start))

    def parse(self, generate_leaves=True):
        """parse l-system and generate model"""

        try:
            self.tree_obj = bpy.data.objects.new('Tree', None)
        except AttributeError:
            raise Exception(
                'TreeGen :: WARNING: lsystem generation was attempted before Blender was ready'
            )

        bpy.context.scene.objects.link(self.tree_obj)
        bpy.context.scene.objects.active = self.tree_obj

        update_log('\nParsing System\n')

        start_time = time()

        # set up curve object
        curve = bpy.data.curves.new('branches', type='CURVE')
        curve.dimensions = '3D'
        curve.resolution_u = 4
        curve.fill_mode = 'FULL'
        curve.bevel_depth = self.thickness
        curve.bevel_resolution = 10
        curve.use_uv_as_generated = True
        branches_obj = bpy.data.objects.new('Branches', curve)
        bpy.context.scene.objects.link(branches_obj)
        branches_obj.parent = self.tree_obj

        # set up turtle etc.
        turtle = CHTurtle()
        # reset turtle pos/dir because blender keeps it for some reason
        turtle.dir = Vector([0, 0, 1])
        turtle.right = Vector([1, 0, 0])
        turtle.pos = Vector([0, 0, 0])
        trunk = curve.splines.new('BEZIER')
        active_branch = trunk
        active_branch.radius_interpolation = 'CARDINAL'
        active_branch.resolution_u = 2
        leaf_array = []
        stack = []  # keeps track of branches and turtle
        valid_branch = False  # keeps track of whether branch contains any F
        # at_end_of_inv_branch = False
        prev_leaf_ang = rand_in_range(0, 360)

        for ind, dat in enumerate(self.data):
            update_log('\r-> {} of {} symbols parsed'.format(
                ind + 1, len(self.data)))

            ltr = dat.letter
            if ltr == "!":
                # set width
                turtle.set_width(dat.parameters["w"])
            elif ltr == "F":
                # draw branch
                if not valid_branch:
                    valid_branch = True  # has an F so make branch valid
                old = turtle.pos.copy()
                # apply tropism force
                h_cross_t = turtle.dir.cross(self.tropism)
                alpha = h_cross_t.magnitude
                h_cross_t.normalize()
                turtle.dir.rotate(Quaternion(h_cross_t, radians(alpha)))
                # move turtle and extend spline
                turtle.move(dat.parameters["l"])
                self.add_points_to_bez(active_branch, old, turtle.pos,
                                       turtle.width, active_branch == trunk)

                if generate_leaves and "leaves" in dat.parameters and abs(
                        dat.parameters["leaves"]) > 1:
                    prev_leaf_ang = self.add_leaves_to_seg(
                        dat.parameters, active_branch, leaf_array, turtle,
                        prev_leaf_ang)

            elif ltr == "A" or ltr == "%":
                # at end of branch so taper width to 0
                if len(active_branch.bezier_points) > 0:
                    active_branch.bezier_points[-1].radius = 0
                # correct for end within invalid branch
                # at_end_of_inv_branch = not valid_branch
            elif ltr == "+":
                # turn left
                turtle.turn_left(dat.parameters["a"])
            elif ltr == "-":
                # turn right
                turtle.turn_right(dat.parameters["a"])
            elif ltr == "&":
                # pitch down
                turtle.pitch_down(dat.parameters["a"])
            elif ltr == "^":
                # pitch up
                turtle.pitch_up(dat.parameters["a"])
            elif ltr == "/":
                # roll right
                turtle.roll_right(dat.parameters["a"])
            elif ltr == "\\":
                # roll left
                turtle.roll_left(dat.parameters["a"])
            elif ltr == "L" and generate_leaves:
                # add a leaf
                leaf_turtle = CHTurtle(turtle)
                leaf_turtle.roll_left(dat.parameters["r_ang"])
                leaf_turtle.pitch_down(dat.parameters["d_ang"])
                leaf_array.append(
                    Leaf(leaf_turtle.pos, leaf_turtle.dir, leaf_turtle.right))
            elif ltr == "[":
                # start branch
                stack.append((active_branch, valid_branch, prev_leaf_ang,
                              CHTurtle(turtle)))
                valid_branch = False  # new branch not valid yet
                # set up new spline
                active_branch = curve.splines.new('BEZIER')
                active_branch.radius_interpolation = 'CARDINAL'
                active_branch.resolution_u = 4
                start_point = active_branch.bezier_points[-1]
                start_point.co = turtle.pos
                start_point.handle_left = turtle.pos - turtle.dir
                start_point.handle_right = turtle.pos + turtle.dir
                start_point.radius = turtle.width
            elif ltr == "]":
                # end branch
                # delete spline if not valid branch
                if not valid_branch:
                    curve.splines.remove(active_branch)
                # restore branch spline, validity, turtle
                if len(stack) > 0:
                    active_branch, valid_branch, prev_leaf_ang, turtle = stack.pop(
                    )
                else:
                    raise Exception(
                        "Invalid system input - unmatched end branch")
                # if at_end_of_inv_branch:
                #     if len(active_branch.bezier_points) > 0:
                #         active_branch.bezier_points[-1].radius = 0
                #     at_end_of_inv_branch = False
            elif ltr == "$":
                # set turtle to vertical
                turtle.dir = Vector([0, 0, 1])
                turtle.right = Vector([1, 0, 0])

        if active_branch != trunk:
            raise Exception("Invalid system input - missing end branch.")

        update_log('\nSystem parsed in %f seconds\n' % (time() - start_time))

        curve_points = 0
        for spline in curve.splines:
            curve_points += len(spline.bezier_points)

        # TODO do this better, could calc vertices by multiplying by bevel res and curve res?
        update_log('Curve points: %i\n' % curve_points)

        if generate_leaves:
            self.create_leaf_mesh(leaf_array)

    def add_points_to_bez(self, line, point1, point2, width, trunk=False):
        """add point to specific bezier spline"""
        direction = (point2 - point1)
        handle_f = 0.3

        # if exists get middle point in branch
        if len(line.bezier_points) > 1:
            start_point = line.bezier_points[-1]
            # linearly interpolate branch width between start and end of branch
            start_point.radius = line.bezier_points[
                -2].radius * 0.5 + width * 0.5
            # add bendiness to branch by rotating direction about random axis by random angle
            if self.bendiness > 0:
                acc_dir = direction.rotated(
                    Quaternion(Vector.random(),
                               radians(self.bendiness * (random() * 35 - 20))))
            else:
                acc_dir = direction
            start_point.handle_right = point1 + handle_f * acc_dir
            start_point.handle_left = point1 - handle_f * acc_dir
        else:
            # scale initial handle to match branch length
            start_point = line.bezier_points[-1]
            if trunk:
                # if trunk we also need to set the start width
                start_point.radius = width
                start_point.handle_right = start_point.co + Vector(
                    [0, 0, direction.magnitude * handle_f])
            else:
                start_point.handle_right = start_point.co + (
                    start_point.handle_right -
                    start_point.co) * direction.magnitude * handle_f
                start_point.handle_left = start_point.co + (
                    start_point.handle_left -
                    start_point.co) * direction.magnitude * handle_f

        # add new point to line and set position, direction and width
        line.bezier_points.add()
        end_point = line.bezier_points[-1]
        end_point.co = point2
        end_point.handle_right = point2 + handle_f * direction
        end_point.handle_left = point2 - handle_f * direction
        end_point.radius = width

    def add_leaves_to_seg(self, params, spline, leaf_array, base_turtle,
                          prev_leaf_ang):
        """add leaves to branch segment 'F'"""
        n_leaves = abs(params["leaves"])
        for ind in range(n_leaves):
            offset = ind / (n_leaves - 1)
            leaf_dir_turtle = CHTurtle()
            leaf_dir_turtle.pos = calc_point_on_bezier(
                offset, spline.bezier_points[-2], spline.bezier_points[-1])
            leaf_dir_turtle.dir = calc_tangent_to_bezier(
                offset, spline.bezier_points[-2],
                spline.bezier_points[-1]).normalized()
            if leaf_dir_turtle.dir.magnitude > 0:
                leaf_dir_turtle.right = leaf_dir_turtle.dir.cross(
                    base_turtle.dir.cross(base_turtle.right)).normalized()
                prev_leaf_ang += params["leaf_r_ang"] * rand_in_range(0.9, 1.1)
                leaf_dir_turtle.roll_left(prev_leaf_ang)

                rad = calc_radius_on_bezier(offset, spline.bezier_points[-2],
                                            spline.bezier_points[-1])
                leaf_pos_turtle = CHTurtle(leaf_dir_turtle)
                leaf_pos_turtle.pitch_down(90)
                leaf_pos_turtle.move(rad * self.thickness)

                leaf_dir_turtle.pitch_down(params["leaf_d_ang"] *
                                           rand_in_range(0.9, 1.1))
                leaf_array.append(
                    Leaf(leaf_pos_turtle.pos, leaf_dir_turtle.dir,
                         leaf_dir_turtle.right))
        return prev_leaf_ang

    def create_leaf_mesh(self, leaves_array):
        """Create leaf mesh for tree"""

        if len(leaves_array) <= 0:
            return

        update_log('\nMaking Leaves\n')

        # Start loading spinner
        windman.progress_begin(0, len(leaves_array))

        start_time = time()

        # go through global leaf array populated in branch making phase and add polygons to mesh
        base_leaf_shape = Leaf.get_shape(self.leaf_shape, 1, self.leaf_scale,
                                         self.leaf_scale_x)
        base_blossom_shape = Leaf.get_shape(self.blossom_shape, 1,
                                            self.blossom_scale, 1)
        leaf_verts = []
        leaf_faces = []
        leaf_count = 0
        blossom_verts = []
        blossom_faces = []
        blossom_count = 0

        for ind, leaf in enumerate(leaves_array):
            if ind % 500 == 0:
                windman.progress_update(ind / 100)

            update_log('\r-> {} leaves made, {} blossoms made'.format(
                leaf_count, blossom_count))

            if random() < self.blossom_rate:
                self.make_leaf(leaf, base_blossom_shape, blossom_count,
                               blossom_verts, blossom_faces)
                blossom_count += 1
            else:
                self.make_leaf(leaf, base_leaf_shape, leaf_count, leaf_verts,
                               leaf_faces)
                leaf_count += 1

        # set up mesh object
        if leaf_count > 0:
            leaves = bpy.data.meshes.new('leaves')
            leaves_obj = bpy.data.objects.new('Leaves', leaves)
            bpy.context.scene.objects.link(leaves_obj)
            leaves_obj.parent = self.tree_obj
            leaves.from_pydata(leaf_verts, (), leaf_faces)
            # set up UVs for leaf polygons
            leaf_uv = base_leaf_shape[2]
            if leaf_uv:
                leaves.uv_textures.new("leavesUV")
                uv_layer = leaves.uv_layers.active.data
                for seg_dat in range(
                        int(len(leaf_faces) / len(base_leaf_shape[1]))):
                    for vert_dat, vert in enumerate(leaf_uv):
                        uv_layer[seg_dat * len(leaf_uv) + vert_dat].uv = vert
                        # leaves.validate()

        if blossom_count > 0:
            blossom = bpy.data.meshes.new('blossom')
            blossom_obj = bpy.data.objects.new('Blossom', blossom)
            bpy.context.scene.objects.link(blossom_obj)
            blossom.from_pydata(blossom_verts, (), blossom_faces)
            # blossom.validate()

        update_log('\nMade %i leaves and %i blossoms in %f seconds\n' %
                   (leaf_count, blossom_count, time() - start_time))

        windman.progress_end()

    def make_leaf(self, leaf, base_leaf_shape, index, verts_array,
                  faces_array):
        """get vertices and faces for leaf and append to appropriate arrays"""
        verts, faces = leaf.get_mesh(self.leaf_bend, base_leaf_shape, index)
        verts_array.extend(verts)
        faces_array.extend(faces)
示例#14
0
    def parse(self, generate_leaves=True):
        """parse l-system and generate model"""

        try:
            self.tree_obj = bpy.data.objects.new('Tree', None)
        except AttributeError:
            raise Exception(
                'TreeGen :: WARNING: lsystem generation was attempted before Blender was ready'
            )

        bpy.context.scene.objects.link(self.tree_obj)
        bpy.context.scene.objects.active = self.tree_obj

        update_log('\nParsing System\n')

        start_time = time()

        # set up curve object
        curve = bpy.data.curves.new('branches', type='CURVE')
        curve.dimensions = '3D'
        curve.resolution_u = 4
        curve.fill_mode = 'FULL'
        curve.bevel_depth = self.thickness
        curve.bevel_resolution = 10
        curve.use_uv_as_generated = True
        branches_obj = bpy.data.objects.new('Branches', curve)
        bpy.context.scene.objects.link(branches_obj)
        branches_obj.parent = self.tree_obj

        # set up turtle etc.
        turtle = CHTurtle()
        # reset turtle pos/dir because blender keeps it for some reason
        turtle.dir = Vector([0, 0, 1])
        turtle.right = Vector([1, 0, 0])
        turtle.pos = Vector([0, 0, 0])
        trunk = curve.splines.new('BEZIER')
        active_branch = trunk
        active_branch.radius_interpolation = 'CARDINAL'
        active_branch.resolution_u = 2
        leaf_array = []
        stack = []  # keeps track of branches and turtle
        valid_branch = False  # keeps track of whether branch contains any F
        # at_end_of_inv_branch = False
        prev_leaf_ang = rand_in_range(0, 360)

        for ind, dat in enumerate(self.data):
            update_log('\r-> {} of {} symbols parsed'.format(
                ind + 1, len(self.data)))

            ltr = dat.letter
            if ltr == "!":
                # set width
                turtle.set_width(dat.parameters["w"])
            elif ltr == "F":
                # draw branch
                if not valid_branch:
                    valid_branch = True  # has an F so make branch valid
                old = turtle.pos.copy()
                # apply tropism force
                h_cross_t = turtle.dir.cross(self.tropism)
                alpha = h_cross_t.magnitude
                h_cross_t.normalize()
                turtle.dir.rotate(Quaternion(h_cross_t, radians(alpha)))
                # move turtle and extend spline
                turtle.move(dat.parameters["l"])
                self.add_points_to_bez(active_branch, old, turtle.pos,
                                       turtle.width, active_branch == trunk)

                if generate_leaves and "leaves" in dat.parameters and abs(
                        dat.parameters["leaves"]) > 1:
                    prev_leaf_ang = self.add_leaves_to_seg(
                        dat.parameters, active_branch, leaf_array, turtle,
                        prev_leaf_ang)

            elif ltr == "A" or ltr == "%":
                # at end of branch so taper width to 0
                if len(active_branch.bezier_points) > 0:
                    active_branch.bezier_points[-1].radius = 0
                # correct for end within invalid branch
                # at_end_of_inv_branch = not valid_branch
            elif ltr == "+":
                # turn left
                turtle.turn_left(dat.parameters["a"])
            elif ltr == "-":
                # turn right
                turtle.turn_right(dat.parameters["a"])
            elif ltr == "&":
                # pitch down
                turtle.pitch_down(dat.parameters["a"])
            elif ltr == "^":
                # pitch up
                turtle.pitch_up(dat.parameters["a"])
            elif ltr == "/":
                # roll right
                turtle.roll_right(dat.parameters["a"])
            elif ltr == "\\":
                # roll left
                turtle.roll_left(dat.parameters["a"])
            elif ltr == "L" and generate_leaves:
                # add a leaf
                leaf_turtle = CHTurtle(turtle)
                leaf_turtle.roll_left(dat.parameters["r_ang"])
                leaf_turtle.pitch_down(dat.parameters["d_ang"])
                leaf_array.append(
                    Leaf(leaf_turtle.pos, leaf_turtle.dir, leaf_turtle.right))
            elif ltr == "[":
                # start branch
                stack.append((active_branch, valid_branch, prev_leaf_ang,
                              CHTurtle(turtle)))
                valid_branch = False  # new branch not valid yet
                # set up new spline
                active_branch = curve.splines.new('BEZIER')
                active_branch.radius_interpolation = 'CARDINAL'
                active_branch.resolution_u = 4
                start_point = active_branch.bezier_points[-1]
                start_point.co = turtle.pos
                start_point.handle_left = turtle.pos - turtle.dir
                start_point.handle_right = turtle.pos + turtle.dir
                start_point.radius = turtle.width
            elif ltr == "]":
                # end branch
                # delete spline if not valid branch
                if not valid_branch:
                    curve.splines.remove(active_branch)
                # restore branch spline, validity, turtle
                if len(stack) > 0:
                    active_branch, valid_branch, prev_leaf_ang, turtle = stack.pop(
                    )
                else:
                    raise Exception(
                        "Invalid system input - unmatched end branch")
                # if at_end_of_inv_branch:
                #     if len(active_branch.bezier_points) > 0:
                #         active_branch.bezier_points[-1].radius = 0
                #     at_end_of_inv_branch = False
            elif ltr == "$":
                # set turtle to vertical
                turtle.dir = Vector([0, 0, 1])
                turtle.right = Vector([1, 0, 0])

        if active_branch != trunk:
            raise Exception("Invalid system input - missing end branch.")

        update_log('\nSystem parsed in %f seconds\n' % (time() - start_time))

        curve_points = 0
        for spline in curve.splines:
            curve_points += len(spline.bezier_points)

        # TODO do this better, could calc vertices by multiplying by bevel res and curve res?
        update_log('Curve points: %i\n' % curve_points)

        if generate_leaves:
            self.create_leaf_mesh(leaf_array)
示例#15
0
def leaves(t):
    return [
        (  # 1 = ovate
            [
                Vector([0.005, 0, 0]),
                Vector([0.005, 0, 0.1]),
                Vector([0.15, 0, 0.15]),
                Vector([0.25, 0, 0.3]),
                Vector([0.2, 0, 0.6]),
                Vector([0, 0, 1]),
                Vector([-0.2, 0, 0.6]),
                Vector([-0.25, 0, 0.3]),
                Vector([-0.15, 0, 0.15]),
                Vector([-0.005, 0, 0.1]),
                Vector([-0.005, 0, 0])
            ], [[0, 1, 9, 10], [1, 2, 3, 4], [4, 5, 6], [6, 7, 8, 9],
                [4, 6, 9, 1]]),
        (  # 2 = linear
            [
                Vector([0.005, 0, 0]),
                Vector([0.005, 0, 0.1]),
                Vector([0.1, 0, 0.15]),
                Vector([0.1, 0, 0.95]),
                Vector([0, 0, 1]),
                Vector([-0.1, 0, 0.95]),
                Vector([-0.1, 0, 0.15]),
                Vector([-0.005, 0, 0.1]),
                Vector([-0.005, 0, 0])
            ], [[0, 1, 7, 8], [1, 2, 3], [3, 4, 5], [5, 6, 7], [1, 3, 5, 7]]),
        (  # 3 = cordate
            [
                Vector([0.005, 0, 0]),
                Vector([0.01, 0, 0.2]),
                Vector([0.2, 0, 0.1]),
                Vector([0.35, 0, 0.35]),
                Vector([0.25, 0, 0.6]),
                Vector([0.1, 0, 0.8]),
                Vector([0, 0, 1]),
                Vector([-0.1, 0, 0.8]),
                Vector([-0.25, 0, 0.6]),
                Vector([-0.35, 0, 0.35]),
                Vector([-0.2, 0, 0.1]),
                Vector([-0.01, 0, 0.2]),
                Vector([-0.005, 0, 0])
            ], [[0, 1, 11, 12], [1, 2, 3, 4], [11, 10, 9, 8], [11, 1, 4, 8],
                [8, 7, 6, 5, 4]]),
        (  # 4 = maple
            [
                Vector([0.005, 0, 0]),
                Vector([0.005, 0, 0.1]),
                Vector([0.25, 0, 0.07]),
                Vector([0.2, 0, 0.18]),
                Vector([0.5, 0, 0.37]),
                Vector([0.43, 0, 0.4]),
                Vector([0.45, 0, 0.58]),
                Vector([0.3, 0, 0.57]),
                Vector([0.27, 0, 0.67]),
                Vector([0.11, 0, 0.52]),
                Vector([0.2, 0, 0.82]),
                Vector([0.08, 0, 0.77]),
                Vector([0, 0, 1]),
                Vector([-0.08, 0, 0.77]),
                Vector([-0.2, 0, 0.82]),
                Vector([-0.11, 0, 0.52]),
                Vector([-0.27, 0, 0.67]),
                Vector([-0.3, 0, 0.57]),
                Vector([-0.45, 0, 0.58]),
                Vector([-0.43, 0, 0.4]),
                Vector([-0.5, 0, 0.37]),
                Vector([-0.2, 0, 0.18]),
                Vector([-0.25, 0, 0.07]),
                Vector([-0.005, 0, 0.1]),
                Vector([-0.005, 0, 0])
            ], [[0, 1, 23, 24], [1, 2, 3, 4, 5], [23, 22, 21, 20, 19],
                [1, 5, 6, 7, 8], [23, 19, 18, 17, 16], [1, 8, 9, 10, 11],
                [23, 16, 15, 14, 13], [1, 11, 12, 13, 23]]),
        (  # 5 = palmate
            [
                Vector([0.005, 0, 0]),
                Vector([0.005, 0, 0.1]),
                Vector([0.25, 0, 0.1]),
                Vector([0.5, 0, 0.3]),
                Vector([0.2, 0, 0.45]),
                Vector([0, 0, 1]),
                Vector([-0.2, 0, 0.45]),
                Vector([-0.5, 0, 0.3]),
                Vector([-0.25, 0, 0.1]),
                Vector([-0.005, 0, 0.1]),
                Vector([-0.005, 0, 0])
            ], [[0, 1, 9, 10], [1, 2, 3, 4], [1, 4, 5, 6, 9], [9, 8, 7, 6]]),
        (  # 6 = spiky oak
            [
                Vector([0.005, 0, 0]),
                Vector([0.005, 0, 0.1]),
                Vector([0.16, 0, 0.17]),
                Vector([0.11, 0, 0.2]),
                Vector([0.23, 0, 0.33]),
                Vector([0.15, 0, 0.34]),
                Vector([0.32, 0, 0.55]),
                Vector([0.16, 0, 0.5]),
                Vector([0.27, 0, 0.75]),
                Vector([0.11, 0, 0.7]),
                Vector([0.18, 0, 0.9]),
                Vector([0.07, 0, 0.86]),
                Vector([0, 0, 1]),
                Vector([-0.07, 0, 0.86]),
                Vector([-0.18, 0, 0.9]),
                Vector([-0.11, 0, 0.7]),
                Vector([-0.27, 0, 0.75]),
                Vector([-0.16, 0, 0.5]),
                Vector([-0.32, 0, 0.55]),
                Vector([-0.15, 0, 0.34]),
                Vector([-0.23, 0, 0.33]),
                Vector([-0.11, 0, 0.2]),
                Vector([-0.16, 0, 0.17]),
                Vector([-0.005, 0, 0.1]),
                Vector([-0.005, 0, 0])
            ], [[0, 1, 23, 24], [1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9],
                [9, 10, 11], [1, 3, 5, 7, 9, 11, 12, 13, 15, 17, 19, 21, 23],
                [23, 22, 21], [21, 20, 19], [19, 18, 17], [17, 16, 15],
                [15, 14, 13]]),
        (  # 7 = round oak
            [
                Vector([0.005, 0, 0]),
                Vector([0.005, 0, 0.1]),
                Vector([0.11, 0, 0.16]),
                Vector([0.11, 0, 0.2]),
                Vector([0.22, 0, 0.26]),
                Vector([0.23, 0, 0.32]),
                Vector([0.15, 0, 0.34]),
                Vector([0.25, 0, 0.45]),
                Vector([0.23, 0, 0.53]),
                Vector([0.16, 0, 0.5]),
                Vector([0.23, 0, 0.64]),
                Vector([0.2, 0, 0.72]),
                Vector([0.11, 0, 0.7]),
                Vector([0.16, 0, 0.83]),
                Vector([0.12, 0, 0.87]),
                Vector([0.06, 0, 0.85]),
                Vector([0.07, 0, 0.95]),
                Vector([0, 0, 1]),
                Vector([-0.07, 0, 0.95]),
                Vector([-0.06, 0, 0.85]),
                Vector([-0.12, 0, 0.87]),
                Vector([-0.16, 0, 0.83]),
                Vector([-0.11, 0, 0.7]),
                Vector([-0.2, 0, 0.72]),
                Vector([-0.23, 0, 0.64]),
                Vector([-0.16, 0, 0.5]),
                Vector([-0.23, 0, 0.53]),
                Vector([-0.25, 0, 0.45]),
                Vector([-0.15, 0, 0.34]),
                Vector([-0.23, 0, 0.32]),
                Vector([-0.22, 0, 0.26]),
                Vector([-0.11, 0, 0.2]),
                Vector([-0.11, 0, 0.16]),
                Vector([-0.005, 0, 0.1]),
                Vector([-0.005, 0, 0])
            ], [[0, 1, 33, 34], [1, 2, 3], [3, 4, 5, 6], [6, 7, 8, 9],
                [9, 10, 11, 12], [12, 13, 14, 15], [15, 16, 17],
                [1, 3, 6, 9, 12, 15, 17, 19, 22, 25, 28, 31, 33], [33, 32, 31],
                [31, 30, 29, 28], [28, 27, 26, 25], [25, 24, 23, 22],
                [22, 21, 20, 19], [19, 18, 17]]),
        (  # 8 = elliptic (default)
            [
                Vector([0.005, 0, 0]),
                Vector([0.005, 0, 0.1]),
                Vector([0.15, 0, 0.2]),
                Vector([0.25, 0, 0.45]),
                Vector([0.2, 0, 0.75]),
                Vector([0, 0, 1]),
                Vector([-0.2, 0, 0.75]),
                Vector([-0.25, 0, 0.45]),
                Vector([-0.15, 0, 0.2]),
                Vector([-0.005, 0, 0.1]),
                Vector([-0.005, 0, 0])
            ], [[0, 1, 9, 10], [1, 2, 3, 4], [4, 5, 6], [6, 7, 8, 9],
                [4, 6, 9, 1]]),
        (  # 9 = rectangle
            [
                Vector([-0.5, 0, 0]),
                Vector([-0.5, 0, 1]),
                Vector([0.5, 0, 1]),
                Vector([0.5, 0, 0])
            ], [[0, 1, 2, 3]], [(-0.5, 0), (-0.5, 1), (0.5, 1), (0.5, 0)]),
        (  # 10 = triangle
            [Vector([-0.5, 0, 0]),
             Vector([0, 0, 1]),
             Vector([0.5, 0, 0])], [[0, 1, 2]], [(-0.5, 0), (0, 1), (0.5, 0)])
    ][t]
示例#16
0
def blossom(t):
    return [
        (  # 1 = cherry
            [
                Vector([0, 0, 0]),
                Vector([0.33, 0.45, 0.45]),
                Vector([0.25, 0.6, 0.6]),
                Vector([0, 0.7, 0.7]),
                Vector([-0.25, 0.6, 0.6]),
                Vector([-0.33, 0.45, 0.45]),
                Vector([0.49, 0.42, 0.6]),
                Vector([0.67, 0.22, 0.7]),
                Vector([0.65, -0.05, 0.6]),
                Vector([0.53, -0.17, 0.45]),
                Vector([0.55, -0.33, 0.6]),
                Vector([0.41, -0.57, 0.7]),
                Vector([0.15, -0.63, 0.6]),
                Vector([0, -0.55, 0.45]),
                Vector([-0.15, -0.63, 0.6]),
                Vector([-0.41, -0.57, 0.7]),
                Vector([-0.55, -0.33, 0.6]),
                Vector([-0.53, -0.17, 0.45]),
                Vector([-0.65, -0.05, 0.6]),
                Vector([-0.67, 0.22, 0.7]),
                Vector([-0.49, 0.42, 0.6])
            ], [[0, 1, 2, 3], [0, 3, 4, 5], [0, 1, 6, 7], [0, 7, 8, 9],
                [0, 9, 10, 11], [0, 11, 12, 13], [0, 13, 14, 15],
                [0, 15, 16, 17], [0, 17, 18, 19], [0, 19, 20, 5]]),
        (  # 2 = orange
            [
                Vector([0, 0, 0]),
                Vector([-0.055, 0.165, 0.11]),
                Vector([-0.125, 0.56, 0.365]),
                Vector([0, 0.7, 0.45]),
                Vector([0.125, 0.56, 0.365]),
                Vector([0.055, 0.165, 0.11]),
                Vector([0.14, 0.10, 0.11]),
                Vector([0.495, 0.29, 0.365]),
                Vector([0.665, 0.215, 0.45]),
                Vector([0.57, 0.055, 0.36]),
                Vector([0.175, 0, 0.11]),
                Vector([0.14, -0.1, 0.11]),
                Vector([0.43, -0.38, 0.365]),
                Vector([0.41, -0.565, 0.45]),
                Vector([0.23, -0.53, 0.365]),
                Vector([0.05, -0.165, 0.11]),
                Vector([-0.14, -0.1, 0.11]),
                Vector([-0.43, -0.38, 0.365]),
                Vector([-0.41, -0.565, 0.45]),
                Vector([-0.23, -0.53, 0.365]),
                Vector([-0.05, -0.165, 0.11]),
                Vector([-0.14, 0.10, 0.11]),
                Vector([-0.495, 0.29, 0.365]),
                Vector([-0.665, 0.215, 0.45]),
                Vector([-0.57, 0.055, 0.36]),
                Vector([-0.175, 0, 0.11]),
                Vector([0.1, -0.1, 0.4]),
                Vector([-0.1, -0.1, 0.4]),
                Vector([-0.1, 0.1, 0.4]),
                Vector([0.1, 0.1, 0.4])
            ], [[0, 1, 2, 3], [0, 3, 4, 5], [0, 6, 7, 8], [0, 8, 9, 10],
                [0, 11, 12, 13], [0, 13, 14, 15], [0, 16, 17, 18],
                [0, 18, 19, 20], [0, 21, 22, 23], [0, 23, 24, 25], [0, 26, 27],
                [0, 27, 28], [0, 28, 29], [0, 29, 26]]),
        (  # 3 = magnolia
            [
                Vector([0, 0, 0]),
                Vector([0.19, -0.19, 0.06]),
                Vector([0.19, -0.04, 0.06]),
                Vector([0.34, -0.11, 0.35]),
                Vector([0.3, -0.3, 0.6]),
                Vector([0.11, -0.34, 0.35]),
                Vector([0.04, -0.19, 0.06]),
                Vector([0.19, 0.19, 0.06]),
                Vector([0.19, 0.04, 0.06]),
                Vector([0.34, 0.11, 0.35]),
                Vector([0.3, 0.3, 0.6]),
                Vector([0.11, 0.34, 0.35]),
                Vector([0.04, 0.19, 0.06]),
                Vector([-0.19, -0.19, 0.06]),
                Vector([-0.19, -0.04, 0.06]),
                Vector([-0.34, -0.11, 0.35]),
                Vector([-0.3, -0.3, 0.6]),
                Vector([-0.11, -0.34, 0.35]),
                Vector([-0.04, -0.19, 0.06]),
                Vector([-0.19, 0.19, 0.06]),
                Vector([-0.19, 0.04, 0.06]),
                Vector([-0.34, 0.11, 0.35]),
                Vector([-0.3, 0.3, 0.6]),
                Vector([-0.11, 0.34, 0.35]),
                Vector([-0.04, 0.19, 0.06]),
                Vector([0, -0.39, 0.065]),
                Vector([0.15, -0.23, 0.065]),
                Vector([0.23, -0.46, 0.39]),
                Vector([0, -0.62, 0.65]),
                Vector([-0.23, -0.46, 0.39]),
                Vector([-0.15, -0.23, 0.065]),
                Vector([0, 0.39, 0.065]),
                Vector([0.15, 0.23, 0.065]),
                Vector([0.23, 0.46, 0.39]),
                Vector([0, 0.62, 0.65]),
                Vector([-0.23, 0.46, 0.39]),
                Vector([-0.15, 0.23, 0.065]),
                Vector([-0.39, 0, 0.065]),
                Vector([-0.23, 0.15, 0.065]),
                Vector([-0.46, 0.23, 0.39]),
                Vector([-0.62, 0, 0.65]),
                Vector([-0.46, -0.23, 0.39]),
                Vector([-0.23, -0.15, 0.065]),
                Vector([0.39, 0, 0.065]),
                Vector([0.23, 0.15, 0.065]),
                Vector([0.46, 0.23, 0.39]),
                Vector([0.62, 0, 0.65]),
                Vector([0.46, -0.23, 0.39]),
                Vector([0.23, -0.15, 0.065])
            ], [[0, 1, 2], [1, 2, 3], [1, 3, 4], [1, 4, 5], [1, 5,
                                                             6], [1, 6, 0],
                [0, 7, 8], [7, 8, 9], [7, 9, 10], [7, 10, 11], [7, 11, 12],
                [7, 12, 0], [0, 13, 14], [13, 14, 15], [13, 15, 16],
                [13, 16, 17], [13, 17, 18], [13, 18, 0], [0, 19, 20],
                [19, 20, 21], [19, 21, 22], [19, 22, 23], [19, 23, 24],
                [19, 24, 0], [0, 25, 26], [25, 26, 27], [25, 27, 28],
                [25, 28, 29], [25, 29, 30], [25, 30, 0], [0, 31, 32],
                [31, 32, 33], [32, 33, 34], [31, 34, 35], [31, 35, 36],
                [31, 36, 0], [0, 37, 38], [37, 38, 39], [37, 39, 40],
                [37, 40, 41], [37, 41, 42], [37, 42, 0], [0, 43, 44],
                [43, 44, 45], [43, 45, 46], [43, 46, 47], [43, 47, 48],
                [43, 48, 0]])
    ][t]