Example #1
0
    def makeSurfaces(self, o, bm):
        # sverts stands for surface verts
        sverts = SurfaceVerts(o, bm, self)

        if not sverts.numVerts:
            return

        # now compose the surface out of the vertices <verts>
        while sverts.numVerts:
            v, vid = sverts.pop()
            # node wrapper for the surface vert <v>
            n = self.nodes[vid]
            # template vertex
            tv = n.v
            # ordered edges for the surface vert <v>
            edges = n.edges
            # find the pair of edges where the surface vert <v> is located
            # vector from the node origin to the location of the surface vert <v>
            vec = v.co - tv.co
            # we need the projection of <vec> onto the plane defined by edges of the template vertex <v>
            vec = projectOntoPlane(vec, n.n)
            if len(edges) == 2:
                # the simpliest case for only two edges, no need for any lookup
                l = tv.link_loops[0]
            else:
                e1, e2 = n.getNeighborEdges(vec)
                # template vertices on the ends of the edges e1 and e2
                tv1 = e1[1]
                tv2 = e2[1]
                # Get a BMLoop from tv.link_loops for which
                # BMLoops coming through tv1 and tv2 are the next and previous BMLoops
                for l in tv.link_loops:
                    if (l.link_loop_next.vert == tv1 and l.link_loop_prev.vert == tv2) or \
                        (l.link_loop_prev.vert == tv1 and l.link_loop_next.vert == tv2):
                        break
            # vertices of BMFace for the surface
            verts = [v]
            # perform a walk along BMFace containing BMLoop <l>
            # the initial loop
            loop = l
            vec2 = (l.link_loop_next.vert.co - l.vert.co).normalized()
            while True:
                l = l.link_loop_next
                if l == loop:
                    break
                vec1 = -vec2
                vec2 = (l.link_loop_next.vert.co - l.vert.co).normalized()
                v = sverts.pop(l.vert, vec1, vec2)[0]
                if v:
                    verts.append(v)
            # finally, create BMFace for the surface
            face = bm.faces.new(verts)
            # check if we need to reverse the normal to the current surface
            sl = sverts.getSurfaceLayer()
            if sl in self.o and self.o[sl] == "reversed":
                bmesh.ops.reverse_faces(bm, faces=(face, ))
Example #2
0
 def makeSurfaces(self, o, bm):
     # sverts stands for surface verts
     sverts = SurfaceVerts(o, bm, self)
     
     if not sverts.numVerts:
         return
     
     # now compose the surface out of the vertices <verts>
     while sverts.numVerts:
         v, vid = sverts.pop()
         # node wrapper for the surface vert <v>
         n = self.nodes[vid]
         # template vertex
         tv = n.v
         # ordered edges for the surface vert <v>
         edges = n.edges
         # find the pair of edges where the surface vert <v> is located
         # vector from the node origin to the location of the surface vert <v>
         vec = v.co - tv.co
         # we need the projection of <vec> onto the plane defined by edges of the template vertex <v>
         vec = projectOntoPlane(vec, n.n)
         if len(edges) == 2:
             # the simpliest case for only two edges, no need for any lookup
             l = tv.link_loops[0]
         else:
             e1, e2 = n.getNeighborEdges(vec)
             # template vertices on the ends of the edges e1 and e2
             tv1 = e1[1]
             tv2 = e2[1]
             # Get a BMLoop from tv.link_loops for which
             # BMLoops coming through tv1 and tv2 are the next and previous BMLoops
             for l in tv.link_loops:
                 if (l.link_loop_next.vert == tv1 and l.link_loop_prev.vert == tv2) or \
                     (l.link_loop_prev.vert == tv1 and l.link_loop_next.vert == tv2):
                     break
         # vertices of BMFace for the surface
         verts = [v]
         # perform a walk along BMFace containing BMLoop <l>
         # the initial loop
         loop = l
         vec2 = (l.link_loop_next.vert.co - l.vert.co).normalized()
         while True:
             l = l.link_loop_next
             if l == loop:
                 break
             vec1 = -vec2
             vec2 = (l.link_loop_next.vert.co - l.vert.co).normalized()
             v = sverts.pop(l.vert, vec1, vec2)[0]
             if v:
                 verts.append(v)
         # finally, create BMFace for the surface
         face = bm.faces.new(verts)
         # check if we need to reverse the normal to the current surface
         sl = sverts.getSurfaceLayer()
         if sl in self.o and self.o[sl] == "reversed":
             bmesh.ops.reverse_faces(bm, faces=(face,))
