예제 #1
0
 def rotate(self, o):
     """
     Realization of <Node.rotate(..)>
     """
     # check if we need to perform rotation
     cos = self.edges[1][2]
     convex = self.edges[1][3]
     if convex and abs(cos) < zero2:
         return
     
     angle = acos(cos)
     
     bm = getBmesh(o)
     bmesh.ops.rotate(
         bm,
         cent = zeroVector,
         matrix = mathutils.Matrix.Rotation(
             angle-math.pi/2. if convex else 1.5*math.pi-angle,
             3,
             self.n
         ),
         verts = getVertsForVertexGroup(o, bm, o.vertex_groups[ self._edges[1][1] ].name)
     )
     setBmesh(o, bm)
     
     return angle
예제 #2
0
 def getEdges(self, o, groupIndices):
     """
     Get vectors that define node edges for the Blender object <o>
     
     Args:
         o: Blender object acting as a node
         groupIndices (list): A list of vertex group indices, each vertex group is assigned to vertices
         forming an open end of the node edge
     """
     edges = []
     bm = getBmesh(o)
     layer = bm.verts.layers.deform[0]
     # Iterate through vertices
     for v in bm.verts:
         edge = None
         for i in groupIndices:
             if i in v[layer]:
                 # now find the vertex that doesn't have the group with the index <i>
                 loop = v.link_loops[0]
                 _v = (loop.link_loop_prev if i in loop.link_loop_next.vert[layer] else loop.link_loop_next).vert
                 edge = (v.co - _v.co).normalized()
                 # store also the group index
                 edges.append([ edge, i ])
                 # we found the vertex belonging to the group with the index <i>,
                 # we don't need to continue iteration through groupIndices
                 break
         if edge:
             # we'll skip the other vertices belonging to the group with the index <i>
             groupIndices.remove(i)
         if not groupIndices:
             # nothing is left to search for
             break
     bm.free()
     return edges
예제 #3
0
 def create(self, o):
     context = self.context
     
     obj = createMeshObject(self.name)
     #obj.hide_select = True
     context.scene.prk.areaName = obj.name
     obj["t"] = self.type
     group = o["g"]
     # remember the group for the first vertex
     obj["last"] = group
     bm = getBmesh(obj)
     # create a deform layer to store vertex groups
     layer = bm.verts.layers.deform.new()
     vert = bm.verts.new(self.getLocation(o))
     
     assignGroupToVerts(obj, layer, group, vert)
     bm.to_mesh(obj.data)
     bm.free()
     
     # without scene.update() hook modifiers will not work correctly
     context.scene.update()
     # perform parenting
     self.parent_set(o.parent, obj)
     # one more update
     context.scene.update()
     
     addHookModifier(obj, group, o, group)
예제 #4
0
 def assignUv(self, uvMap=None):
     if not uvMap:
         uvMap = defaultUvMap
     o = self.obj
     # create a new UV map if necessary
     if not uvMap in o:
         o.data.uv_textures.new(uvMap)
     
     bm = getBmesh(o)
     # the inital loop
     _loop = self.getInitialLoop(bm)
     # find the open end if the finish sequence isn't a closed sequence
     loop = _loop
     vert = loop.vert
     while True:
         if len(vert.link_loops) == 1:
             # found the open end
             _loop = loop
             break
         loop = (vert.link_loops[1] if vert.link_loops[0] == loop else vert.link_loops[0]).link_loop_prev
         vert = loop.vert
         if loop == _loop:
             break
     
     # finally, assign UV coordinates
     layer = bm.loops.layers.uv[uvMap]
     # the layer for vertex groups
     groupLayer = bm.verts.layers.deform[0]
     h = getLevelHeight(self.context, o)
     offsetU = 0.
     loop = _loop
     vert = loop.vert
     e1 = getControlEmptyFromLoop(loop, groupLayer, o)
     while True:
         # remember the base loop
         _vert = vert
         # remember, we are dealing with rectangles
         # left bottom
         loop[layer].uv = (offsetU, 0.)
         # left top
         loop.link_loop_prev[layer].uv = (offsetU, h)
         # right bottom
         loop = loop.link_loop_next
         e2 = getControlEmptyFromLoop(loop, groupLayer, o)
         offsetU += (e2.location - e1.location).length
         loop[layer].uv = (offsetU, 0.)
         # right top
         loop.link_loop_next[layer].uv = (offsetU, h)
         
         # the step below isn't necessary, we already came to the required loop
         #loop = loop.link_loop_next
         vert = loop.vert
         if len(vert.link_loops) == 1:
             # reached the opposite end (end if the finish sequence isn't a closed sequence)
             break
         loop = vert.link_loops[1] if vert.link_loops[0] == loop else vert.link_loops[0]
         if loop == _loop:
             break
         e1 = e2
     setBmesh(o, bm)
