Пример #1
0
class Geometry:

    def __init__(self, name, format = GeomVertexFormat.getV3()):
        self.views = []
        self.vertexBuffer = GeomVertexData(name + "-vdata", format, GeomEnums.UHDynamic)

        self.np = NodePath(name)
        self.np.node().setBounds(OmniBoundingVolume())
        self.np.node().setFinal(1)
        # taha was here

    def generateIndices(self, firstVertex = 0, numVerts = None):
        if numVerts is None:
            numVerts = self.vertexBuffer.getNumRows()
            clear = True
        else:
            clear = False
        for view in self.views:
            view.generateIndices(firstVertex, numVerts, clear)

    def generateGeometry(self):
        self.generateVertices()
        self.generateIndices()

    def generateVertices(self):
        pass

    def cleanup(self):
        for view in self.views:
            view.cleanup()
        self.views = None
        self.np.removeNode()
        self.np = None
        self.vertexBuffer = None

    def addView(self, view):
        self.views.append(view)
        return view

    def removeView(self, view):
        if isinstance(view, int):
            viewObj = self.views[view]
        else:
            viewObj = view

        viewObj.cleanup()
        self.views.remove(viewObj)
Пример #2
0
Файл: ui.py Проект: tgbugs/desc
def makeGrid(rng = 1000, spacing = 10): #FIXME make this scale based on zoom???
    ctup = (.3,.3,.3,1)
    xs = range(-rng,rng+1,spacing)
    ys = xs

    fmt = GeomVertexFormat.getV3c4() #3 component vertex, w/ 4 comp color
    #fmt = GeomVertexFormat.getV3() #3 component vertex, w/ 4 comp color
    vertexData = GeomVertexData('points', fmt, Geom.UHStatic)

    verts = GeomVertexWriter(vertexData, 'vertex')
    color = GeomVertexWriter(vertexData, 'color')


    for i,d in enumerate(xs):
        switch1 = (-1) ** i * rng
        switch2 = (-1) ** i * -rng
        #print(d,switch1,0)
        verts.addData3f(d, switch1, 0)
        verts.addData3f(d, switch2, 0)
        color.addData4f(*ctup)
        color.addData4f(*ctup)

    for i,d in enumerate(ys):
        switch1 = (-1) ** i * rng
        switch2 = (-1) ** i * -rng
        verts.addData3f(switch1, d, 0)
        verts.addData3f(switch2, d, 0)
        color.addData4f(*ctup)
        color.addData4f(*ctup)

    gridLines = GeomLinestrips(Geom.UHStatic)
    gridLines.addConsecutiveVertices(0, vertexData.getNumRows())
    gridLines.closePrimitive()

    grid = Geom(vertexData)
    grid.addPrimitive(gridLines)
    return grid
Пример #3
0
def makeGrid(rng=1000, spacing=10):  #FIXME make this scale based on zoom???
    ctup = (.3, .3, .3, 1)
    xs = range(-rng, rng + 1, spacing)
    ys = xs

    fmt = GeomVertexFormat.getV3c4()  #3 component vertex, w/ 4 comp color
    #fmt = GeomVertexFormat.getV3() #3 component vertex, w/ 4 comp color
    vertexData = GeomVertexData('points', fmt, Geom.UHStatic)

    verts = GeomVertexWriter(vertexData, 'vertex')
    color = GeomVertexWriter(vertexData, 'color')

    for i, d in enumerate(xs):
        switch1 = (-1)**i * rng
        switch2 = (-1)**i * -rng
        #print(d,switch1,0)
        verts.addData3f(d, switch1, 0)
        verts.addData3f(d, switch2, 0)
        color.addData4f(*ctup)
        color.addData4f(*ctup)

    for i, d in enumerate(ys):
        switch1 = (-1)**i * rng
        switch2 = (-1)**i * -rng
        verts.addData3f(switch1, d, 0)
        verts.addData3f(switch2, d, 0)
        color.addData4f(*ctup)
        color.addData4f(*ctup)

    gridLines = GeomLinestrips(Geom.UHStatic)
    gridLines.addConsecutiveVertices(0, vertexData.getNumRows())
    gridLines.closePrimitive()

    grid = Geom(vertexData)
    grid.addPrimitive(gridLines)
    return grid