Example #3
0
    def pop(self, tv=None, vec1=None, vec2=None):
        # tv stands for template vertex
        # If <templateVert>, <vec1> and <vec2> are given, that means pop a surface vert for <tv>
        # located between vectors <vec1> and <vec2>
        # If <tv>, <vec1> and <vec2> aren't given, a random surface vertex and its vid are returned
        sverts = self.sverts
        # check if there is any layer in <sverts>
        if not len(sverts):
            return None, None

        if self.sl is None:
            # set the current surface layer
            self.sl = next(iter(sverts))
        sl = self.sl
        vid = self.template.getVid(tv) if tv else next(iter(sverts[sl]))
        # if the template vertex <tv> is given, it may not have a related surface vertex
        if not vid in sverts[sl]:
            return None, None
        if len(sverts[sl][vid]) == 1:
            v = sverts[sl][vid][0]
            del sverts[sl][vid]
            if not len(sverts[sl]):
                del sverts[sl]
                # remember the surface layer if a reversion of the surface normal is needed
                self._sl = self.sl
                self.sl = None
        else:
            if tv:
                # get surface verts for <vid>
                for v in sverts[sl][vid]:
                    vec = v.co - tv.co
                    # we need the projection of <vec> onto the plane defined by edges of the template vertex <v>
                    vec = projectOntoPlane(vec, self.template.nodes[vid].n)
                    if isVectorBetweenVectors(vec, vec1, vec2):
                        # Stop iteration through surface verts for <vid>,
                        # the required surface vert has been found
                        break
                sverts[sl][vid].remove(v)
            else:
                v = sverts[sl][vid].pop()
        self.numVerts -= 1
        return v, vid
Example #4
0
 def pop(self, tv=None, vec1=None, vec2=None):
     # tv stands for template vertex
     # If <templateVert>, <vec1> and <vec2> are given, that means pop a surface vert for <tv>
     # located between vectors <vec1> and <vec2>
     # If <tv>, <vec1> and <vec2> aren't given, a random surface vertex and its vid are returned
     sverts = self.sverts
     # check if there is any layer in <sverts>
     if not len(sverts):
         return None, None
     
     if self.sl is None:
         # set the current surface layer
         self.sl = next(iter(sverts))
     sl = self.sl
     vid = self.template.getVid(tv) if tv else next(iter(sverts[sl]))
     # if the template vertex <tv> is given, it may not have a related surface vertex
     if not vid in sverts[sl]:
         return None, None
     if len(sverts[sl][vid]) == 1:
         v = sverts[sl][vid][0]
         del sverts[sl][vid]
         if not len(sverts[sl]):
             del sverts[sl]
             # remember the surface layer if a reversion of the surface normal is needed
             self._sl = self.sl
             self.sl = None
     else:
         if tv:
             # get surface verts for <vid>
             for v in sverts[sl][vid]:
                 vec = v.co-tv.co
                 # we need the projection of <vec> onto the plane defined by edges of the template vertex <v>
                 vec = projectOntoPlane(vec, self.template.nodes[vid].n)
                 if isVectorBetweenVectors(vec, vec1, vec2):
                     # Stop iteration through surface verts for <vid>,
                     # the required surface vert has been found
                     break
             sverts[sl][vid].remove(v)
         else:
             v = sverts[sl][vid].pop()
     self.numVerts -= 1
     return v, vid