예제 #5
0
    def create(self, controls, parent, profile):
        context = self.context

        profile, closed, clockwise = self.getProfileData(profile)

        obj = createMeshObject("extruded")
        obj["t"] = "extruded"

        bm = getBmesh(obj)
        # vertex groups are in the deform layer, create one before any operation with bmesh:
        layer = bm.verts.layers.deform.new()

        numVerts = len(profile)
        numControls = len(controls)
        for i in range(numControls):
            c = controls[i]
            corner = Corner(c.location,
                            pVert=controls[i - 1].location,
                            nVert=controls[(i + 1) % numControls].location)
            group = c["g"]
            for p in profile:
                v = bm.verts.new(corner.inset(p[0], p[1]))
                assignGroupToVerts(obj, layer, group, v)

        # create faces
        bm.verts.ensure_lookup_table()
        for i in range(numControls):
            offset1 = (i - 1) * numVerts
            offset2 = offset1 + numVerts
            v1_1 = bm.verts[offset1]
            v2_1 = bm.verts[offset2]
            for p in range(1, numVerts):
                v1_2 = bm.verts[offset1 + p]
                v2_2 = bm.verts[offset2 + p]
                bm.faces.new((v2_2, v1_2, v1_1,
                              v2_1) if clockwise else (v2_2, v2_1, v1_1, v1_2))
                v1_1 = v1_2
                v2_1 = v2_2
            if closed:
                v1_2 = bm.verts[offset1]
                v2_2 = bm.verts[offset2]
                bm.faces.new((v2_2, v1_2, v1_1,
                              v2_1) if clockwise else (v2_2, v2_1, v1_1, v1_2))

        bm.to_mesh(obj.data)
        bm.free()

        # without scene.update() hook modifiers will not work correctly
        context.scene.update()
        # perform parenting
        parent_set(parent, obj)
        # one more update
        context.scene.update()

        # add hook modifiers
        for c in controls:
            group = c["g"]
            addHookModifier(obj, group, c, group)
예제 #6
0
 def slice(obj, terrain, app):
     sliceSize = app.sliceSize
     bm = getBmesh(obj)
     
     def _slice(index, plane_no, terrainMin, terrainMax):
         # min and max value along the axis defined by <index>
         # 1) terrain
         # a simple conversion from the world coordinate system to the local one
         terrainMin = terrainMin - obj.location[index]
         terrainMax = terrainMax - obj.location[index]
         # 2) <bm>, i.e. Blender mesh
         minValue = min(obj.bound_box, key = lambda v: v[index])[index]
         maxValue = max(obj.bound_box, key = lambda v: v[index])[index]
         
         # cut everything off outside the terrain bounding box
         if minValue < terrainMin:
             minValue = terrainMin
             bmesh.ops.bisect_plane(
                 bm,
                 geom=bm.verts[:]+bm.edges[:]+bm.faces[:],
                 plane_co=(0., minValue, 0.) if index else (minValue, 0., 0.),
                 plane_no=plane_no,
                 clear_inner=True
             )
         
         if maxValue > terrainMax:
             maxValue = terrainMax
             bmesh.ops.bisect_plane(
                 bm,
                 geom=bm.verts[:]+bm.edges[:]+bm.faces[:],
                 plane_co=(0., maxValue, 0.) if index else (maxValue, 0., 0.),
                 plane_no=plane_no,
                 clear_outer=True
             )
         
         # now cut the slices
         width = maxValue - minValue
         if width > sliceSize:
             numSlices = math.ceil(width/sliceSize)
             _sliceSize = width/numSlices
             coord = minValue
             sliceIndex = 1
             while sliceIndex < numSlices:
                 coord += _sliceSize
                 bmesh.ops.bisect_plane(
                     bm,
                     geom=bm.verts[:]+bm.edges[:]+bm.faces[:],
                     plane_co=(0., coord, 0.) if index else (coord, 0., 0.),
                     plane_no=plane_no
                 )
                 sliceIndex += 1
     
     _slice(0, (1., 0., 0.), terrain.minX, terrain.maxX)
     _slice(1, (0., 1., 0.), terrain.minY, terrain.maxY)
     setBmesh(obj, bm)
예제 #7
0
 def createFromArea(self, area):
     context = self.context
     controls = area.getControls()
     
     obj = createMeshObject(area.obj.name+"_finish")
     obj["t"] = self.type
     self.obj = obj
     
     bm = getBmesh(obj)
     # vertex groups are in the deform layer, create one before any operation with bmesh:
     layer = bm.verts.layers.deform.new()
     
     # a vector along z-axis with the length equal to the wall height
     height = getLevelHeight(context, area.obj)*zAxis
     numControls = len(controls)
     for c in controls:
         group = c["g"]
         # the vert at the bottom
         v_b = bm.verts.new(c.location)
         # the vert at the top
         v_t = bm.verts.new(c.location+height)
         assignGroupToVerts(obj, layer, group, v_b, v_t)
         # assign vertex group for the top vertex
         assignGroupToVerts(obj, layer, "t", v_t)
     
     # create faces
     bm.verts.ensure_lookup_table()
     v1_b = bm.verts[-2]
     v1_t = bm.verts[-1]
     for i in range(numControls):
         # <2> is the number of vertices (of the just created wall surface) per control point
         v2_b = bm.verts[i*2]
         v2_t = bm.verts[i*2+1]
         bm.faces.new((v1_b, v1_t, v2_t, v2_b))
         v1_b = v2_b
         v1_t = v2_t
     setBmesh(obj, bm)
     
     # without scene.update() hook modifiers will not work correctly
     context.scene.update()
     # perform parenting
     parent_set(area.obj.parent, obj)
     # one more update
     context.scene.update()
     
     # add HOOK modifiers
     for c in controls:
         group = c["g"]
         addHookModifier(obj, group, c, group)
     # add a HOOK modifier controlling the top vertices
     addHookModifier(obj, "t", getNextLevelParent(context, obj), "t")
     # add a SOLIDIFY modifier
     addSolidifyModifier(obj, "solidify", thickness=0.001, offset=1.)
     self.treatInsertions(controls)