Пример #4
0
def getNodeFromController(controller, controlled_prim):
    if type(controlled_prim) is collada.controller.BoundSkinPrimitive:
        ch = Character('simplechar')
        bundle = ch.getBundle(0)
        skeleton = PartGroup(bundle, '<skeleton>')

        character_joints = {}
        for (name, joint_matrix) in controller.joint_matrices.iteritems():
            joint_matrix.shape = (-1)
            character_joints[name] = CharacterJoint(ch, bundle, skeleton, name,
                                                    Mat4(*joint_matrix))

        tbtable = TransformBlendTable()

        for influence in controller.index:
            blend = TransformBlend()
            for (joint_index, weight_index) in influence:
                char_joint = character_joints[controller.getJoint(joint_index)]
                weight = controller.getWeight(weight_index)[0]
                blend.addTransform(JointVertexTransform(char_joint), weight)
            tbtable.addBlend(blend)

        array = GeomVertexArrayFormat()
        array.addColumn(InternalName.make('vertex'), 3, Geom.NTFloat32,
                        Geom.CPoint)
        array.addColumn(InternalName.make('normal'), 3, Geom.NTFloat32,
                        Geom.CPoint)
        array.addColumn(InternalName.make('texcoord'), 2, Geom.NTFloat32,
                        Geom.CTexcoord)
        blendarr = GeomVertexArrayFormat()
        blendarr.addColumn(InternalName.make('transform_blend'), 1,
                           Geom.NTUint16, Geom.CIndex)

        format = GeomVertexFormat()
        format.addArray(array)
        format.addArray(blendarr)
        aspec = GeomVertexAnimationSpec()
        aspec.setPanda()
        format.setAnimation(aspec)
        format = GeomVertexFormat.registerFormat(format)

        dataname = controller.id + '-' + controlled_prim.primitive.material.id
        vdata = GeomVertexData(dataname, format, Geom.UHStatic)
        vertex = GeomVertexWriter(vdata, 'vertex')
        normal = GeomVertexWriter(vdata, 'normal')
        texcoord = GeomVertexWriter(vdata, 'texcoord')
        transform = GeomVertexWriter(vdata, 'transform_blend')

        numtris = 0
        if type(controlled_prim.primitive) is collada.polylist.BoundPolylist:
            for poly in controlled_prim.primitive.polygons():
                for tri in poly.triangles():
                    for tri_pt in range(3):
                        vertex.addData3f(tri.vertices[tri_pt][0],
                                         tri.vertices[tri_pt][1],
                                         tri.vertices[tri_pt][2])
                        normal.addData3f(tri.normals[tri_pt][0],
                                         tri.normals[tri_pt][1],
                                         tri.normals[tri_pt][2])
                        if len(controlled_prim.primitive._texcoordset) > 0:
                            texcoord.addData2f(tri.texcoords[0][tri_pt][0],
                                               tri.texcoords[0][tri_pt][1])
                        transform.addData1i(tri.indices[tri_pt])
                    numtris += 1
        elif type(controlled_prim.primitive
                  ) is collada.triangleset.BoundTriangleSet:
            for tri in controlled_prim.primitive.triangles():
                for tri_pt in range(3):
                    vertex.addData3f(tri.vertices[tri_pt][0],
                                     tri.vertices[tri_pt][1],
                                     tri.vertices[tri_pt][2])
                    normal.addData3f(tri.normals[tri_pt][0],
                                     tri.normals[tri_pt][1],
                                     tri.normals[tri_pt][2])
                    if len(controlled_prim.primitive._texcoordset) > 0:
                        texcoord.addData2f(tri.texcoords[0][tri_pt][0],
                                           tri.texcoords[0][tri_pt][1])
                    transform.addData1i(tri.indices[tri_pt])
                numtris += 1

        tbtable.setRows(SparseArray.lowerOn(vdata.getNumRows()))

        gprim = GeomTriangles(Geom.UHStatic)
        for i in range(numtris):
            gprim.addVertices(i * 3, i * 3 + 1, i * 3 + 2)
            gprim.closePrimitive()

        pgeom = Geom(vdata)
        pgeom.addPrimitive(gprim)

        render_state = getStateFromMaterial(controlled_prim.primitive.material)
        control_node = GeomNode("ctrlnode")
        control_node.addGeom(pgeom, render_state)
        ch.addChild(control_node)

        bundle = AnimBundle('simplechar', 5.0, 2)
        skeleton = AnimGroup(bundle, '<skeleton>')
        root = AnimChannelMatrixXfmTable(skeleton, 'root')

        #hjoint = AnimChannelMatrixXfmTable(root, 'joint1')
        #table = [10, 11, 12, 13, 14, 15, 14, 13, 12, 11]
        #data = PTAFloat.emptyArray(len(table))
        #for i in range(len(table)):
        #    data.setElement(i, table[i])
        #hjoint.setTable(ord('i'), CPTAFloat(data))

        #vjoint = AnimChannelMatrixXfmTable(hjoint, 'joint2')
        #table = [10, 9, 8, 7, 6, 5, 6, 7, 8, 9]
        #data = PTAFloat.emptyArray(len(table))
        #for i in range(len(table)):
        #    data.setElement(i, table[i])
        #vjoint.setTable(ord('j'), CPTAFloat(data))

        wiggle = AnimBundleNode('wiggle', bundle)

        np = NodePath(ch)
        anim = NodePath(wiggle)
        a = Actor(np, {'simplechar': anim})
        a.loop('simplechar')
        return a
        #a.setPos(0, 0, 0)

    else:
        raise Exception("Error: unsupported controller type")
