def ComputePlanarCoordsOfIncidentVertForEdges(self):
        for i in range(self.GetNumOfEdges()):
            if (self.IsExtremeEdge(i)):
                continue

            bottom = self.Edge(i).edge_length
            leftLen = self.Edge(self.Edge(i).indexOfLeftEdge).edge_length
            squareOfLeftLen = leftLen**2
            rightLen = self.Edge(self.Edge(i).indexOfRightEdge).edge_length
            if (bottom < Constants.FLT_EPSILON):
                bottom = Constants.FLT_EPSILON
            x = (squareOfLeftLen - rightLen**2) / bottom + bottom
            x /= 2.0
            self.m_Edges[i].coordOfOppositeVert = make_pair(
                x, (max(0.0, squareOfLeftLen - x**2))**0.5)

        for i in range(self.GetNumOfEdges()):
            if (self.IsExtremeEdge(i)):
                continue

            reverseEdge = self.m_Edges[
                self.m_Edges[i].indexOfLeftEdge].indexOfReverseEdge
            coord = self.GetNew2DCoordinatesByReversingCurrentEdge(
                reverseEdge, self.m_Edges[reverseEdge].coordOfOppositeVert)
            scale = abs(coord.first) + abs(coord.second)
            if (scale < Constants.FLT_EPSILON):
                scale = Constants.FLT_EPSILON
            coord.first *= (1.0 / scale)
            coord.second *= (1.0 / scale)
            leng = (coord.first**2 + coord.second**2)**0.5

            if (leng < Constants.FLT_EPSILON):
                leng = Constants.FLT_EPSILON

            self.m_Edges[i].matrixRotatedToLeftEdge = make_pair(
                coord.first / leng, coord.second / leng)

            reverseEdge = self.m_Edges[
                self.m_Edges[i].indexOfRightEdge].indexOfReverseEdge
            rightX = self.m_Edges[reverseEdge].edge_length
            rightY = 0
            leftX = self.m_Edges[reverseEdge].edge_length - self.m_Edges[
                reverseEdge].coordOfOppositeVert.first
            leftY = -self.m_Edges[reverseEdge].coordOfOppositeVert.second

            detaX = rightX - leftX
            detaY = rightY - leftY
            scale = abs(detaX) + abs(detaY)

            if (scale < Constants.FLT_EPSILON):
                scale = Constants.FLT_EPSILON