예제 #8
0
    def createFromArea(self, area):
        context = self.context
        controls = area.getControls()

        obj = createMeshObject(area.obj.name + "_finish")
        obj["t"] = self.type
        self.obj = obj

        bm = getBmesh(obj)
        # vertex groups are in the deform layer, create one before any operation with bmesh:
        layer = bm.verts.layers.deform.new()

        # a vector along z-axis with the length equal to the wall height
        height = getLevelHeight(context, area.obj) * zAxis
        numControls = len(controls)
        for c in controls:
            group = c["g"]
            # the vert at the bottom
            v_b = bm.verts.new(c.location)
            # the vert at the top
            v_t = bm.verts.new(c.location + height)
            assignGroupToVerts(obj, layer, group, v_b, v_t)
            # assign vertex group for the top vertex
            assignGroupToVerts(obj, layer, "t", v_t)

        # create faces
        bm.verts.ensure_lookup_table()
        v1_b = bm.verts[-2]
        v1_t = bm.verts[-1]
        for i in range(numControls):
            # <2> is the number of vertices (of the just created wall surface) per control point
            v2_b = bm.verts[i * 2]
            v2_t = bm.verts[i * 2 + 1]
            bm.faces.new((v1_b, v1_t, v2_t, v2_b))
            v1_b = v2_b
            v1_t = v2_t
        setBmesh(obj, bm)

        # without scene.update() hook modifiers will not work correctly
        context.scene.update()
        # perform parenting
        parent_set(area.obj.parent, obj)
        # one more update
        context.scene.update()

        # add HOOK modifiers
        for c in controls:
            group = c["g"]
            addHookModifier(obj, group, c, group)
        # add a HOOK modifier controlling the top vertices
        addHookModifier(obj, "t", getNextLevelParent(context, obj), "t")
        # add a SOLIDIFY modifier
        addSolidifyModifier(obj, "solidify", thickness=0.001, offset=1.)
        self.treatInsertions(controls)
예제 #9
0
 def create(self, controls, parent, profile):
     context = self.context
     
     profile, closed, clockwise = self.getProfileData(profile)
     
     obj = createMeshObject("extruded")
     obj["t"] = "extruded"
     
     bm = getBmesh(obj)
     # vertex groups are in the deform layer, create one before any operation with bmesh:
     layer = bm.verts.layers.deform.new()
     
     numVerts = len(profile)
     numControls = len(controls)
     for i in range(numControls):
         c = controls[i]
         corner = Corner(c.location, pVert = controls[i-1].location, nVert = controls[(i+1)%numControls].location)
         group = c["g"]
         for p in profile:
             v = bm.verts.new(corner.inset(p[0], p[1]))
             assignGroupToVerts(obj, layer, group, v)
     
     # create faces
     bm.verts.ensure_lookup_table()
     for i in range(numControls):
         offset1 = (i-1)*numVerts
         offset2 = offset1+numVerts
         v1_1 = bm.verts[offset1]
         v2_1 = bm.verts[offset2]
         for p in range(1, numVerts):
             v1_2 = bm.verts[offset1+p]
             v2_2 = bm.verts[offset2+p]
             bm.faces.new((v2_2, v1_2, v1_1, v2_1) if clockwise else (v2_2, v2_1, v1_1, v1_2))
             v1_1 = v1_2
             v2_1 = v2_2
         if closed:
             v1_2 = bm.verts[offset1]
             v2_2 = bm.verts[offset2]
             bm.faces.new((v2_2, v1_2, v1_1, v2_1) if clockwise else (v2_2, v2_1, v1_1, v1_2))
     
     bm.to_mesh(obj.data)
     bm.free()
     
     # without scene.update() hook modifiers will not work correctly
     context.scene.update()
     # perform parenting
     parent_set(parent, obj)
     # one more update
     context.scene.update()
     
     # add hook modifiers
     for c in controls:
         group = c["g"]
         addHookModifier(obj, group, c, group)
예제 #10
0
 def finish(self):
     obj = getAreaObject(self.context)
     bm = getBmesh(obj)
     bm.verts.ensure_lookup_table()
     face = bm.faces.new(bm.verts)
     bm.to_mesh(obj.data)
     if obj.data.polygons[0].normal[2]<-zero:
         bmesh.ops.reverse_faces(bm, faces = (face,))
         bm.to_mesh(obj.data)
     bm.free()
     # perform cleanup
     del obj["last"]
     self.context.scene.prk.areaName = ""
     return obj