Пример #5
0
def getNodeFromController(controller, controlled_prim):
    if type(controlled_prim) is collada.controller.BoundSkinPrimitive:
        ch = Character('simplechar')
        bundle = ch.getBundle(0)
        skeleton = PartGroup(bundle, '<skeleton>')

        character_joints = {}
        for (name, joint_matrix) in controller.joint_matrices.iteritems():
            joint_matrix.shape = (-1)
            character_joints[name] = CharacterJoint(ch, bundle, skeleton, name, Mat4(*joint_matrix)) 
        
        tbtable = TransformBlendTable()
        
        for influence in controller.index:
            blend = TransformBlend()
            for (joint_index, weight_index) in influence:
                char_joint = character_joints[controller.getJoint(joint_index)]
                weight = controller.getWeight(weight_index)[0]
                blend.addTransform(JointVertexTransform(char_joint), weight)
            tbtable.addBlend(blend)
            
        array = GeomVertexArrayFormat()
        array.addColumn(InternalName.make('vertex'), 3, Geom.NTFloat32, Geom.CPoint)
        array.addColumn(InternalName.make('normal'), 3, Geom.NTFloat32, Geom.CPoint)
        array.addColumn(InternalName.make('texcoord'), 2, Geom.NTFloat32, Geom.CTexcoord)
        blendarr = GeomVertexArrayFormat()
        blendarr.addColumn(InternalName.make('transform_blend'), 1, Geom.NTUint16, Geom.CIndex)
        
        format = GeomVertexFormat()
        format.addArray(array)
        format.addArray(blendarr)
        aspec = GeomVertexAnimationSpec()
        aspec.setPanda()
        format.setAnimation(aspec)
        format = GeomVertexFormat.registerFormat(format)
        
        dataname = controller.id + '-' + controlled_prim.primitive.material.id
        vdata = GeomVertexData(dataname, format, Geom.UHStatic)
        vertex = GeomVertexWriter(vdata, 'vertex')
        normal = GeomVertexWriter(vdata, 'normal')
        texcoord = GeomVertexWriter(vdata, 'texcoord')
        transform = GeomVertexWriter(vdata, 'transform_blend') 
        
        numtris = 0
        if type(controlled_prim.primitive) is collada.polylist.BoundPolylist:
            for poly in controlled_prim.primitive.polygons():
                for tri in poly.triangles():
                    for tri_pt in range(3):
                        vertex.addData3f(tri.vertices[tri_pt][0], tri.vertices[tri_pt][1], tri.vertices[tri_pt][2])
                        normal.addData3f(tri.normals[tri_pt][0], tri.normals[tri_pt][1], tri.normals[tri_pt][2])
                        if len(controlled_prim.primitive._texcoordset) > 0:
                            texcoord.addData2f(tri.texcoords[0][tri_pt][0], tri.texcoords[0][tri_pt][1])
                        transform.addData1i(tri.indices[tri_pt])
                    numtris+=1
        elif type(controlled_prim.primitive) is collada.triangleset.BoundTriangleSet:
            for tri in controlled_prim.primitive.triangles():
                for tri_pt in range(3):
                    vertex.addData3f(tri.vertices[tri_pt][0], tri.vertices[tri_pt][1], tri.vertices[tri_pt][2])
                    normal.addData3f(tri.normals[tri_pt][0], tri.normals[tri_pt][1], tri.normals[tri_pt][2])
                    if len(controlled_prim.primitive._texcoordset) > 0:
                        texcoord.addData2f(tri.texcoords[0][tri_pt][0], tri.texcoords[0][tri_pt][1])
                    transform.addData1i(tri.indices[tri_pt])
                numtris+=1
                    
        tbtable.setRows(SparseArray.lowerOn(vdata.getNumRows())) 
        
        gprim = GeomTriangles(Geom.UHStatic)
        for i in range(numtris):
            gprim.addVertices(i*3, i*3+1, i*3+2)
            gprim.closePrimitive()
            
        pgeom = Geom(vdata)
        pgeom.addPrimitive(gprim)
        
        render_state = getStateFromMaterial(controlled_prim.primitive.material)
        control_node = GeomNode("ctrlnode")
        control_node.addGeom(pgeom, render_state)
        ch.addChild(control_node)
    
        bundle = AnimBundle('simplechar', 5.0, 2)
        skeleton = AnimGroup(bundle, '<skeleton>')
        root = AnimChannelMatrixXfmTable(skeleton, 'root')
        
        #hjoint = AnimChannelMatrixXfmTable(root, 'joint1') 
        #table = [10, 11, 12, 13, 14, 15, 14, 13, 12, 11] 
        #data = PTAFloat.emptyArray(len(table)) 
        #for i in range(len(table)): 
        #    data.setElement(i, table[i]) 
        #hjoint.setTable(ord('i'), CPTAFloat(data)) 
        
        #vjoint = AnimChannelMatrixXfmTable(hjoint, 'joint2') 
        #table = [10, 9, 8, 7, 6, 5, 6, 7, 8, 9] 
        #data = PTAFloat.emptyArray(len(table)) 
        #for i in range(len(table)): 
        #    data.setElement(i, table[i]) 
        #vjoint.setTable(ord('j'), CPTAFloat(data)) 

        wiggle = AnimBundleNode('wiggle', bundle)

        np = NodePath(ch) 
        anim = NodePath(wiggle) 
        a = Actor(np, {'simplechar' : anim})
        a.loop('simplechar') 
        return a
        #a.setPos(0, 0, 0)
    
    else:
        raise Exception("Error: unsupported controller type")