Example #5
0
    def insertAssets(self, context):
        o = self.o
        nodes = self.nodes
        nodeCache = self.nodeCache

        # scan the template for assets
        for a in o.children:
            if a.get("t") != "asset":
                continue
            vid1 = a["vid1"]
            vid2 = a["vid2"]

            bm = getBmesh(o)
            vert1 = getVertsForVertexGroup(o, bm, vid1)[0]
            vert2 = getVertsForVertexGroup(o, bm, vid2)[0]
            v1 = vert1.co
            v2 = vert2.co

            # get the edge connecting two vertices <v1> and <v2>
            for edge in vert1.link_edges:
                if vert2 in edge.verts:
                    break
            location = projectOntoLine(a.location - v1, (v2 - v1).normalized())
            # relative location on the edge
            location = location.length / (v2 - v1).length
            # If the <edge> is external, take into account offsets for the vertices <v1> and <v2>,
            # otherwise don't take offsets into account
            if len(edge.link_faces) == 1:
                # the only BMLoop for <edge>
                loop = edge.link_loops[0]
                # do we walk from <vert2> to <vert1> or in the opposite direction
                fromVert2 = loop.vert == vert2
                if fromVert2:
                    # temporarily swap <vert1> and <vert2>
                    vert1, vert2 = vert2, vert1
                # edge vector for the corner of the vertex <vert1>
                edgeVec1 = getVectorFromEdge(edge, vert1)
                # edge vector for corner of the <vert2> is the other external edge for <vert2>
                for edgeVec2 in vert2.link_edges:
                    if edgeVec2 != edge and len(edgeVec2.link_faces) == 1:
                        break
                edgeVec2 = getVectorFromEdge(edgeVec2, vert2)
                if fromVert2:
                    # swap the values back
                    vert1, vert2 = vert2, vert1
                    edgeVec1, edgeVec2 = edgeVec2, edgeVec1
                # adding offset to the vectors <v1> and <v2>
                v1 += self.parentTemplate.childOffsets.get(vid1, edgeVec1)
                v2 += self.parentTemplate.childOffsets.get(vid2, edgeVec2)

            location = v1 + location * (v2 - v1)

            # calculate the offset <tOffset> perpedicular to the vector <v2 - v1> (i.e. transverse offset)
            # type of the asset
            t = a.get("t2")

            def processOffset(tOffset, pVid, sVid):
                """
                A helper function to check if we have an appropriate <tOffset>
                
                Args:
                    tOffset (list): Blender EMPTY object serving as asset placeholder
                    pVid (str): Primary vid
                    sVid (str): the other vid
                
                Returns:
                    A tuple with <tOffset> (may be set to None) and transformation matrix (may be None)
                """
                # index of the open end of the node Blender object to which the asset is attached
                e = tOffset.get("e")
                ends = nodes[pVid].ends["e_" + str(e)]
                if pVid in ends and sVid in ends:
                    matrix = nodes[pVid].matrix
                else:
                    matrix = None
                    tOffset = None
                return tOffset, matrix

            # check if the asset placeholder is set for the node with <vid1>
            tOffset = nodeCache.get(o[vid1]).assets[t]
            if tOffset:
                tOffset, matrix = processOffset(tOffset, vid1, vid2)
            if not tOffset:
                # check if the asset placeholder is set for the node with <vid2>
                tOffset = nodeCache.get(o[vid2]).assets[t]
                tOffset, matrix = processOffset(tOffset, vid2, vid1)
            if tOffset:
                tOffset = matrix * tOffset.location if matrix else tOffset.location.copy(
                )
                location += projectOntoPlane(tOffset, (v2 - v1).normalized())
            bm.free()
            # parent object for the hierarchy of assets
            p = createEmptyObject("test", location, True, empty_draw_size=0.01)
            parent_set(self.meshObject.parent, p)
            # import asset
            a = appendFromFile(
                context,
                os.path.join(context.scene.prk.baseDirectory, a["path"]))
            a.location = zeroVector.copy()
            parent_set(p, a)