예제 #11
0
    def getProfileData(self, profile):
        coords = []

        bm = getBmesh(profile)
        bm.verts.ensure_lookup_table()

        # is profile a closed loop?
        closed = True if len(bm.verts) == len(bm.edges) else False
        start = bm.verts[0]
        # keep the edge visited in the previous pass of the cycle in the following variable
        e = start.link_edges[0]
        if not closed:
            # find an either open end of the profile
            while len(start.link_edges) != 1:
                e = start.link_edges[0] if start.link_edges[
                    1] == e else start.link_edges[1]
                start = e.verts[0] if e.verts[1] == start else e.verts[1]

        vert = start
        # keep the edge visited in the previous pass of the cycle in the following variable
        e = vert.link_edges[0]
        while True:
            p = vert.co
            coords.append((p.x, p.z))
            if not closed and len(vert.link_edges) == 1 and vert != start:
                break
            vert = e.verts[0] if e.verts[1] == vert else e.verts[1]
            if closed and vert == start:
                break
            e = vert.link_edges[-1] if vert.link_edges[
                0] == e else vert.link_edges[0]

        bm.free()

        # Now determine if the coords are in the clockwise or counterclockwise order.
        # See http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
        # The method is based on the shoelace formula
        _sum = 0.
        # store the coordinates of the previous point in the following variable
        _c = None
        for c in coords:
            if not _c:
                _c = coords[-1]
            _sum += (c[0] - _c[0]) * (c[1] + _c[1])
            _c = c
        clockwise = True if _sum > 0 else False

        return coords, closed, clockwise
예제 #12
0
 def getProfileData(self, profile):
     coords = []
     
     bm = getBmesh(profile)
     bm.verts.ensure_lookup_table()
     
     # is profile a closed loop?
     closed = True if len(bm.verts)==len(bm.edges) else False
     start = bm.verts[0]
     # keep the edge visited in the previous pass of the cycle in the following variable
     e = start.link_edges[0]
     if not closed:
         # find an either open end of the profile
         while len(start.link_edges)!=1:
             e = start.link_edges[0] if start.link_edges[1] == e else start.link_edges[1]
             start = e.verts[0] if e.verts[1]==start else e.verts[1]
             
     vert = start
     # keep the edge visited in the previous pass of the cycle in the following variable
     e = vert.link_edges[0]
     while True:
         p = vert.co
         coords.append((p.x, p.z))
         if not closed and len(vert.link_edges) == 1 and vert != start:
             break
         vert = e.verts[0] if e.verts[1]==vert else e.verts[1]
         if closed and vert == start:
             break
         e = vert.link_edges[-1] if vert.link_edges[0] == e else vert.link_edges[0]
     
     bm.free()
     
     # Now determine if the coords are in the clockwise or counterclockwise order.
     # See http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
     # The method is based on the shoelace formula
     _sum = 0.
     # store the coordinates of the previous point in the following variable
     _c = None
     for c in coords:
         if not _c:
             _c = coords[-1]
         _sum += (c[0]-_c[0])*(c[1]+_c[1])
         _c = c
     clockwise = True if _sum>0 else False
     
     return coords, closed, clockwise
예제 #13
0
 def assignUv(self, uvMap=None):
     if not uvMap:
         uvMap = defaultUvMap
     o = self.obj
     # create a new UV map if necessary
     if not uvMap in o:
         o.data.uv_textures.new(uvMap)
     
     bm = getBmesh(self.obj)
     bm.verts.ensure_lookup_table()
     layer = bm.loops.layers.uv[uvMap]
     
     # the initial loop
     origin = bm.verts[0]
     start = origin.link_loops[0]
     # vector along the x-Axis of the area coordinate system
     firstLoopVector = start.link_loop_next.vert.co - origin.co
     firstLoopVector.normalize()
     
     # Calculate the transformation matrix from the level coordinate system to the area coordinate system,
     # where the x-axis is oriented along the first loop of <bm>,
     # y-axis lies in the plane of the area,
     # z-axis is parallel to the z-axis of the level coordinate system
     # translationMatrix is inversed translation matrix from the origin of the global coordinate system to the shape origin
     translationMatrix = mathutils.Matrix.Translation(-origin.co)
     # now calculate the inversed rotation matrix
     # create a rotation matrix instance with default values (i.e. a unit matrix)
     rotationMatrix = mathutils.Matrix()
     # cosine and sine of the angle between <xAxis> and <firstLoopVector>
     cos = firstLoopVector[0]
     sin = firstLoopVector[1]
     # rotation matrix from <firstLoopVector> to <xAxis> with -<zAxis> as the rotation axis
     rotationMatrix[0][0:2] = cos, sin
     rotationMatrix[1][0:2] = -sin, cos
     # remember inversed(TRS) = inversed(S)*inversed(R)*inversed(T), so in our case:
     matrix = rotationMatrix*translationMatrix
     
     loop = start
     while True:
         loop[layer].uv = (matrix*loop.vert.co)[:2]
         loop = loop.link_loop_next
         if loop == start:
             break
     setBmesh(o, bm)
예제 #14
0
 def getControls(self):
     """
     Returns an ordered list of EMPTYs controlling the vertices of the area
     """
     bm = getBmesh(self.obj)
     bm.verts.ensure_lookup_table()
     # All vertex groups are in the deform layer.
     # There can be only one deform layer
     layer = bm.verts.layers.deform[0]
     # building a list of control EMPTYs
     controls = []
     start = bm.verts[0].link_loops[0]
     loop = start
     while True:
         controls.append( getControlEmptyFromLoop(loop, layer, self.obj) )
         loop = loop.link_loop_next
         if loop == start:
             break
     bm.free()
     return controls