#             if(scale != 0.0):
            detaX *= (1.0 / scale)
            detaY *= (1.0 / scale)
            leng = (detaX**2 + detaY**2)**0.5
            if (leng < Constants.FLT_EPSILON):
                leng = Constants.FLT_EPSILON
            self.m_Edges[i].matrixRotatedToRightEdge = make_pair(
                detaX / leng, detaY / leng)
 def __init__(self):
     self.indexOfLeftVert = -1
     self.indexOfRightVert = -1
     self.indexOfOppositeVert = -1
     self.indexOfLeftEdge = -1
     self.indexOfRightEdge = -1
     self.indexOfReverseEdge = -1
     self.indexOfFrontFace = -1
     self.edge_length = 0
     self.coordOfOppositeVert = make_pair(0.0, 0.0)
     self.matrixRotatedToLeftEdge = make_pair(0.0, 0.0)
     self.matrixRotatedToRightEdge = make_pair(0.0, 0.0)
    def GetNew2DCoordinatesByRotatingAroundLeftChildEdge(
            self, edgeIndex, input2DCoordinates):

        return make_pair(
            self.m_Edges[edgeIndex].matrixRotatedToLeftEdge.first *
            input2DCoordinates.first -
            self.m_Edges[edgeIndex].matrixRotatedToLeftEdge.second *
            input2DCoordinates.second,
            self.m_Edges[edgeIndex].matrixRotatedToLeftEdge.second *
            input2DCoordinates.first +
            self.m_Edges[edgeIndex].matrixRotatedToLeftEdge.first *
            input2DCoordinates.second)
    def GetNew2DCoordinatesByRotatingAroundRightChildEdge(
            self, edgeIndex, input2DCoordinates):
        reverseEdge = self.m_Edges[
            self.m_Edges[edgeIndex].indexOfRightEdge].indexOfReverseEdge
        coordOfLeftEnd = self.GetNew2DCoordinatesByReversingCurrentEdge(
            reverseEdge, self.m_Edges[reverseEdge].coordOfOppositeVert)

        return make_pair(
            self.m_Edges[edgeIndex].matrixRotatedToRightEdge.first *
            input2DCoordinates.first -
            self.m_Edges[edgeIndex].matrixRotatedToRightEdge.second *
            input2DCoordinates.second + coordOfLeftEnd.first,
            self.m_Edges[edgeIndex].matrixRotatedToRightEdge.second *
            input2DCoordinates.first +
            self.m_Edges[edgeIndex].matrixRotatedToRightEdge.first *
            input2DCoordinates.second + coordOfLeftEnd.second)
    def ComputeAnglesAroundVerts(self):
        self.m_FlagsForCheckingConvexVerts = [
            False for i in range(self.GetNumOfVerts())
        ]

        for i in range(len(self.m_NeighsAndAngles)):
            neighSize = len(self.Neigh(i))
            if (neighSize > len(self.m_NeighsAndAngles[i])):
                diffLen = neighSize - len(self.m_NeighsAndAngles[i])
                self.m_NeighsAndAngles[i].extend([make_pair(0, 0)]
                                                 for j in range(diffLen))

        for i in range(len(self.m_NeighsAndAngles)):
            angleSum = 0

            for j in range(len(self.m_NeighsAndAngles[i])):

                if (self.IsExtremeEdge(self.Neigh(i)[j].first)):
                    self.m_NeighsAndAngles[i][j].second = 2 * math.pi + 0.1

                else:
                    next = j + 1

                    if (next >= len(self.m_NeighsAndAngles[i])):
                        next = 0

                    #Essentially left, right, and bottom
                    l = self.Edge(self.Neigh(i)[j].first).edge_length
                    r = self.Edge(self.Neigh(i)[next].first).edge_length
                    b = self.Edge(
                        self.Edge(self.Neigh(i)
                                  [j].first).indexOfRightEdge).edge_length

                    try:
                        costheta = (l**2 + r**2 - b**2) / (2 * l * r)
                        self.m_NeighsAndAngles[i][j].second = math.acos(
                            min(1.0, max(-1.0, costheta)))
                    except ZeroDivisionError:
                        self.m_NeighsAndAngles[i][j].second = 0

                angleSum += self.m_NeighsAndAngles[i][j].second

            self.m_FlagsForCheckingConvexVerts[i] = (
                angleSum < ((2 * math.pi) - Constants.ToleranceOfConvexAngle))
 def GetNew2DCoordinatesByReversingCurrentEdge(self, edgeIndex,
                                               input2DCoordinates):
     return make_pair(
         self.m_Edges[edgeIndex].edge_length - input2DCoordinates.first,
         -input2DCoordinates.second)
    def CollectAndArrangeNeighs(self):
        self.m_nIsolatedVerts = 0
        sequenceOfDegrees = [0 for it in range(self.GetNumOfVerts())]
        #The below should be a resize operation essentially. But the below statement is okay
        #because this is the first time the list itself is created
        self.m_NeighsAndAngles = [[] for i in range(self.GetNumOfVerts())]
        for i in range(len(self.m_NeighsAndAngles)):
            self.m_NeighsAndAngles[i].extend([make_pair(-1, 0)])

        for i in range(self.GetNumOfEdges()):
            edge = self.Edge(i)
            sequenceOfDegrees[edge.indexOfLeftVert] += 1
            indexOfStartEdge = self.m_NeighsAndAngles[
                edge.indexOfLeftVert][0].first

            if (indexOfStartEdge == -1
                    or not self.IsStartEdge(indexOfStartEdge)):
                indexOfStartEdge = i
                self.m_NeighsAndAngles[edge.indexOfLeftVert][0].first = i

            elif (self.IsStartEdge(i)):
                self.m_NeighsAndAngles[edge.indexOfLeftVert].append(
                    make_pair(i, 0))