Пример #6
0
class Track3d(object):
    '''
    Generate the 3d Mesh out of the StreetData and the 2dTrack
    '''

    def __init__(self, res, x, y, z=200, player_count=1, street_data=""):
        '''
        '''
        self._notify = DirectNotify().newCategory("TrackGen3D")
        self._notify.info("New Track3D-Object created: %s" % (self))
        # street_data = (Vec2(4.0,4.0), Vec2(10.0,10.0), Vec2(10.0,0.0), Vec2(4.0,0.0), Vec2(0.0,-1.0))
        # street_data = StreetData(Vec2(15.0,1.0), Vec2(15.0,-5.0), Vec2(0.0,-5.0), mirrored=True) #, Vec2(15.0,0.0)
        self.street_data = StreetData()

        # self.street_data.readFile("data/road/road01.xml")
        # self.street_data.readFile("data/road/tube.xml")
        if street_data == "":
            datas = ["road01", "tube"]
            street_data = datas[random.randint(0, len(datas) - 1)]
        self.street_data.readFile("data/road/" + street_data + ".xml")

        self.streetTextrange = 0.0
        self.track = Track(x, y, z)
        self.track.generateTestTrack(player_count)
        # self.track.generateTrack(player_count)

        self.track_points = self.track.getInterpolatedPoints(res)
        self.varthickness = []  # Generate the Vector for thickness of the road

        self.generateNormals()
        # for i in range(len(self.track_points)-1):
        # if i == 0:
        # self.varthickness.append(self.calcTheVector(self.track_points[i],self.track_points[i],self.track_points[i+1])) #First
        # continue
        # self.varthickness.append(self.calcTheVector(self.track_points[i-1],self.track_points[i],self.track_points[i+1]))
        # self.varthickness.append(self.calcTheVector(self.track_points[len(self.track_points)-2],self.track_points[len(self.track_points)-1],self.track_points[len(self.track_points)-1])) #Last
        ##
        # Normalizing the Vector
        # for i in self.varthickness:
        # i.normalize()
        ##
        # print self.varthickness[-1]
        # print self.varthickness[0]
        # print self.varthickness[1]
        # print self.varthickness[2]

        # Spin the last 100 Points a litte bit to Vec3(-1,0,0)
        for i in range(-100, 1):
            # print self.varthickness[i] * (-i / 100), self.varthickness[i] , ((i* -1) / 100.0), i
            # print ((i* -1) / 100.0), self.varthickness[i], self.varthickness[i] * ((i* -1) / 100.0)
            self.varthickness[i] = self.varthickness[i] * (((i + 1) * -1) / 100.0) + Vec3(-1, 0, 0)
            self.normals[i] = self.normals[i] * (((i + 1) * -1) / 100.0) + Vec3(0, 0, 1)

            self.varthickness[i].normalize()
            self.normals[i].normalize()
            # print self.varthickness[i]

        # print self.varthickness[-1]
        # print self.varthickness[0]
        # print self.varthickness[1]
        # print self.varthickness[2]
        # print self.varthickness
        # for i in range(len(self.varthickness)):
        # if self.varthickness[i-1].almostEqual(self.varthickness[i], 0.3):
        # pass
        # else:
        # print "varthickness", self.varthickness[i-1], self.varthickness[i]

# -------------------------------------------------------------------------------------

    def resetWriters(self):
        '''
        '''
        self.vdata = GeomVertexData('street', GeomVertexFormat.getV3n3c4t2(), Geom.UHStatic)

        self.vertex = GeomVertexWriter(self.vdata, 'vertex')
        self.normal = GeomVertexWriter(self.vdata, 'normal')
        self.color = GeomVertexWriter(self.vdata, 'color')
        self.texcoord = GeomVertexWriter(self.vdata, 'texcoord')
        self.prim = GeomTriangles(Geom.UHStatic)