예제 #15
0
 def invoke(self, context, event):
     # template Blender object
     o = context.object
     bpy.ops.object.mode_set(mode='OBJECT')
     
     # check if exactly one edge is selected
     bm = getBmesh(o)
     edge = [edge for edge in bm.edges if edge.select]
     if len(edge) != 1:
         bpy.ops.object.mode_set(mode='EDIT')
         self.report({'ERROR'}, "To assign an asset select exactly 2 vertices on the same edge")
         return {'CANCELLED'}
     bm.free()
     
     prk = context.scene.prk
     baseDir = prk.baseDirectory
     if baseDir:
         self.directory = os.path.join(baseDir, prk.item.window.assetType)
     
     context.window_manager.fileselect_add(self)
     return {'RUNNING_MODAL'}
예제 #16
0
    def invoke(self, context, event):
        # template Blender object
        o = context.object
        bpy.ops.object.mode_set(mode='OBJECT')

        # check if exactly one edge is selected
        bm = getBmesh(o)
        edge = [edge for edge in bm.edges if edge.select]
        if len(edge) != 1:
            bpy.ops.object.mode_set(mode='EDIT')
            self.report({
                'ERROR'
            }, "To assign an asset select exactly 2 vertices on the same edge")
            return {'CANCELLED'}
        bm.free()

        prk = context.scene.prk
        baseDir = prk.baseDirectory
        if baseDir:
            self.directory = os.path.join(baseDir, prk.item.window.assetType)

        context.window_manager.fileselect_add(self)
        return {'RUNNING_MODAL'}
예제 #17
0
 def makeFromEmpties(self, empties):
     context = self.context
     
     obj = createMeshObject(self.name)
     #obj.hide_select = True
     # type
     obj["t"] = self.type
     
     bm = getBmesh(obj)
     # create a deform layer to store vertex groups
     layer = bm.verts.layers.deform.new()
     
     for e in empties:
         vert = bm.verts.new(self.getLocation(e))
         assignGroupToVerts(obj, layer, e["g"], vert)
     
     # the face
     face = bm.faces.new(bm.verts)
     
     bm.to_mesh(obj.data)
     if obj.data.polygons[0].normal[2]<-zero:
         bmesh.ops.reverse_faces(bm, faces = (face,))
         bm.to_mesh(obj.data)
     bm.free()
     
     # without scene.update() hook modifiers will not work correctly
     context.scene.update()
     # perform parenting
     self.parent_set(empties[0].parent, obj)
     # one more update
     context.scene.update()
     
     # add HOOK modifiers
     for e in empties:
         group = e["g"]
         addHookModifier(obj, group, e, group)
     return obj
예제 #18
0
 def getEdges(self, o, groupIndices):
     """
     Get vectors that define node edges for the Blender object <o>
     
     Args:
         o: Blender object acting as a node
         groupIndices (list): A list of vertex group indices, each vertex group is assigned to vertices
         forming an open end of the node edge
     """
     edges = []
     bm = getBmesh(o)
     layer = bm.verts.layers.deform[0]
     # Iterate through vertices
     for v in bm.verts:
         edge = None
         for i in groupIndices:
             if i in v[layer]:
                 # now find the vertex that doesn't have the group with the index <i>
                 loop = v.link_loops[0]
                 _v = (loop.link_loop_prev
                       if i in loop.link_loop_next.vert[layer] else
                       loop.link_loop_next).vert
                 edge = (v.co - _v.co).normalized()
                 # store also the group index
                 edges.append([edge, i])
                 # we found the vertex belonging to the group with the index <i>,
                 # we don't need to continue iteration through groupIndices
                 break
         if edge:
             # we'll skip the other vertices belonging to the group with the index <i>
             groupIndices.remove(i)
         if not groupIndices:
             # nothing is left to search for
             break
     bm.free()
     return edges
예제 #19
0
    def rotate(self, o):
        """
        Realization of <Node.rotate(..)>
        """
        # check if we need to perform rotation
        cos = self.edges[1][2]
        convex = self.edges[1][3]
        if convex and abs(cos) < zero2:
            return

        angle = acos(cos)

        bm = getBmesh(o)
        bmesh.ops.rotate(
            bm,
            cent=zeroVector,
            matrix=mathutils.Matrix.Rotation(
                angle - math.pi / 2. if convex else 1.5 * math.pi - angle, 3,
                self.n),
            verts=getVertsForVertexGroup(
                o, bm, o.vertex_groups[self._edges[1][1]].name))
        setBmesh(o, bm)

        return angle