Example #6
0
    def prepareOffsets(self):
        """
        Calculate offsets for intermediary template vertices which don't
        have an ancestor in the parent template
        """
        p = self.parentTemplate
        if not p:
            # nothing to prepare
            return
        # iterate through the vertices of the template to find an outer vertex presented in <p.childOffsets>
        # also find a pair of outer edges connected to the outer vertex
        vert = None
        # a variable for the first edge to be found
        _e = None
        for v in self.bm.verts:
            vid = self.getVid(v)
            if vid in p.nodes:
                # check if the vertex <v> has an outer edge
                for e in v.link_edges:
                    if len(e.link_faces) == 1:
                        if _e:
                            # the second edge is simply <e>
                            break
                        else:
                            vert = v
                            # the first edge is found
                            _e = e
                if vert:
                    break
        if not vert:
            # nothing to prepare
            return

        _vec = getVectorFromEdge(_e, vert)
        vec = getVectorFromEdge(e, vert)
        # the cross product of <_e> and <p> must point in the direction of the normal to <vert>
        if _vec.cross(vec).dot(vert.normal) > 0:
            e = _e
            vec = _vec
        # the reference edges to get offset from the ChildOffset class is <e>

        # walk along outer edges starting from <vert>
        v = vert
        # the last visited edge
        _e = e
        # the unit vector along the current edge
        _n = None
        vids = []
        # the current offset
        offset = p.childOffsets.get(vid, vec)
        while True:
            # Walk along outer vertices until we encounter a vertex with vid in <p.childOffsets> OR
            # the direction of the current edge is changed significantly

            # get the next outer vertex
            for e in v.link_edges:
                if len(e.link_faces) == 1 and e != _e:
                    _v = v
                    v = e.verts[1] if e.verts[0] == v else e.verts[0]
                    break
            vid = self.getVid(v)

            hasOffset = vid in p.nodes

            # the unit vector along the edge defined by <_v> and <v>
            n = (v.co - _v.co).normalized()

            # check if the direction of the edge has been changed
            directionChanged = _n and abs(1. - _n.dot(n)) > zero2

            if hasOffset:
                # set the current offset
                offset = p.childOffsets.get(vid, getVectorFromEdge(e, v))
                _offset = None
                if directionChanged:
                    # set offset only sfor the last vid in <vids>
                    vids = [vids[-1]]
                if vids:
                    # We need the projection of <offset> vector onto the plane
                    # defined by the normal <n> to the plane
                    _offset = projectOntoPlane(offset, n)
                    # set offset for all outer vertices in <vids> list
                    for vid in vids:
                        self.childOffsets.set(vid, None, _offset)
                    vids = []
                _n = None
            else:
                if directionChanged:
                    offset = None
                    _n = None
                    vids = [vid]
                else:
                    if offset:
                        # We need the projection of <offset> vector onto the plane
                        # defined by the normal <n> to the plane
                        _offset = projectOntoPlane(offset, n)
                        self.childOffsets.set(vid, None, _offset)
                    else:
                        vids.append(vid)
                    _n = n
            # check if need to quit the cycle
            if v == vert:
                break
            _e = e
Example #7
0
 def insertAssets(self, context):
     o = self.o
     nodes = self.nodes
     nodeCache = self.nodeCache
     
     # scan the template for assets
     for a in o.children:
         if a.get("t") != "asset":
             continue
         vid1 = a["vid1"]
         vid2 = a["vid2"]
         
         bm = getBmesh(o)
         vert1 = getVertsForVertexGroup(o, bm, vid1)[0]
         vert2 = getVertsForVertexGroup(o, bm, vid2)[0]
         v1 = vert1.co
         v2 = vert2.co
         
         # get the edge connecting two vertices <v1> and <v2>
         for edge in vert1.link_edges:
             if vert2 in edge.verts:
                 break
         location = projectOntoLine(a.location-v1, (v2-v1).normalized())
         # relative location on the edge
         location = location.length / (v2 - v1).length
         # If the <edge> is external, take into account offsets for the vertices <v1> and <v2>,
         # otherwise don't take offsets into account
         if len(edge.link_faces) == 1:
             # the only BMLoop for <edge>
             loop = edge.link_loops[0]
             # do we walk from <vert2> to <vert1> or in the opposite direction
             fromVert2 = loop.vert == vert2
             if fromVert2:
                 # temporarily swap <vert1> and <vert2>
                 vert1, vert2 = vert2, vert1
             # edge vector for the corner of the vertex <vert1>
             edgeVec1 = getVectorFromEdge(edge, vert1)
             # edge vector for corner of the <vert2> is the other external edge for <vert2>
             for edgeVec2 in vert2.link_edges:
                 if edgeVec2 != edge and len(edgeVec2.link_faces) == 1:
                     break
             edgeVec2 = getVectorFromEdge(edgeVec2, vert2)
             if fromVert2:
                 # swap the values back
                 vert1, vert2 = vert2, vert1
                 edgeVec1, edgeVec2 = edgeVec2, edgeVec1
             # adding offset to the vectors <v1> and <v2>
             v1 += self.parentTemplate.childOffsets.get(vid1, edgeVec1)
             v2 += self.parentTemplate.childOffsets.get(vid2, edgeVec2)
         
         location = v1 + location * (v2 - v1)
         
         # calculate the offset <tOffset> perpedicular to the vector <v2 - v1> (i.e. transverse offset)
         # type of the asset
         t = a.get("t2")
         def processOffset(tOffset, pVid, sVid):
             """
             A helper function to check if we have an appropriate <tOffset>
             
             Args:
                 tOffset (list): Blender EMPTY object serving as asset placeholder
                 pVid (str): Primary vid
                 sVid (str): the other vid
             
             Returns:
                 A tuple with <tOffset> (may be set to None) and transformation matrix (may be None)
             """
             # index of the open end of the node Blender object to which the asset is attached
             e = tOffset.get("e")
             ends = nodes[pVid].ends["e_"+str(e)]
             if pVid in ends and sVid in ends:
                 matrix = nodes[pVid].matrix
             else:
                 matrix = None
                 tOffset = None
             return tOffset, matrix
         
         # check if the asset placeholder is set for the node with <vid1>
         tOffset = nodeCache.get(o[vid1]).assets[t]
         if tOffset:
             tOffset, matrix = processOffset(tOffset, vid1, vid2)
         if not tOffset:
             # check if the asset placeholder is set for the node with <vid2>
             tOffset = nodeCache.get(o[vid2]).assets[t]
             tOffset, matrix = processOffset(tOffset, vid2, vid1)
         if tOffset:
             tOffset = matrix*tOffset.location if matrix else tOffset.location.copy()
             location += projectOntoPlane(tOffset, (v2 - v1).normalized())
         bm.free()
         # parent object for the hierarchy of assets
         p = createEmptyObject("test", location, True, empty_draw_size=0.01)
         parent_set(self.meshObject.parent, p)
         # import asset
         a = appendFromFile(context, os.path.join(context.scene.prk.baseDirectory, a["path"]))
         a.location = zeroVector.copy()
         parent_set(p, a)
