private List <Vector3> GetHoleLoop(MeshInfo m1, MeshInfo m2, List <Vector3> vertices, ref List <Vector3> usedVertices, ref List <EdgeIntersect> intersections)
        {
            List <Vector3> holeLoop = new List <Vector3>();

            EdgeInfo e        = m1.OuterEdges[intersections[0].edge1];
            Vector3  firstV   = m1.Vertices[e.v1];
            int      startIdx = e.v1;
            int      edgeIdx  = intersections[0].edge1;

            if (vertices.Contains(firstV) || usedVertices.Contains(firstV))
            {
                firstV   = m1.Vertices[e.v2];
                startIdx = e.v2;
            }

            holeLoop.Add(firstV);
            usedVertices.Add(firstV);

            bool     done        = false;
            bool     onFirstMesh = true;
            MeshInfo m           = onFirstMesh ? m1 : m2;

            EdgeInfo lastEdge    = m1.OuterEdges.Find(x => x.v1 == startIdx);
            int      lastEdgeIdx = m1.OuterEdges.FindIndex(x => x == lastEdge);


            while (!done)
            {
                Vector3       newV      = Vector3.zero;
                EdgeIntersect intersect = new EdgeIntersect();

                if (GetClosestIntersect(holeLoop[holeLoop.Count - 1], intersections, e, m1, m2, onFirstMesh, out intersect, false, true))
                {
                    newV = intersect.intersectionPoint;
                    intersections.Remove(intersect);

                    // Flip
                    onFirstMesh = !onFirstMesh;
                    edgeIdx     = onFirstMesh ? intersect.edge1 : intersect.edge2;
                    m           = onFirstMesh ? m1 : m2;
                    e           = m.OuterEdges[edgeIdx];
                }
                else
                {
                    if (m.Vertices[e.v1] != holeLoop[0])
                    {
                        newV = m.Vertices[e.v1];
                    }

                    edgeIdx--;
                    if (edgeIdx < 0)
                    {
                        edgeIdx = m.OuterEdges.Count - 1;
                    }

                    e = m.OuterEdges[edgeIdx];
                }

                holeLoop.Add(newV);
                usedVertices.Add(newV);

                if (!done)
                {
                    done = (e.v2 == startIdx && onFirstMesh && !intersections.Exists(x => x.edge1 == edgeIdx || x.edge1 == lastEdgeIdx)) || (holeLoop.Last() == m1.Vertices[startIdx] && holeLoop.Count != 1);
                }
            }
            return(holeLoop);
        }
        private bool GetClosestIntersect(Vector3 lastPoint, List <EdgeIntersect> intersections, EdgeInfo e, MeshInfo m1, MeshInfo m2, bool onFirstMesh, out EdgeIntersect intersect, bool debug = false, bool reverse = false)
        {
            intersect = new EdgeIntersect();
            List <EdgeIntersect> intersects = new List <EdgeIntersect>();
            MeshInfo             m          = m1;

            if (onFirstMesh)
            {
                m          = m1;
                intersects = intersections.FindAll(x => m1.OuterEdges[x.edge1] == e);
            }
            else
            {
                m          = m2;
                intersects = intersections.FindAll(x => m2.OuterEdges[x.edge2] == e);
            }

            if (intersects.Count == 0)
            {
                return(false);
            }

            // Get direction of the edge
            Vector3 edge_p1       = m.Vertices[e.v1];
            Vector3 edge_p2       = m.Vertices[e.v2];
            Vector3 edgeDirection = Vector3.zero;

            if (reverse)
            {
                edgeDirection = (edge_p1 - edge_p2).normalized;
            }
            else
            {
                edgeDirection = (edge_p2 - edge_p1).normalized;
            }

            if (debug)
            {
                InSceneDebugTool.Instance.DrawPoint(edge_p1, Color.red, .3f);
                InSceneDebugTool.Instance.DrawPoint(edge_p2, Color.blue, .4f);
            }

            float minDist = float.MaxValue;

            if (intersects.Count == 1)
            {
                intersect = intersects[0];

                Vector3 newPointDirection = (intersect.intersectionPoint - lastPoint).normalized;
                // Same direction/not opposite direction
                if (Vector3.Dot(newPointDirection, edgeDirection) > 0)
                {
                    return(true);
                }
                else
                {
                    return(false);
                }
            }
            else
            {
                foreach (EdgeIntersect eI in intersects)
                {
                    Vector3 intersectionPoint = new Vector3();
                    Vector3 p1 = m1.Vertices[m1.OuterEdges[eI.edge1].v1];
                    Vector3 p2 = m1.Vertices[m1.OuterEdges[eI.edge1].v2];
                    Vector3 p3 = m2.Vertices[m2.OuterEdges[eI.edge2].v1];
                    Vector3 p4 = m2.Vertices[m2.OuterEdges[eI.edge2].v2];

                    Utils.SegmentIntersect(p1, p2, p3, p4, out intersectionPoint);

                    // Check if in correct direction
                    Vector3 newPointDirection = (intersectionPoint - lastPoint).normalized;
                    if (Vector3.Dot(newPointDirection, edgeDirection) > 0)
                    { // Same direction if dot is positive
                        if (Vector3.Distance(intersectionPoint, lastPoint) < minDist)
                        {
                            minDist   = Vector3.Distance(intersectionPoint, lastPoint);
                            intersect = eI;
                        }
                    }
                }
            }

            if (minDist == float.MaxValue)
            {
                return(false);
            }

            return(true);
        }
        private List <Vector3> GetOuterVertices(MeshInfo m1, MeshInfo m2, ref List <EdgeIntersect> intersections, ref Dictionary <MeshInfo, List <int> > sharedPointsDict)
        {
            // Find a starting point, only requirement is that it lies outside of m2
            int startIndex = 0;

            while (Utils.PointInPolygon(m1.Vertices[startIndex], m2))
            {
                startIndex++;
                if (startIndex >= m1.Vertices.Count)
                {
                    AllMeshes.Remove(m1);
                    return(new List <Vector3>());
                }
            }

            // Initialiazing variable
            bool           onFirstMesh = true;
            EdgeInfo       edge        = m1.OuterEdges.Find(x => x.v1 == startIndex);
            int            edgeIdx     = m1.OuterEdges.FindIndex(x => x == edge);
            List <Vector3> vertices    = new List <Vector3>();

            // Add first point
            vertices.Add(m1.Vertices[startIndex]);

            EdgeInfo lastEdge    = m1.OuterEdges.Find(x => x.v2 == startIndex);
            int      lastEdgeIdx = m1.OuterEdges.FindIndex(x => x == lastEdge);
            MeshInfo m           = onFirstMesh ? m1 : m2;

            // If the first point is a shared point, we need to select the correct edge before entering the while loop
            if (sharedPointsDict[m1].Contains(startIndex))
            {
                (onFirstMesh, edgeIdx) = ClosestEdgeFromSharedPoint(m1.OuterEdges, m2.OuterEdges, m1.OuterEdges.Find(x => x.v2 == startIndex), m1, m2, onFirstMesh);
                m    = onFirstMesh ? m1 : m2;
                edge = m.OuterEdges[edgeIdx];
            }

            // Walk over the edges untill an intersection is found, in which case we swap mesh. Keep going till we are back
            bool    done    = false;
            Vector2 prevDir = Vector2.zero;

            while (!done)
            {
                Vector3       newV      = Vector3.zero;
                EdgeIntersect intersect = new EdgeIntersect();


                if (sharedPointsDict[m].Contains(edge.v2))
                {
                    newV = m.Vertices[edge.v2];

                    (onFirstMesh, edgeIdx) = ClosestEdgeFromSharedPoint(m1.OuterEdges, m2.OuterEdges, edge, m1, m2, onFirstMesh);

                    m    = onFirstMesh ? m1 : m2;
                    edge = m.OuterEdges[edgeIdx];
                }
                else
                {
                    if (GetClosestIntersect(vertices[vertices.Count - 1], intersections, edge, m1, m2, onFirstMesh, out intersect))
                    {
                        newV = intersect.intersectionPoint;
                        intersections.Remove(intersect);

                        // Flip
                        onFirstMesh = !onFirstMesh;
                        edgeIdx     = onFirstMesh ? intersect.edge1 : intersect.edge2;
                        m           = onFirstMesh ? m1 : m2;
                        edge        = m.OuterEdges[edgeIdx];
                    }
                    else
                    {
                        if (m.Vertices[edge.v2] != vertices[0])
                        {
                            newV = m.Vertices[edge.v2];
                        }

                        edgeIdx++;
                        if (edgeIdx >= m.OuterEdges.Count)
                        {
                            edgeIdx = 0;
                        }

                        edge = m.OuterEdges[edgeIdx];
                    }
                }

                if (newV != Vector3.zero)
                {
                    Vector2 sndPoint = Utils.Vector2FromVector3(m.Vertices[edge.v2]);
                    Vector2 newDir   = (Utils.Vector2FromVector3(newV) - sndPoint).normalized;

                    if (prevDir == Vector2.zero)
                    {
                        prevDir = (Utils.Vector2FromVector3(vertices.Last()) - Utils.Vector2FromVector3(newV)).normalized;
                    }

                    if (prevDir != newDir)
                    {
                        if (newV != m1.Vertices[startIndex])
                        {
                            vertices.Add(newV);
                        }
                        else
                        {
                            done = true;
                        }
                    }
                    prevDir = newDir;
                }

                if (!done)
                {
                    done = (edge.v1 == startIndex && onFirstMesh && !intersections.Exists(x => x.edge1 == edgeIdx || x.edge1 == lastEdgeIdx)) || (vertices.Last() == m1.Vertices[startIndex] && vertices.Count != 1);
                }
            }
            return(vertices);
        }