# -------------------------------------------------------------------------------------

    def calcTheVector(self, pre, now, past):
        vector1 = (pre[0] - now[0], pre[1] - now[1])
        vector2 = (now[0] - past[0], now[1] - past[1])
        high = pre[2] - past[2]
        return Vec3(((vector1[1] + vector2[1]) / 2.0), ((vector1[0] + vector2[0]) / 2.0), high)

# -------------------------------------------------------------------------------------

    def getVarthickness(self):
        return self.varthickness

# -------------------------------------------------------------------------------------

    def setTrackPoints(self, track_points):
        '''
        '''
        self.track_points = track_points

    def getTrackPoints(self):
        '''
        '''
        return self.track_points

    trackpoints = property(fget=getTrackPoints, fset=setTrackPoints)

# -------------------------------------------------------------------------------------

    def generateNormals(self):
        '''
        '''
        self.varthickness = []
        self.normals = []
        last_normal = Vec3(0, 0, 1)
        # last_vec = Vec3(0, 1, 0)
        for i in range(len(self.track_points)):
            if i == 0:
                vec = self.track_points[0] - self.track_points[1]
            elif i + 1 == len(self.track_points):
                vec = self.track_points[i - 1] - self.track_points[0]
            else:
                vec = self.track_points[i - 1] - self.track_points[i + 1]

            # calculate here the direction out of the street vector and the last normal
            last_normal.normalize()
            vec.normalize()
            mat = Mat3()

            mat.setRotateMat(-90, last_normal)  # turn the direction around the last_normal
            turned_vec = mat.xform(vec)

            turned_vec.normalize()
            last_normal = turned_vec.cross(vec)  # calculate the new normal

            turned_vec.normalize()
            self.varthickness.append(turned_vec)
            self.normals.append(last_normal)

# -------------------------------------------------------------------------------------

    def createVertices(self, track_points=None, street_data=None):
        '''
        '''
        if track_points is None:
            track_points = self.track_points
        if street_data is None:
            street_data = self.street_data

        self.resetWriters()
        texcoordinates = []
        # street_data_length = len(street_data)

        texcoordinates = street_data.getTexCoordinates()
        tracklength = self.track.getLength()
        tex_step = 0.006 * (0.0002 * tracklength)
        for i in range(len(track_points)):
            turned_vec = self.varthickness[i]
            last_normal = self.normals[i]
            j = 0
            for shapedot in street_data:
                # this is like a layer in 3d [Ebenengleichung]
                # vec = vec + vec*scalar + vec*scalar
                # this is used to transform the 2d-Streetshape to 3d
                point = track_points[i] + (turned_vec * shapedot[0]) + (last_normal * shapedot[1])

                self.vertex.addData3f(point[0], point[1], point[2])
                self.normal.addData3f(0, 0, 1)  # KA how to calc
                self.streetTextrange += tex_step

                self.texcoord.addData2f(texcoordinates[j], self.streetTextrange)
                j += 1

# -------------------------------------------------------------------------------------

    def connectVertices(self, street_data):
        # param j = len(street_Data)
        j = len(street_data)
        for i in range(self.vdata.getNumRows() - (j)):  # -j??????  oder +-1
            if (i + 1) % j != 0:
                self.prim.addVertex(i)
                self.prim.addVertex(i + 1)
                self.prim.addVertex(i + j + 1)
                self.prim.closePrimitive()

                self.prim.addVertex(i)
                self.prim.addVertex(i + j + 1)
                self.prim.addVertex(i + j)
                self.prim.closePrimitive()
            else:  # close mesh's bottom side

                self.prim.addVertex(i + 1 - j)
                self.prim.addVertex(i + 1)
                self.prim.addVertex(i)
                self.prim.closePrimitive()

                self.prim.addVertex(i)
                self.prim.addVertex(i + 1)
                self.prim.addVertex(i + j)
                self.prim.closePrimitive()

        # close start and end
        k = self.vdata.getNumRows() - j
        for i in range(j):
            if (i + 1) % j != 0:
                self.prim.addVertex(i)
                self.prim.addVertex(i + k + 1)
                self.prim.addVertex(i + 1)
                self.prim.closePrimitive()

                self.prim.addVertex(i)
                self.prim.addVertex(i + k)
                self.prim.addVertex(i + k + 1)
                self.prim.closePrimitive()

            else:  # close mesh's bottom side
                self.prim.addVertex(i)
                self.prim.addVertex(i + k - j + 1)
                self.prim.addVertex(i - j + 1)
                self.prim.closePrimitive()

                self.prim.addVertex(i)
                self.prim.addVertex(i + k)
                self.prim.addVertex(i + k - j + 1)
                self.prim.closePrimitive()