Example #8
0
 def prepareOffsets(self):
     """
     Calculate offsets for intermediary template vertices which don't
     have an ancestor in the parent template
     """
     p = self.parentTemplate
     if not p:
         # nothing to prepare
         return
     # iterate through the vertices of the template to find an outer vertex presented in <p.childOffsets>
     # also find a pair of outer edges connected to the outer vertex
     vert = None
     # a variable for the first edge to be found
     _e = None
     for v in self.bm.verts:
         vid = self.getVid(v)
         if vid in p.nodes:
             # check if the vertex <v> has an outer edge
             for e in v.link_edges:
                 if len(e.link_faces) == 1:
                     if _e:
                         # the second edge is simply <e>
                         break
                     else:
                         vert = v
                         # the first edge is found
                         _e = e
             if vert:
                 break
     if not vert:
         # nothing to prepare
         return
     
     _vec = getVectorFromEdge(_e, vert)
     vec = getVectorFromEdge(e, vert)
     # the cross product of <_e> and <p> must point in the direction of the normal to <vert>
     if _vec.cross(vec).dot(vert.normal) > 0:
         e = _e
         vec = _vec
     # the reference edges to get offset from the ChildOffset class is <e>
     
     # walk along outer edges starting from <vert>
     v = vert
     # the last visited edge
     _e = e
     # the unit vector along the current edge
     _n = None
     vids = []
     # the current offset
     offset = p.childOffsets.get(vid, vec)
     while True:
         # Walk along outer vertices until we encounter a vertex with vid in <p.childOffsets> OR
         # the direction of the current edge is changed significantly
         
         # get the next outer vertex
         for e in v.link_edges:
             if len(e.link_faces) == 1 and e != _e:
                 _v = v
                 v = e.verts[1] if e.verts[0] == v else e.verts[0]
                 break
         vid = self.getVid(v)
         
         hasOffset = vid in p.nodes
         
         # the unit vector along the edge defined by <_v> and <v>
         n = (v.co - _v.co).normalized()
         
         # check if the direction of the edge has been changed
         directionChanged = _n and abs(1.-_n.dot(n)) > zero2
         
         if hasOffset:
             # set the current offset
             offset = p.childOffsets.get(vid, getVectorFromEdge(e, v))
             _offset = None
             if directionChanged:
                 # set offset only sfor the last vid in <vids>
                 vids = [vids[-1]]
             if vids:
                 # We need the projection of <offset> vector onto the plane
                 # defined by the normal <n> to the plane
                 _offset = projectOntoPlane(offset, n)
                 # set offset for all outer vertices in <vids> list
                 for vid in vids:
                     self.childOffsets.set(vid, None, _offset)
                 vids = []
             _n = None
         else:
             if directionChanged:
                 offset = None
                 _n = None
                 vids = [vid]
             else:
                 if offset:
                     # We need the projection of <offset> vector onto the plane
                     # defined by the normal <n> to the plane
                     _offset = projectOntoPlane(offset, n)
                     self.childOffsets.set(vid, None, _offset)
                 else:
                     vids.append(vid)
                 _n = n
         # check if need to quit the cycle
         if v == vert:
             break
         _e = e