예제 #20
0
    def assignUv(self, uvMap=None):
        if not uvMap:
            uvMap = defaultUvMap
        o = self.obj
        # create a new UV map if necessary
        if not uvMap in o:
            o.data.uv_textures.new(uvMap)

        bm = getBmesh(o)
        # the inital loop
        _loop = self.getInitialLoop(bm)
        # find the open end if the finish sequence isn't a closed sequence
        loop = _loop
        vert = loop.vert
        while True:
            if len(vert.link_loops) == 1:
                # found the open end
                _loop = loop
                break
            loop = (vert.link_loops[1] if vert.link_loops[0] == loop else
                    vert.link_loops[0]).link_loop_prev
            vert = loop.vert
            if loop == _loop:
                break

        # finally, assign UV coordinates
        layer = bm.loops.layers.uv[uvMap]
        # the layer for vertex groups
        groupLayer = bm.verts.layers.deform[0]
        h = getLevelHeight(self.context, o)
        offsetU = 0.
        loop = _loop
        vert = loop.vert
        e1 = getControlEmptyFromLoop(loop, groupLayer, o)
        while True:
            # remember the base loop
            _vert = vert
            # remember, we are dealing with rectangles
            # left bottom
            loop[layer].uv = (offsetU, 0.)
            # left top
            loop.link_loop_prev[layer].uv = (offsetU, h)
            # right bottom
            loop = loop.link_loop_next
            e2 = getControlEmptyFromLoop(loop, groupLayer, o)
            offsetU += (e2.location - e1.location).length
            loop[layer].uv = (offsetU, 0.)
            # right top
            loop.link_loop_next[layer].uv = (offsetU, h)

            # the step below isn't necessary, we already came to the required loop
            #loop = loop.link_loop_next
            vert = loop.vert
            if len(vert.link_loops) == 1:
                # reached the opposite end (end if the finish sequence isn't a closed sequence)
                break
            loop = vert.link_loops[1] if vert.link_loops[
                0] == loop else vert.link_loops[0]
            if loop == _loop:
                break
            e1 = e2
        setBmesh(o, bm)
예제 #21
0
 def extend(self, empty):
     context = self.context
     
     # get Blender object for the area
     obj = getAreaObject(self.context)
     bm = getBmesh(obj)
     bm.verts.ensure_lookup_table()
     _vert = bm.verts[-1]
     
     # find the Blender object for the empty that controls the last created area vertex
     prevEmpty = obj.modifiers[obj["last"]].object
     
     # If empty and prevEmpty belong to the same wall,
     # check if we need to create in-between verts for the area,
     # i.e. empty and prevEmpty aren't adjacent
     inbetweens = []
     if empty.parent == prevEmpty.parent and empty["m"] == prevEmpty["m"]:
         wall = getWallFromEmpty(context, self.op, empty)
         if not (wall.getNext(empty) == prevEmpty or wall.getPrevious(empty) == prevEmpty):
             # find Blender empty objects for <wall>, located between empty and prevEmpty
             empties = []
             # first searching in the forward direction
             e = prevEmpty
             while True:
                 e = wall.getNext(e)
                 if e == empty or not e:
                     break
                 empties.append(e)
             
             isClosed = wall.isClosed()
             if isClosed:
                 # keep list of empties
                 _empties = empties
             
             if not e or isClosed:
                 # now try in the backward direction
                 empties = []
                 e = prevEmpty
                 while True:
                     e = wall.getPrevious(e)
                     if e == empty:
                         break
                     empties.append(e)
             # for the closed wall check whick path is shorter, in the forward or backward directions
             if isClosed and len(empties) > len(_empties): 
                 empties = _empties
             # finally, create area verts for EMTPYs
             for e in empties:
                 group = e["g"]
                 vert = bm.verts.new(self.getLocation(e))
                 assignGroupToVerts(obj, bm.verts.layers.deform[0], group, vert)
                 _vert = vert
                 inbetweens.append((e, group))
             
     group = empty["g"]
     obj["last"] = group
     vert = bm.verts.new(self.getLocation(empty))
     assignGroupToVerts(obj, bm.verts.layers.deform[0], group, vert)
     
     bm.to_mesh(obj.data)
     bm.free()
     
     # without scene.update() hook modifiers will not work correctly
     # this step is probably optional here, however it's required in AreaBegin.execute()
     context.scene.update()
     if inbetweens:
         for e,g in inbetweens:
             addHookModifier(obj, g, e, g)
     addHookModifier(obj, group, empty, group)
예제 #22
0
 def shear(self, o, angle):
     """
     Realization of <Node.shear(..)>
     """
     if angle is None or not "c" in o.vertex_groups:
         return
     
     _edges = self._edges
     
     convex = self.edges[1][3]
     bm = getBmesh(o)
     shearFactor = 1./math.tan(angle/2.)
     if convex:
         shearFactor = shearFactor - 1.
     else:
         shearFactor = -shearFactor - 1.
     
     # For the share transformation of the central part defined by the vertex group <c>
     # we may have to provide a space matrix, since the parameters of the share transformation are
     # defined under assumtions that the central part defined by the vertex group <c> is oriented
     # along the <baseBisector>. So the <space> matrix defines the rotation that orients
     # the actual bisector along the <baseBisector>
     bisector = (_edges[0][0] + _edges[1][0]).normalized()
     dot = bisector.dot(baseBisector)
     # check if <bisector> and <baseBisector> are already aligned
     if abs(1-dot) > zero2:
         _angle = acos(dot)
         if self.n.dot( bisector.cross(baseBisector) ) < 0.:
             _angle = -_angle
         spaceMatrix = mathutils.Matrix.Rotation(_angle, 4, self.n)
     else:
         spaceMatrix = mathutils.Matrix.Identity(4)
     
     bmesh.ops.transform(
         bm,
         matrix = mathutils.Matrix.Shear('XY', 4, (shearFactor, 0.)),
         verts = getVertsForVertexGroup(o, bm, "c"),
         space = spaceMatrix
     )
     # Set BMesh here to get the correct result in the next section
     # of the code related to the shape key update
     setBmesh(o, bm)
     
     # update shape key data (if available) for the vertices of the vertex group <c>
     shape_keys = o.data.shape_keys
     if shape_keys:
         if shape_keys.key_blocks.get("frame_width", None):
             bm = getBmesh(o)
             
             shapeKey = bm.verts.layers.shape.get("frame_width")
             # the bisector of the edges after the shear transformation
             bisector = mathutils.Matrix.Rotation(
                 angle/2. - math.pi/4. if convex else 0.75*math.pi - angle/2.,
                 3,
                 self.n
             ) * bisector
             # offset vector for the shape key
             offset = shapeKeyOffset / math.sin(angle/2.) * bisector
             for v in getVertsForVertexGroup(o, bm, "c"):
                 # check if the vertex changes its location for the shape key
                 if ( (v[shapeKey] - v.co).length > zero2):
                     v[shapeKey] = v.co + offset
             
             setBmesh(o, bm)
