private OverlapType DetectOverlap(MeshInfo m1, MeshInfo m2)
        {
            // If the bounds are not overlapping the polygons won't overlap
            // Doing this check first speeds the algorithm up
            if (!BoundsOverlap(m1.Bounds, m2.Bounds))
            {
                return(OverlapType.NotOverlapping);
            }

            // If any edge is overlapping it does overlap
            if (AnyEdgeOverlap(m1, m2))
            {
                return(OverlapType.Overlapping);
            }
            else
            {
                // No edges overlap, so now we need to know if a random point is inside the other polygon
                Vector3 randomPoint1 = m1.Vertices[Random.Range(0, m1.Vertices.Count - 1)];
                Vector3 randomPoint2 = m2.Vertices[Random.Range(0, m2.Vertices.Count - 1)];

                // Checking tuple so the second loop can become shorter every loop
                if (Utils.PointInPolygon(randomPoint2, m1))
                {
                    return(OverlapType.FullyContainedIn1);
                }

                if (Utils.PointInPolygon(randomPoint1, m2))
                {
                    return(OverlapType.FullyContainedIn2);
                }
            }

            return(OverlapType.NotOverlapping);
        }
示例#2
0
        public static bool PointInPolygon(Vector3 p, MeshInfo polygon, bool debug = false)
        {
            if (!CheckInBounds(p, polygon.Bounds))
            {
                if (debug)
                {
                    InSceneDebugTool.Instance.DrawPoint(p, Color.blue);
                }
                return(false);
            }

            // Create an infinite line on the x-axis
            Vector3 p2 = p;

            p2.x += 1000;

            // If this has an even number of intersections with the polygon the point lies outside, otherwise it lies inside
            int i = LineMeshIntersectionCount(p, p2, polygon);

            if (debug)
            {
                InSceneDebugTool.Instance.DrawLine(p, p2, Color.yellow);
                if (i % 2 == 0)
                {
                    InSceneDebugTool.Instance.DrawPoint(p, Color.red);
                }
                else
                {
                    InSceneDebugTool.Instance.DrawPoint(p, Color.green);
                }
            }

            return(i % 2 != 0);
        }
        private List <List <Vector3> > GetExistingHoleLoopVertices(MeshInfo m1, MeshInfo m2)
        {
            List <List <Vector3> > holeVertices = new List <List <Vector3> >();
            List <List <Vector2> > list         = m1.GetHoles();

            for (int i = 0; i < list.Count; i++)
            {
                List <Vector3> converted = new List <Vector3>();
                for (int v = 0; v < list[i].Count; v++)
                {
                    converted.Add(Utils.Vector3FromVector2(list[i][v]));
                }
                holeVertices.Add(converted);
            }
            list = m2.GetHoles();
            for (int i = 0; i < list.Count; i++)
            {
                List <Vector3> converted = new List <Vector3>();
                for (int v = 0; v < list[i].Count; v++)
                {
                    converted.Add(Utils.Vector3FromVector2(list[i][v]));
                }
                holeVertices.Add(converted);
            }
            return(holeVertices);
        }
 public void PreProcessMeshes()
 {
     Debug.Log($"Preprocessing... {AllMeshes.Count}");
     AllMeshes.Sort((x1, x2) => x2.Bounds.extents.magnitude.CompareTo(x1.Bounds.extents.magnitude));
     for (int i = 0; i < AllMeshes.Count; i++)
     {
         MeshInfo m = AllMeshes[i];
         if (CombineFor(m, AllMeshes, i))
         {
             PreProcessMeshes();
             break;
         }
     }
 }
        private List <int> GetEdgesConnectedToV(MeshInfo m, Vector3 v)
        {
            List <int> indices = new List <int>();

            for (int i = 0; i < m.OuterEdges.Count; i++)
            {
                EdgeInfo eI = m.OuterEdges[i];
                // Only want the second vertices, guaranteeing order of execution
                if (m.Vertices[eI.v1] == v)
                {
                    indices.Add(i);
                }
            }
            return(indices);
        }
        private (bool, int) ClosestEdgeFromSharedPoint(List <EdgeInfo> edges1, List <EdgeInfo> edges2, EdgeInfo e, MeshInfo m1, MeshInfo m2, bool onFirstMesh)
        {
            MeshInfo m = m1;

            if (onFirstMesh)
            {
                m = m1;
            }
            else
            {
                m = m2;
            }
            Vector3 sharedPoint = m.Vertices[e.v2];

            int     idx   = -1;
            float   angle = float.MinValue;
            Vector2 dirP1 = new Vector2(m.Vertices[e.v1].x - sharedPoint.x, m.Vertices[e.v1].z - sharedPoint.z);

            // Check for m1
            List <int> otherEdges = GetEdgesConnectedToV(m1, sharedPoint);

            foreach (int i in otherEdges)
            {
                Vector3 v = m1.Vertices[m1.OuterEdges[i].v2];
                float   a = Utils.CWAngleBetweenVectors(dirP1, new Vector2(v.x - sharedPoint.x, v.z - sharedPoint.z));
                if (a > angle)
                {
                    angle       = a;
                    idx         = i;
                    onFirstMesh = true;
                }
            }

            // Check for m2
            otherEdges = GetEdgesConnectedToV(m2, sharedPoint);
            foreach (int i in otherEdges)
            {
                Vector3 v = m2.Vertices[m2.OuterEdges[i].v2];
                float   a = Utils.CWAngleBetweenVectors(dirP1, new Vector2(v.x - sharedPoint.x, v.z - sharedPoint.z));
                if (a > angle)
                {
                    angle       = a;
                    idx         = i;
                    onFirstMesh = false;
                }
            }
            return(onFirstMesh, idx);
        }