# -------------------------------------------------------------------------------------

    def createRoadMesh(self):
        '''
        '''
        # Creating the Vertex
        self.createVertices()
        # Connect the Vertex
        self.connectVertices(self.street_data)

        geom = Geom(self.vdata)
        geom.addPrimitive(self.prim)

        node = GeomNode('street')
        node.addGeom(geom)

        # nodePath = self.render.attachNewNode(node)
        return node

    # -------------------------------------------------------------------------------------

    def createUninterpolatedRoadMesh(self):
        '''
        '''
        # Creating the Vertex
        self.createVertices(self.track.getPoints(), self.street_data)
        # Connect the Vertex
        self.connectVertices(self.street_data)

        geom = Geom(self.vdata)
        geom.addPrimitive(self.prim)

        node = GeomNode('street')
        node.addGeom(geom)

        # nodePath = self.render.attachNewNode(node)
        return node

# -------------------------------------------------------------------------------------

    def createBorderLeftMesh(self):
        '''
        '''
        # Creating the Vertex
        self.createVertices(self.track_points, self.street_data.border_l)

        # Connect the Vertex
        self.connectVertices(self.street_data.border_l)

        geom = Geom(self.vdata)
        geom.addPrimitive(self.prim)

        node = GeomNode('border_l')
        node.addGeom(geom)

        # nodePath = self.render.attachNewNode(node)
        return node

# -------------------------------------------------------------------------------------

    def createBorderRightMesh(self):
        '''
        '''
        # Creating the Vertex
        self.createVertices(self.track_points, self.street_data.border_r)
        # Connect the Vertex
        self.connectVertices(self.street_data.border_r)

        geom = Geom(self.vdata)
        geom.addPrimitive(self.prim)

        node = GeomNode('border_r')
        node.addGeom(geom)

        # nodePath = self.render.attachNewNode(node)
        return node

# -------------------------------------------------------------------------------------

    def createBorderLeftCollisionMesh(self):
        '''
        '''
        # Creating the Vertex
        self.createVertices(self.track_points, self.street_data.border_l_coll)

        # Connect the Vertex
        self.connectVertices(self.street_data.border_l_coll)

        geom = Geom(self.vdata)
        geom.addPrimitive(self.prim)

        node = GeomNode('border_l_coll')
        node.addGeom(geom)

        # nodePath = self.render.attachNewNode(node)
        return node

# -------------------------------------------------------------------------------------

    def createBorderRightCollisionMesh(self):
        '''
        '''
        # Creating the Vertex
        self.createVertices(self.track_points, self.street_data.border_r_coll)
        # Connect the Vertex
        self.connectVertices(self.street_data.border_r_coll)

        geom = Geom(self.vdata)
        geom.addPrimitive(self.prim)

        node = GeomNode('border_r_coll')
        node.addGeom(geom)

        # nodePath = self.render.attachNewNode(node)
        return node