예제 #23
0
    def shear(self, o, angle):
        """
        Realization of <Node.shear(..)>
        """
        if angle is None or not "c" in o.vertex_groups:
            return

        _edges = self._edges

        convex = self.edges[1][3]
        bm = getBmesh(o)
        shearFactor = 1. / math.tan(angle / 2.)
        if convex:
            shearFactor = shearFactor - 1.
        else:
            shearFactor = -shearFactor - 1.

        # For the share transformation of the central part defined by the vertex group <c>
        # we may have to provide a space matrix, since the parameters of the share transformation are
        # defined under assumtions that the central part defined by the vertex group <c> is oriented
        # along the <baseBisector>. So the <space> matrix defines the rotation that orients
        # the actual bisector along the <baseBisector>
        bisector = (_edges[0][0] + _edges[1][0]).normalized()
        dot = bisector.dot(baseBisector)
        # check if <bisector> and <baseBisector> are already aligned
        if abs(1 - dot) > zero2:
            _angle = acos(dot)
            if self.n.dot(bisector.cross(baseBisector)) < 0.:
                _angle = -_angle
            spaceMatrix = mathutils.Matrix.Rotation(_angle, 4, self.n)
        else:
            spaceMatrix = mathutils.Matrix.Identity(4)

        bmesh.ops.transform(bm,
                            matrix=mathutils.Matrix.Shear(
                                'XY', 4, (shearFactor, 0.)),
                            verts=getVertsForVertexGroup(o, bm, "c"),
                            space=spaceMatrix)
        # Set BMesh here to get the correct result in the next section
        # of the code related to the shape key update
        setBmesh(o, bm)

        # update shape key data (if available) for the vertices of the vertex group <c>
        shape_keys = o.data.shape_keys
        if shape_keys:
            if shape_keys.key_blocks.get("frame_width", None):
                bm = getBmesh(o)

                shapeKey = bm.verts.layers.shape.get("frame_width")
                # the bisector of the edges after the shear transformation
                bisector = mathutils.Matrix.Rotation(
                    angle / 2. - math.pi / 4. if convex else 0.75 * math.pi -
                    angle / 2., 3, self.n) * bisector
                # offset vector for the shape key
                offset = shapeKeyOffset / math.sin(angle / 2.) * bisector
                for v in getVertsForVertexGroup(o, bm, "c"):
                    # check if the vertex changes its location for the shape key
                    if ((v[shapeKey] - v.co).length > zero2):
                        v[shapeKey] = v.co + offset

                setBmesh(o, bm)
예제 #24
0
    def make(self, t, **kwargs):
        verts = t.bm.verts
        context = self.context
        hooksForNodes = kwargs["hooksForNodes"]
        # template Blender object
        _o = t.o
        # Create a Blender EMPTY object to serve as a parent for the window mesh;
        # its name doesn't have <T_> prefix
        name = _o.name[2:]
        # <pt> stands for parent template
        pt = t.parentTemplate
        if pt:
            p = createEmptyObject(name,
                                  _o.location - pt.o.location,
                                  False,
                                  empty_draw_size=0.01)
        else:
            # parent for the whole hierarchy of window Blender objects
            p = t.p
        t.meshParent = p
        # start a Blender object for the template
        o = createMeshObject(name + "_mesh")
        t.meshObject = o

        context.scene.update()
        # perform parenting
        parent_set(p, o)
        if t.parentTemplate:
            parent_set(pt.meshParent, p)
        context.scene.update()
        context.scene.objects.active = o

        t.prepareOffsets()

        # iterate through the vertices of the template Blender object
        numVerts = 0
        for v in verts:
            # id of the vertex
            vid = t.getVid(v)
            if not (vid in _o and _o[vid] in bpy.data.objects):
                continue
            # Blender object for the node at the vertex
            j = bpy.data.objects[_o[vid]]
            t.setNode(v, j, o, context, hooksForNodes=hooksForNodes)
            numVerts += 1

        # final operations: bridging or extruding edges loops of the nodes, making surfaces
        bm = getBmesh(o)
        t.bridgeOrExtendNodes(o, bm, kwargs["dissolveEndEdges"])
        if numVerts == len(verts):
            t.makeSurfaces(o, bm)
        setBmesh(o, bm)

        # remove unneeded vertex group
        groups = [g for g in o.vertex_groups if g.name[0] in ("e", "s", "c")]
        for g in groups:
            o.vertex_groups.remove(g)

        # add Edge Split modifier
        if kwargs["addEdgeSplitModifier"]:
            addEdgeSplitModifier(o, o.name)

        # set maximum possible range for the shape keys
        if hooksForNodes and o.data.shape_keys:
            for kb in o.data.shape_keys.key_blocks:
                kb.slider_min = -10.
                kb.slider_max = 10.

        t.insertAssets(context)

        # hide the template Blender object and all its children
        hide(t.o, True)