示例#7
0
        public static int LineMeshIntersectionCount(Vector3 p1, Vector3 p2, MeshInfo mesh)
        {
            int count = 0;

            foreach (EdgeInfo e in mesh.OuterEdges)
            {
                Vector3 p3 = mesh.Vertices[e.v1];
                Vector3 p4 = mesh.Vertices[e.v2];
                Vector3 intersectionPoint = new Vector3();
                if (Utils.SegmentIntersect(p1, p2, p3, p4, out intersectionPoint))
                {
                    count++;
                }
            }
            return(count);
        }
        private void FixOverlap(MeshInfo m1, MeshInfo m2)
        {
            // Get all intersections
            List <EdgeIntersect> intersections = new List <EdgeIntersect>();
            Dictionary <MeshInfo, List <int> > sharedPointsDict = new Dictionary <MeshInfo, List <int> >();
            List <int> m1Shared = new List <int>();
            List <int> m2Shared = new List <int>();

            (intersections, m1Shared, m2Shared) = GetAllEdgeIntersections(m1.Vertices, m2.Vertices, ref m1.OuterEdges, ref m2.OuterEdges, false);
            sharedPointsDict.Add(m1, m1Shared);
            sharedPointsDict.Add(m2, m2Shared);

            List <Vector3> vertices = GetOuterVertices(m1, m2, ref intersections, ref sharedPointsDict);

            // Get existing hole gaps
            List <List <Vector3> > holeVertices = GetExistingHoleLoopVertices(m1, m2);

            // Solving the remaining intersection gives the gaps in between meshes as hole loops
            int            depth        = 2;
            List <Vector3> usedVertices = new List <Vector3>();

            while (intersections.Count > 0)
            {
                depth--;
                if (depth < 0)
                {
                    break;
                }

                List <Vector3> holeLoop = GetHoleLoop(m1, m2, vertices, ref usedVertices, ref intersections);
                if (holeLoop.Count < 3)
                {
                    break;
                }
                holeVertices.Add(holeLoop);
            }

            AllMeshes.Remove(m1);
            AllMeshes.Remove(m2);

            MeshInfo newMesh = new MeshInfo(vertices, holeVertices);

            AllMeshes.Add(newMesh);
        }
        private bool CombineFor(MeshInfo meshInfo, List <MeshInfo> meshes, int i)
        {
            MeshInfo mesh1       = meshInfo;
            Vector3  randomPoint = mesh1.Vertices[Random.Range(0, mesh1.Vertices.Count - 1)];

            for (int j = i + 1; j < meshes.Count; j++)
            {
                MeshInfo mesh2 = meshes[j];

                OverlapType type = DetectOverlap(mesh1, mesh2);

                if (type == OverlapType.NotOverlapping)
                {
                    continue;
                }

                if (type == OverlapType.FullyContainedIn1)
                {
                    AllMeshes.Remove(meshes[j]);
                    return(true);
                }

                if (type == OverlapType.FullyContainedIn2)
                {
                    AllMeshes.Remove(meshes[i]);
                    return(true);
                }

                if (type == OverlapType.Overlapping)
                {
                    if (mesh1.Bounds.extents.magnitude > mesh2.Bounds.extents.magnitude)
                    {
                        FixOverlap(mesh1, mesh2);
                    }
                    else
                    {
                        FixOverlap(mesh2, mesh1);
                    }

                    return(true);
                }
            }
            return(false);
        }
        public void AddHoleVertex(Vector3 v, MeshClicker containing)
        {
            if (_vertices.Count == 0)
            {
                Mesh     m  = containing.GetComponent <MeshFilter>().sharedMesh;
                MeshInfo mI = new MeshInfo(m);
                if (Utils.PointInPolygon(v, mI))
                {
                    _drawingHoleIn    = containing.gameObject;
                    _boundaryVertices = m.vertices.ToList();
                    _boundaryEdges    = GetEdges(m.triangles).FindBoundary().SortEdges();


                    List <EdgeInfo>         outerBoundary;
                    List <List <EdgeInfo> > holes;
                    Utils.ExtractLoopsFromMesh(m, out outerBoundary, out holes);

                    _outerBoundaryVertices = new List <Vector3>();
                    for (int i = 0; i < outerBoundary.Count; i++)
                    {
                        // Construct outer boundary
                        _outerBoundaryVertices.Add(_boundaryVertices[outerBoundary[i].v1]);
                        InSceneDebugTool.Instance.DrawEdge(outerBoundary[i], m, Color.red);
                    }

                    for (int l = 0; l < holes.Count; l++)
                    {
                        List <EdgeInfo> loop = holes[l];
                        foreach (EdgeInfo e in loop)
                        {
                            InSceneDebugTool.Instance.DrawEdge(e, m, Color.blue);
                        }
                        List <Vector2> hole = new List <Vector2>();
                        for (int i = 0; i < loop.Count; i++)
                        {
                            hole.Add(Utils.Vector2FromVector3(_boundaryVertices[loop[i].v1]));
                        }
                        _holes.Add(hole);
                    }
                }
            }
            AddVertex(v);
        }
        private bool AnyEdgeOverlap(MeshInfo mesh1, MeshInfo mesh2)
        {
            foreach (EdgeInfo e1 in mesh1.OuterEdges)
            {
                Vector3 p1 = mesh1.Vertices[e1.v1];
                Vector3 p2 = mesh1.Vertices[e1.v2];

                foreach (EdgeInfo e2 in mesh2.OuterEdges)
                {
                    Vector3 p3 = mesh2.Vertices[e2.v1];
                    Vector3 p4 = mesh2.Vertices[e2.v2];
                    Vector3 intersectionPoint = new Vector3();
                    if (Utils.SegmentIntersect(p1, p2, p3, p4, out intersectionPoint))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
        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> 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 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);
        }