class ConstrainedDelaunayTriangulator(object):
    """Creates a Constrained Delaunay Triangulation"""
    @staticmethod
    def drawTriangleIndices(adjLst, name='indsgroup'):
        from direct.gui.OnscreenText import OnscreenText
        indNP = render.attachNewNode(name)
        for i in range(0, len(adjLst)):
            center = getCenterOfPoints3D(adjLst[i].getPoints())
            dummy = indNP.attachNewNode(str(i))
            txt = OnscreenText(text=str(i), pos=center, scale=1)
            txt.reparentTo(dummy)
            dummy.setP(dummy.getP() - 90)

        return indNP

    @staticmethod
    def findContainingTriangle(point, startTriangle, fullList):
        triangles = collections.deque([])
        triangles.append(startTriangle)
        while triangles:
            tri = triangles.popleft()
            if tri.containsPoint(point):
                return tri
            triangles.extend([fullList[i] for i in tri.getNeighbors(includeEmpties=False)])
        raise ValueError("Point added that's outside of the bounded space {0}".format(point))

    def __init__(self, vertexName='ConstrainedDelaunayTriangles', vertexFormat=GeomVertexFormat.getV3(),
                  usage = Geom.UHDynamic, onVertexCreationCallback = None, universalZ = 0.0):
        self._vertexData = GeomVertexData(vertexName, vertexFormat, Geom.UHDynamic)
        self._geomTriangles = GeomTriangles(usage)
        self._geomTrianglesHoles = GeomTriangles(usage)
        self._vertexRewriter = GeomVertexRewriter(self._vertexData, 'vertex')  # user cannot have control of a writer

        if onVertexCreationCallback is None:
            onVertexCreationCallback = lambda x, y, z: None  # something to call without checking existence later
        self._vertexCallback = onVertexCreationCallback

        self._universalZ = universalZ
        self.__holes = [[]]
        self.__polygon = []
        inf = float('inf')
        negInf = float('-inf')
        self.bounds = {
            'minX': inf,
            'maxX': negInf,
            'minY': inf,
            'maxY': negInf,
        }
        self.lastStaticVertexIndex = -1

    def addHoleVertex(self, index):
        """Adds the next consecutive vertex of the current hole."""
        # we might not have holes but we should always have triangles after triangulation
        self.__holes[-1].append(index)

    def addPolygonVertex(self, index):
        """Adds the next consecutive vertex of the polygon."""
        self.__polygon.append(index)

    def _addVertex(self, x, y, z, bounded=True):
        # BLOG track bounds to create the encapsulating triangle rather than lexicographic ordering
        # BLOG could have used a heap while adding verts, then popped as we processed each vertex
        if x < self.bounds['minX'] and bounded:
            self.bounds['minX'] = x
        if x > self.bounds['maxX'] and bounded:
            self.bounds['maxX'] = x

        if y < self.bounds['minY'] and bounded:
            self.bounds['minY'] = y
        if y > self.bounds['maxY'] and bounded:
            self.bounds['maxY'] = y
        if not self._vertexRewriter.isAtEnd():
            self._vertexRewriter.setRow(self._vertexData.getNumRows())
        n = self._vertexRewriter.getWriteRow()
        self._vertexRewriter.addData3f(x, y, self._universalZ)
        self._vertexCallback(x, y, self._universalZ)

        return n

    def addVertex(self, pointOrX, y=None, z=None, bounded=True):
        """Adds a new vertex to the vertex pool."""
        if hasattr(pointOrX, 'y'):  # if the first argument is a point expand and call the backing function
            return self._addVertex(pointOrX.x, pointOrX.y, pointOrX.z, bounded=bounded)
        return self._addVertex(pointOrX, y, z, bounded=bounded)

    def addVertexToPolygon(self, pointOrX, y, z, bounded=True):
        """Adds a vertex to the pool and then adds its index to the polygon vertex index list."""
        n = self.addVertex(pointOrX, y, z, bounded=bounded)
        self.addPolygonVertex(n)
        return n

    def addVertexToHole(self, pointOrX, y, z):
        """Adds a vertex to the pool and then adds its index to the polygon vertex index list."""
        n = self.addVertex(pointOrX, y, z)
        self.addHoleVertex(n)
        return n
    
    def beginHole(self):
        """Finishes the previous hole, if any, and prepares to add a new hole."""
        if self.__holes[-1]:  # if the last hole (list of vertices) is empty use it as the next hole
            self.__holes.append([])  # if it's not empty append a new hole
    
    def clear(self):
        """Removes all vertices and polygon specifications from the Triangulator, and prepares it to start over."""
        raise NotImplementedError("""ConstrainedDelaunayTriangulator.clear() is not implemented.""")
    
    def clearPolygon(self):
        """Removes the current polygon definition (and its set of holes), but does not clear the vertex pool."""
        raise NotImplementedError("""ConstrainedDelaunayTriangulator.clearPolygon() is not implemented.""")

    def getAdjacencyList(self):
        """Returns a list of triangles, each referencing its own neighbors by their list index."""
        return self.__polygon

    def getGeomNode(self, name='ConstrainedDelaunayTriangles'):
        """returns a GeomNode, with the provided name, sufficient to put in the scene and draw."""
        # BLOG My TODO legend
        # DOC 1) (adding to scene) create a Geom and add primitives of like base-type i.e. triangles and triangle strips
        geom = Geom(self._vertexData)
        geom.addPrimitive(self._geomTriangles)
        # DOC 2) create a GeomNode to hold the Geom(s) and add the Geom(s)
        gn = GeomNode(name)
        gn.addGeom(geom)
        # DOC 3) attach the node to the scene (in the calling code)
        # gnNodePath = render.attachNewNode(gn)
        return gn
    
    def getNumTriangles(self):
        """Returns the number of triangles generated by the previous call to triangulate()."""
        if not self.isTriangulated():
            raise ValueError("Vertices must be added and triangulate() must be called before calling getNumTriangles()")
        return len(self.__polygon)
    
    def getNumVertices(self):
        """Returns the number of vertices in the pool."""
        return self._vertexData.getNumRows()

    def getVertexReader(self):
        """Returns a reader for the vertex column."""
        return GeomVertexReader(self._vertexData, 'vertex')
    
    def getTriangleV0(self, n):
        """Returns vertex 0 of the nth triangle generated by the previous call to triangulate()."""
        try:
            return self.__polygon[n].pointIndex0()
        except AttributeError:  # BLOG switching errors to clarify the cause
            raise LookupError("Must call triangulate() before querying for a triangle's vertices.")
    
    def getTriangleV1(self, n):
        """Returns vertex 1 of the nth triangle generated by the previous call to triangulate()."""
        try:
            return self.__polygon[n].pointIndex1()
        except AttributeError:  # BLOG switching errors to clarify the cause
            raise LookupError("Must call triangulate() before querying for a triangle's vertices.")
    
    def getTriangleV2(self, n):
        """Returns vertex 2 of the nth triangle generated by the previous call to triangulate()."""
        try:
            return self.__polygon[n].pointIndex2()
        except AttributeError:  # BLOG switching errors to clarify the cause
            raise LookupError("Must call triangulate() before querying for a triangle's vertices.")

    def getTriangleList(self):
        import copy
        return copy.copy(self.__polygon)

    def getVertex(self, n):
        """Returns the nth vertex."""
        self._vertexRewriter.setRow(n)
        return self._vertexRewriter.getData3f()

    def getGeomVertexData(self):
        return self._vertexData

    def getGeomTriangles(self):
        assert self.isTriangulated()
        return self._geomTriangles
    
    def getVertices(self):
        """Returns a list of vertices."""
        verts = []
        for i in range(0, self._vertexData.getNumRows()):
            self._vertexRewriter.setRow(i)
            verts.append(self._vertexRewriter.getData3f())
        return verts
    
    def isLeftWinding(self):
        """Returns true if the polygon vertices are listed in counterclockwise order,
        or false if they appear to be listed in clockwise order."""
        assert self.isTriangulated()
        return self.__polygon[0].isLeftWinding()

    def isTriangulated(self):
        """Guesses whether the polygon has been triangulated."""
        return len(self.__polygon) > 0 and isinstance(self.__polygon[0], ConstrainedDelaunayAdjacencyTriangle)
    
    def triangulate(self, makeDelaunay=True):
        """Does the work of triangulating the specified polygon."""
        global notify
        if self.isTriangulated():
            raise ValueError("triangulate() must only be called once.")
        notify.warning("bounds: minX, minY, maxX, maxY {0} {1} {2} {3}".format(self.bounds['minX'], self.bounds['minY'],
                                                                               self.bounds['maxX'], self.bounds['maxY']))
        h = abs(self.bounds['maxY'] - self.bounds['minY'])
        w = abs(self.bounds['maxX'] - self.bounds['minX'])
        topLeft = Point3(self.bounds['minX'] - 10*w,
                         self.bounds['maxY'] + 10*h,
                         self._universalZ)
        bottomRight = Point3(self.bounds['minX'] - 10*w,
                            self.bounds['minY'] - 10*h,
                            self._universalZ)
        farRight = Point3(self.bounds['maxX'] + 10*w, (self.bounds['maxY'] + self.bounds['minY'])/2, self._universalZ)
        # Other than the tree below, any vertices added after this are CDT as opposed to DT
        self.lastStaticVertexIndex = self.getNumVertices() - 1
        # these three will be removed later, thus will not be artificial restraints
        v0 = self.addVertex(topLeft, bounded=False)
        v1 = self.addVertex(bottomRight, bounded=False)
        v2 = self.addVertex(farRight, bounded=False)
        bounds = ConstrainedDelaunayAdjacencyTriangle(v0, v1, v2,
                                                      self._vertexData, self._geomTriangles, self._vertexRewriter)
        triangulated = [bounds]

        while True:
            try:
                pt = self.__polygon.pop()
            except IndexError:
                break
            self._vertexRewriter.setRow(pt)
            point = self._vertexRewriter.getData3f()
            notify.warning("\n######################## len {} TRIANGULATE {} ###########################\n".format(len(triangulated), point))
            notify.warning("\n########################## SO FAR\n{}\n############################\n".format([tr.index for tr in triangulated]))
            # find the triangle the point lays within
            found = ConstrainedDelaunayTriangulator.findContainingTriangle(point, bounds, triangulated)
            if found is not None:
                # BLOG heapq.merge() is useless as it returns an iterable which can't be indexed, but heaps require lists
                # BLOG Hence, it's probably faster to heap.push than to iterate (in C) a merge then iterate to recreate a list
                # BLOG if I use a heap
                # triangulate the point into the triangle, collecting any new triangles
                newTriangles = found.triangulatePoint(pt, triangulated)
                triangulated.extend(newTriangles)
                if makeDelaunay:
                    for tri in newTriangles:
                        tri.legalize(tri.point0, triangulated)  # point, triangulated)
                        tri.legalize(tri.point1, triangulated)
                        tri.legalize(tri.point2, triangulated)
            else:
                raise ValueError("Point given that's outside of original space.")
        notify.warning("triangulated: length: {} type: {}".format(len(triangulated), type(triangulated)))
        self.__polygon = triangulated