예제 #25
0
 def make(self, t, **kwargs):
     verts = t.bm.verts
     context = self.context
     hooksForNodes = kwargs["hooksForNodes"]
     # template Blender object
     _o = t.o
     # Create a Blender EMPTY object to serve as a parent for the window mesh;
     # its name doesn't have <T_> prefix
     name = _o.name[2:]
     # <pt> stands for parent template
     pt = t.parentTemplate
     if pt:
         p = createEmptyObject(name, _o.location-pt.o.location, False, empty_draw_size=0.01)
     else:
         # parent for the whole hierarchy of window Blender objects
         p = t.p
     t.meshParent = p
     # start a Blender object for the template
     o = createMeshObject(name + "_mesh")
     t.meshObject = o
     
     context.scene.update()
     # perform parenting
     parent_set(p, o)
     if t.parentTemplate:
         parent_set(pt.meshParent, p)
     context.scene.update()
     context.scene.objects.active = o
     
     t.prepareOffsets()
     
     # iterate through the vertices of the template Blender object
     numVerts = 0
     for v in verts:
         # id of the vertex
         vid = t.getVid(v)
         if not (vid in _o and _o[vid] in bpy.data.objects):
             continue
         # Blender object for the node at the vertex
         j = bpy.data.objects[_o[vid]]
         t.setNode(v, j, o, context, hooksForNodes = hooksForNodes)
         numVerts += 1
     
     # final operations: bridging or extruding edges loops of the nodes, making surfaces
     bm = getBmesh(o)
     t.bridgeOrExtendNodes(o, bm, kwargs["dissolveEndEdges"])
     if numVerts == len(verts):
         t.makeSurfaces(o, bm)
     setBmesh(o, bm)
     
     # remove unneeded vertex group
     groups = [g for g in o.vertex_groups if g.name[0] in ("e", "s", "c")]
     for g in groups:
         o.vertex_groups.remove(g)
     
     # add Edge Split modifier
     if kwargs["addEdgeSplitModifier"]:
         addEdgeSplitModifier(o, o.name)
         
     # set maximum possible range for the shape keys
     if hooksForNodes and o.data.shape_keys:
         for kb in o.data.shape_keys.key_blocks:
             kb.slider_min = -10.
             kb.slider_max = 10.
     
     t.insertAssets(context)
     
     # hide the template Blender object and all its children
     hide(t.o, True)
예제 #26
0
    def createEnvelope(self):
        terrain = self.terrain
        name = "%s_envelope" % terrain.name
        if name in bpy.data.objects:
            # use existing Blender object
            envelope = bpy.data.objects[name]
            # delete modifiers
            for m in reversed(envelope.modifiers):
                envelope.modifiers.remove(m)
        else:
            # create new envelope for the terrain
            envelope = createMeshObject(name, (0., 0., self.minZ),
                                        terrain.data.copy())
            # flatten the terrain envelope
            envelope.scale[2] = 0.
            envelope.select = True
            bpy.context.scene.objects.active = envelope
            bpy.ops.object.transform_apply(location=False,
                                           rotation=False,
                                           scale=True)

            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.mesh.select_all(action='DESELECT')
            bpy.ops.mesh.select_mode(type='FACE')
            bpy.ops.object.mode_set(mode='OBJECT')
            for p in envelope.data.polygons:
                if p.normal[2] < 0.:
                    p.select = True
            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.mesh.delete(type='FACE')
            bpy.ops.mesh.select_mode(type='VERT')
            bpy.ops.mesh.select_all(action='SELECT')
            bpy.ops.mesh.remove_doubles()
            bpy.ops.mesh.region_to_loop()
            bpy.ops.mesh.select_all(action='INVERT')
            bpy.ops.mesh.dissolve_verts(use_face_split=False,
                                        use_boundary_tear=False)
            bpy.ops.mesh.select_all(action='SELECT')
            #bpy.ops.mesh.dissolve_limited(angle_limit=math.radians(0.1))
            bpy.ops.object.mode_set(mode='OBJECT')
            bm = getBmesh(envelope)
            for f in bm.faces:
                f.smooth = False
                # ensure all normals point upward
                pointNormalUpward(f)
            # inset faces to avoid weird results of the BOOLEAN modifier
            insetFaces = bmesh.ops.inset_region(bm,
                                                faces=bm.faces,
                                                use_boundary=True,
                                                use_even_offset=True,
                                                use_interpolate=True,
                                                use_relative_offset=False,
                                                use_edge_rail=False,
                                                use_outset=False,
                                                thickness=self.envelopeInset,
                                                depth=0.)['faces']
            bmesh.ops.delete(bm, geom=insetFaces, context=5)
            setBmesh(envelope, bm)

        self.envelope = envelope
        envelope.select = False
        envelope.hide_render = True
        # hide <envelope> after all Blender operator
        envelope.hide = True
        # SOLIDIFY modifier instead of BMesh extrude operator
        m = envelope.modifiers.new(name="Solidify", type='SOLIDIFY')
        m.offset = 1.
        m.thickness = self.maxZ - self.minZ + self.envelopeOffset