#         print('SEQUENCE OF DEGREES ::: ', sequenceOfDegrees);

        for i in range(self.GetNumOfVerts()):

            if (self.m_NeighsAndAngles[i][0].first == -1):
                self.m_NeighsAndAngles[i] = []
                self.m_nIsolatedVerts += 1
                continue

            startEdges = []

            for j in range(len(self.Neigh(i))):
                startEdges.append(self.Neigh(i)[j].first)

            #The below is typically the resize operation equivalent of C++
            #In the C++ if the list is already of a size given in resize with
            #existing elements, then it does not touch the elements nor changes anything
            #But if the resizing size is higher than the current size then it will append
            #new elements to the difference of old size and new size;
            if (sequenceOfDegrees[i] > len(self.m_NeighsAndAngles[i])):
                difflen = sequenceOfDegrees[i] - len(self.m_NeighsAndAngles[i])
                self.m_NeighsAndAngles[i].extend(
                    [make_pair(0, 0) for j in range(difflen)])

            num = 0
            for j in range(len(startEdges)):
                curEdge = startEdges[j]
                while (True):
                    self.m_NeighsAndAngles[i][num].first = curEdge
                    num += 1

                    if (num >= sequenceOfDegrees[i]):
                        break

                    if (self.IsExtremeEdge(curEdge)):
                        break

                    curEdge = self.Edge(curEdge).indexOfLeftEdge

                    if (curEdge == startEdges[j]):
                        break

            if (num != sequenceOfDegrees[i]):
                raise ValueError("Complex vertices")
    def CreateEdgesFromVertsAndFaces(self):
        pondOfUndeterminedEdges = {}

        sZFaces = self.GetNumOfFaces()

        for i in range(sZFaces):
            threeindices = [None, None, None]

            for j in range(3):
                post = (j + 1) % 3
                pre = (j + 2) % 3

                leftVert = self.Face(i)[pre]
                rightVert = self.Face(i)[j]

                it = pondOfUndeterminedEdges.get(make_pair(
                    leftVert, rightVert))

                if (it):
                    posInEdgeList = it

                    if (self.m_Edges[posInEdgeList].indexOfOppositeVert != -1):
                        raise ValueError('Repeated Edges!')

                    threeindices[j] = posInEdgeList
                    self.m_Edges[
                        posInEdgeList].indexOfOppositeVert = self.Face(i)[post]
                    self.m_Edges[posInEdgeList].indexOfFrontFace = i

                else:
                    edge = CEdge()
                    edge.edge_length = max(Constants.FLT_EPSILON,
                                           (self.Vert(leftVert) -
                                            self.Vert(rightVert)).length)
                    edge.indexOfLeftVert = leftVert
                    edge.indexOfRightVert = rightVert
                    edge.indexOfReverseEdge = len(self.m_Edges) + 1
                    edge.indexOfFrontFace = i
                    edge.indexOfOppositeVert = self.Face(i)[post]
                    self.m_Edges.append(edge)

                    pairofvert = make_pair(leftVert, rightVert)
                    pondOfUndeterminedEdges[pairofvert] = len(self.m_Edges) - 1
                    threeindices[j] = len(self.m_Edges) - 1

                    edge = CEdge()
                    edge.edge_length = max(Constants.FLT_EPSILON,
                                           (self.Vert(leftVert) -
                                            self.Vert(rightVert)).length)

                    edge.indexOfLeftVert = rightVert
                    edge.indexOfRightVert = leftVert
                    edge.indexOfReverseEdge = len(self.m_Edges) - 1
                    edge.indexOfFrontFace = -1
                    edge.indexOfOppositeVert = -1
                    self.m_Edges.append(edge)
                    pondOfUndeterminedEdges[make_pair(
                        rightVert, leftVert)] = len(self.m_Edges) - 1

            for j in range(3):
                self.m_Edges[threeindices[j]].indexOfLeftEdge = self.Edge(
                    threeindices[(j + 2) % 3]).indexOfReverseEdge
                self.m_Edges[threeindices[j]].indexOfRightEdge = self.Edge(
                    threeindices[(j + 1) % 3]).indexOfReverseEdge