Example #1
0
        private int TraverseCut(Cut cut, EdgeLoop loop, List <Vertex> perimeter, int currentVertexIndex)
        {
            cut.traversed = true;

            // add all vertices of the egress's cut to the loop
            loop.vertices.AddRange(cut);
            perimeter[currentVertexIndex].loops.Add(loop);

            // find the index of the last vertex in the cut (which is always an egress) and get its index in the perimeter
            currentVertexIndex = perimeter.IndexOf(cut[cut.Count - 1]);
            perimeter[currentVertexIndex].loops.Add(loop);

            string cutString = "";

            foreach (Vertex vertex in cut)
            {
                cutString += " ";
                if (perimeter.Contains(vertex))
                {
                    cutString += perimeter.IndexOf(vertex) + ": ";
                }
                cutString += vertex;
            }
            //Debug.Log("Traversing egress: " + cutString);
            //Debug.Log("Egress traversed. Arrived at " + currentVertexIndex);

            return(currentVertexIndex);
        }
Example #2
0
        private List <Triangle> TriangulateEdgeLoop(EdgeLoop loop, bool debug = false)
        {
            List <Triangle> triangles = new List <Triangle>();

            for (int i = 1; i < loop.vertices.Count - 1; i++)
            {
                triangles.Add(new Triangle(loop.vertices[0], loop.vertices[i], loop.vertices[(i + 1) % loop.vertices.Count]));
            }

            return(triangles);
        }
Example #3
0
        public bool LiesWithinLoop(EdgeLoop loop)
        {
            //Debug.Log("kjshfd");


            // collect intersection points
            Vector3        castDirection         = (loop.vertices[0].value - loop.vertices[1].value).normalized;
            List <Vector3> positiveIntersections = new List <Vector3>();
            List <Vector3> negativeIntersections = new List <Vector3>();

            for (int i = 0; i < loop.vertices.Count; i++)
            {
                Point3 intersection = IntersectLineWithEdge(
                    this.value,
                    castDirection,
                    loop.vertices[i].value,
                    loop.vertices[(i + 1) % loop.vertices.Count].value);
                if (intersection != null)
                {
                    Vector3 directionToIntersection = (intersection.value - this.value).normalized;
                    //Debug.Log("found intersection");
                    if (Vector3.Dot(directionToIntersection, castDirection) == 1)
                    {
                        positiveIntersections.Add(intersection.value);
                    }
                    else
                    {
                        negativeIntersections.Add(intersection.value);
                    }
                }
            }

            // remove duplicates
            RemoveDuplicates(positiveIntersections);
            RemoveDuplicates(negativeIntersections);

            // count # above, below
            // if both odd, return true, else return false
            return(positiveIntersections.Count % 2 == 1 && negativeIntersections.Count % 2 == 1);
        }
Example #4
0
        private EdgeLoop DiscoverInternalLoop(Vertex initialVertex, List <Vertex> unusedVertices, List <EdgeLoop> loops)
        {
            //TODO: discovery of loops
            Queue <EdgeLoop> potentialLoops = new Queue <EdgeLoop>();
            List <EdgeLoop>  completedLoops = new List <EdgeLoop>();

            potentialLoops.Enqueue(new EdgeLoop());
            potentialLoops.Peek().vertices.Add(initialVertex);
            int k = 0;

            Debug.Log("before");
            while (potentialLoops.Count > 0)
            {
                Debug.Log("as");
                Vertex nextVertex;
                do
                {
                    nextVertex = null;
                    // foundNext = false;
                    //Debug.Log(potentialLoops.Count);
                    List <Vertex> loopVertices = potentialLoops.Peek().vertices;
                    for (int i = unusedVertices.Count - 1; i >= 0; i--)
                    {
                        if (unusedVertices[i].SharesTriangle(loopVertices[loopVertices.Count - 1]) &&
                            !loopVertices.Contains(unusedVertices[i]))
                        {
                            if (nextVertex == null)
                            {
                                Debug.Log("found next in path");
                                nextVertex = unusedVertices[i];
                            }
                            else
                            {
                                Debug.Log("found additional possible path");
                                EdgeLoop newLoop = new EdgeLoop(potentialLoops.Peek().vertices);
                                //Debug.Log(newLoop.vertices);
                                potentialLoops.Enqueue(newLoop);
                                foreach (EdgeLoop vertex in potentialLoops)
                                {
                                    //Debug.Log(vertex);
                                }
                            }
                            k++;
                            if (k > 100)
                            {
                                throw new System.Exception();
                            }
                            //unusedVertices.RemoveAt(i);
                            //initialVertex = unusedVertices[i];
                            //foundNext = true;
                        }
                    }
                    if (nextVertex != null)
                    {
                        Debug.Log(nextVertex.value);
                        loopVertices.Add(nextVertex);

                        Debug.Log(loopVertices.Count);
                        Debug.Log(potentialLoops.Peek().vertices.Count);
                    }
                } while (nextVertex != null);
                completedLoops.Add(potentialLoops.Dequeue());
            }

            // Debug.Log(potentialLoops.Peek().vertices.Count);

            // the loop with the greatest number of vertices is the correct loop
            EdgeLoop finalLoop = completedLoops[0];

            foreach (EdgeLoop loop in completedLoops)
            {
                if (loop.vertices.Count > finalLoop.vertices.Count)
                {
                    finalLoop = loop;
                }
            }
            Debug.Log(finalLoop.vertices.Count);

            // determine which external loop contains this new loop
            foreach (EdgeLoop loop in loops)
            {
                if (initialVertex.LiesWithinLoop(loop))
                {
                    if (loop.nestedLoop == null)
                    {
                        loop.nestedLoop = finalLoop;
                    }
                    else
                    {
                        finalLoop.nestedLoop = loop.nestedLoop;
                        EdgeLoop previousLoop = loop;
                        do
                        {
                            if (initialVertex.LiesWithinLoop(finalLoop.nestedLoop))
                            {
                                previousLoop.nestedLoop            = finalLoop.nestedLoop;
                                finalLoop.nestedLoop               = finalLoop.nestedLoop.nestedLoop;
                                previousLoop.nestedLoop.nestedLoop = finalLoop;
                            }
                            else
                            {
                                break;
                            }
                        } while (finalLoop.nestedLoop != null);
                    }

                    // we've found the loop we're contained by, break out
                    break;
                }
            }

            return(finalLoop);
        }
Example #5
0
        // classify existing verticies
        // perform new cut operation on each face of the bounded shape
        // add back to mesh

        public Mesh ClipAToB(GameObject toClip, GameObject bounds, GameObject result, bool flipNormals = false)
        {
            //Debug.Log("hello");
            // get a list of all triangles of the bounding mesh
            List <Triangle> boundsTriangles = GetBoundsTriangles(toClip, bounds);

            // get a list of all vertices of the clipping target
            List <Vertex> vertices = ClassifyVertices(toClip, bounds, boundsTriangles);

            // get a list of all triangles of the clipping target
            List <Triangle> meshTriangles = GetAllTriangles(toClip, vertices);

            // here is where the final triangles will be stored
            List <Triangle> triangles = new List <Triangle>();

            // to create the triangles, we'll need a list of edge loops to triangluate
            List <EdgeLoop> edgeLoops = new List <EdgeLoop>();

            //TODO: this is debug code that I need for now
            // fill the edge loops that need to be filled, add the result to the list of triangles
            if (triangleCount > -1 && triangleCount < meshTriangles.Count)
            {
                edgeLoops.AddRange(ClipTriangleToBound(meshTriangles[triangleCount], boundsTriangles, vertices, true));
                foreach (EdgeLoop loop in edgeLoops)
                {
                    if (loop.filled)
                    {
                        triangles.AddRange(TriangulateEdgeLoop(loop));
                    }
                    EdgeLoop nestedLoop = loop.nestedLoop;
                    while (nestedLoop != null)
                    {
                        if (nestedLoop.filled)
                        {
                            triangles.AddRange(TriangulateEdgeLoop(nestedLoop));
                        }
                        nestedLoop = nestedLoop.nestedLoop;
                    }
                }
            }
            else if (triangleCount < meshTriangles.Count)
            {
                foreach (Triangle triangle in meshTriangles)
                {
                    edgeLoops.AddRange(ClipTriangleToBound(triangle, boundsTriangles, vertices));
                }

                foreach (EdgeLoop loop in edgeLoops)
                {
                    if (loop.filled)
                    {
                        triangles.AddRange(TriangulateEdgeLoop(loop));
                    }
                    EdgeLoop nestedLoop = loop.nestedLoop;
                    while (nestedLoop != null)
                    {
                        if (nestedLoop.filled)
                        {
                            triangles.AddRange(TriangulateEdgeLoop(nestedLoop));
                        }
                        nestedLoop = nestedLoop.nestedLoop;
                    }
                }
            }
            else
            {
                return(null);
            }

            if (flipNormals)
            {
                foreach (Triangle triangle in triangles)
                {
                    triangle.FlipNormal();
                }
            }

            Mesh completedMesh = new Mesh();

            result.GetComponent <MeshFilter>().mesh = completedMesh;

            // reindex vertices and add them to the mesh
            List <Vector3> createdVertices = new List <Vector3>();

            // add vertices to mesh
            for (int i = 0; i < vertices.Count; i++)
            {
                vertices[i].index = i;
                createdVertices.Add(vertices[i].value);
            }
            completedMesh.SetVertices(createdVertices);

            // add triangles to mesh
            int[] newTriangles = new int[triangles.Count * 3];
            int   index        = 0;

            foreach (Triangle triangle in triangles)
            {
                foreach (Vertex vertex in triangle.vertices)
                {
                    if (!vertices.Contains(vertex))
                    {
                        Debug.Log("Vertex " + vertex + " not contained in vertices, :: " + vertex.containedByBound);
                    }
                }
            }

            //Debug.Log(triangles.Count);

            foreach (Triangle triangle in triangles)
            {
                newTriangles[index] = triangle.vertices[0].index;
                index++;
                newTriangles[index] = triangle.vertices[1].index;
                index++;
                newTriangles[index] = triangle.vertices[2].index;
                index++;
            }

            completedMesh.SetTriangles(newTriangles, 0);

            completedMesh.RecalculateTangents();
            completedMesh.RecalculateNormals();

            return(completedMesh);
        }
Example #6
0
        private List <EdgeLoop> ClipTriangleToBound(Triangle triangle, List <Triangle> boundsTriangles, List <Vertex> vertices, bool debug = false)
        {
            List <Egress> aToBEgresses          = new List <Egress>();
            List <Egress> bToCEgresses          = new List <Egress>();
            List <Egress> cToAEgresses          = new List <Egress>();
            List <Vertex> internalIntersections = new List <Vertex>();

            // find all intersections between the triangle and the bound
            foreach (Triangle boundsTriangle in boundsTriangles)
            {
                IntersectTriangleEdge(triangle.vertices[0].value, triangle.vertices[1].value, aToBEgresses, boundsTriangle, debug);
                IntersectTriangleEdge(triangle.vertices[1].value, triangle.vertices[2].value, bToCEgresses, boundsTriangle, debug);
                IntersectTriangleEdge(triangle.vertices[2].value, triangle.vertices[0].value, cToAEgresses, boundsTriangle, debug);
                internalIntersections.AddRange(FindTriangleIntersections(boundsTriangle, triangle));

                if (debug)
                {
                    foreach (Vertex intersection in internalIntersections)
                    {
                        Debug.DrawRay(transform.localToWorldMatrix.MultiplyPoint3x4(intersection.value), Vector3.back * 0.1f, Color.green, Time.deltaTime);
                    }
                }
            }

            if (debug)
            {
                foreach (Vertex vertex in triangle.vertices)
                {
                    Color color = Color.blue;
                    if (vertex.containedByBound)
                    {
                        color = Color.cyan;
                    }
                    Debug.DrawRay(transform.localToWorldMatrix.MultiplyPoint3x4(vertex.value), Vector3.back * 0.1f, color, Time.deltaTime);
                }
            }

            List <Egress> allEgresses = new List <Egress>();

            allEgresses.AddRange(aToBEgresses);
            allEgresses.AddRange(bToCEgresses);
            allEgresses.AddRange(cToAEgresses);

            // combine duplicate internal intersections
            for (int i = internalIntersections.Count - 1; i > 0; i--)
            {
                for (int k = i - 1; k >= 0; k--)
                {
                    if (Vector3.Distance(internalIntersections[i].value, internalIntersections[k].value) < intersectionError)
                    {
                        internalIntersections[k].triangles.AddRange(internalIntersections[i].triangles);
                        internalIntersections.RemoveAt(i);
                        break;
                    }
                }
            }

            // store the resulting intersections in the greater vertex list
            vertices.AddRange(aToBEgresses);
            vertices.AddRange(bToCEgresses);
            vertices.AddRange(cToAEgresses);
            vertices.AddRange(internalIntersections);

            // organize the intersections into cuts
            CreateCuts(allEgresses, internalIntersections);

            //TODO: soon. deal with floating islands by collecting up loops without egresses
            // (they won't be a part of any cuts)

            // organize all triangle vertices and egress intersections in an ordered list around the perimeter
            List <Vertex> perimeter = new List <Vertex>();

            aToBEgresses.Sort((a, b) => (int)Mathf.Sign(Vector3.Distance(a.value, triangle.vertices[0].value) - Vector3.Distance(b.value, triangle.vertices[0].value)));
            bToCEgresses.Sort((a, b) => (int)Mathf.Sign(Vector3.Distance(a.value, triangle.vertices[1].value) - Vector3.Distance(b.value, triangle.vertices[1].value)));
            cToAEgresses.Sort((a, b) => (int)Mathf.Sign(Vector3.Distance(a.value, triangle.vertices[2].value) - Vector3.Distance(b.value, triangle.vertices[2].value)));

            perimeter.Add(triangle.vertices[0]);
            perimeter.AddRange(aToBEgresses);
            perimeter.Add(triangle.vertices[1]);
            perimeter.AddRange(bToCEgresses);
            perimeter.Add(triangle.vertices[2]);
            perimeter.AddRange(cToAEgresses);
            perimeter.Add(triangle.vertices[0]);// a duplicate of the first vertex as a sentinel


            // find all edge loops and classify whether they should be retopologized or not

            List <EdgeLoop> loops = new List <EdgeLoop>();

            // while there are still entries in that list for which we haven't identified all loops (1 for triangle vertices, 2 for egresses)
            //Debug.Log("Beginning classification of edge loops");
            foreach (Vertex vertex in triangle.vertices)
            {
                vertex.loops = new List <EdgeLoop>();
            }

            while (true)
            {
                // find the earliest entry whose loops aren't satisfied
                int currentVertexIndex = 0;
                //Debug.Log("~~FINDING NEW STARTING POINT~~");
                for (currentVertexIndex = 0; currentVertexIndex < perimeter.Count - 2; currentVertexIndex++)
                {
                    //Debug.Log("Index: " + currentVertexIndex + ", Is Egress = " + (perimeter[currentVertexIndex] is Egress) + ", loop count: " + perimeter[currentVertexIndex].loops.Count);

                    // for egresses:
                    if (perimeter[currentVertexIndex] is Egress)
                    {
                        //Debug.Log(((Egress)perimeter[currentVertexIndex]).cuts.Count);

                        // if this one is unsatisfied, break. We've found the earliest
                        if (perimeter[currentVertexIndex].loops.Count < ((Egress)perimeter[currentVertexIndex]).cuts.Count + 1)
                        {
                            break;
                        }
                    }
                    else // for original vertices
                    {
                        // if this one is unsatisfied, break. We've found the earliest
                        if (perimeter[currentVertexIndex].loops.Count < 1)
                        {
                            break;
                        }
                    }
                }

                string parString = "perimeter:";
                foreach (Vertex vertex in perimeter)
                {
                    parString += " " + perimeter.IndexOf(vertex) + ": (" + (vertex is Egress) + ")" + vertex.value;
                }
                //Debug.Log(parString);
                //Debug.Log("finished with: " + currentVertexIndex);
                //Debug.Log("perimeter size: " + perimeter.Count);

                // we've satisfied all loops, which is our exit condition
                if (currentVertexIndex == perimeter.Count - 2)
                {
                    break;
                }

                // now that we've found the beginning of a loop, it's time to find the rest
                Vertex initialVertex = perimeter[currentVertexIndex];

                // determine whether this loop should be filled or not
                EdgeLoop loop = new EdgeLoop();

                // the loop defines either a surface or a hole, and we can determine that by looking at our starting entry
                // the starting entry can be one of two cases:
                // 1. an egress which is already part of one loop
                if (initialVertex is Egress)
                {
                    // in this case, the new loop is the opposite of whatever the previous loop is
                    loop.filled = !initialVertex.loops[initialVertex.loops.Count - 1].filled;

                    // also, if the initial vertex is an egress, we should add it and move on to the next perimeter value,
                    // so as not to traverse backwards along the cut

                    /*Cut furthestCut = ((Egress)initialVertex).GetFurthestCut(perimeter);
                     *
                     * loop.vertices.Add(perimeter[currentVertexIndex]);
                     * perimeter[currentVertexIndex].loops.Add(loop);
                     * currentVertexIndex++;*/
                }
                else // 2. a vertex of the original triangle
                {
                    // in this case, if the vertex is contained by the bound, the loop is a surface, otherwise it's a hole
                    loop.filled = initialVertex.containedByBound;
                }

                // traverse forward in the ordered list, following each cut, until we reach the initial point
                // once the inital entry is reached again, we have identified a loop, and can add it to the pile
                int tooMuch = 0;
                //Debug.Log("starting new loop");
                do
                {
                    // if the current vertex is an egress
                    tooMuch++;
                    if (tooMuch > 100)
                    {
                        Debug.Log("too long");
                        throw new System.ApplicationException();
                        break;
                    }

                    //Debug.Log(currentVertexIndex);

                    Cut furthestCut = null;

                    if (perimeter[currentVertexIndex] is Egress)
                    {
                        furthestCut = ((Egress)perimeter[currentVertexIndex]).GetFurthestCut(perimeter);
                    }

                    if (furthestCut != null)
                    {
                        currentVertexIndex = TraverseCut(furthestCut, loop, perimeter, currentVertexIndex);

                        if (perimeter[currentVertexIndex] == initialVertex)// if we arrived at the initial vertex
                        {
                            loop.vertices.RemoveAt(loop.vertices.Count - 1);
                            break;
                        }

                        // if there's more than one cut on the vertex, we need to potentially
                        while (((Egress)perimeter[currentVertexIndex]).cuts.Count > 1)
                        {
                            //Debug.Log("Double traversal");
                            // select cut
                            Cut toIgnore = null;
                            foreach (Cut cut in ((Egress)perimeter[currentVertexIndex]).cuts)
                            {
                                if (cut[cut.Count - 1] == furthestCut[0])
                                {
                                    toIgnore = cut;
                                    break;
                                }
                            }
                            furthestCut = ((Egress)perimeter[currentVertexIndex]).GetFurthestCut(perimeter, toIgnore, currentVertexIndex, perimeter.IndexOf(initialVertex));

                            if (furthestCut != null)
                            {
                                currentVertexIndex = TraverseCut(furthestCut, loop, perimeter, currentVertexIndex);
                            }
                            else
                            {
                                //Debug.Log("Couldn't find double traversal");
                                break;
                            }

                            if (perimeter[currentVertexIndex] == initialVertex)// if we arrived at the initial vertex
                            {
                                loop.vertices.RemoveAt(loop.vertices.Count - 1);
                                goto EndOfDoWhile;
                            }
                        }
                    }
                    else
                    {
                        // add current vertex to loop
                        loop.vertices.Add(perimeter[currentVertexIndex]);
                        perimeter[currentVertexIndex].loops.Add(loop);
                    }

                    // increment the current index by 1
                    currentVertexIndex++;

                    if (currentVertexIndex >= perimeter.Count)
                    {
                        string listString = "";
                        foreach (Vertex vertex in loop.vertices)
                        {
                            listString += " " + perimeter.IndexOf(vertex);
                        }
                        Debug.Log("Failed to create loop, (Filled: " + loop.filled + ") :: " + listString);
                    }
                    // once the current vertex loops around to the start, we're done
                } while (perimeter[currentVertexIndex] != initialVertex);
EndOfDoWhile:

                //Debug.Log("terminated");
                loops.Add(loop);
            }
            if (debug)
            {
                foreach (EdgeLoop loop in loops)
                {
                    string listString = "";
                    foreach (Vertex vertex in loop.vertices)
                    {
                        listString += " " + perimeter.IndexOf(vertex);
                    }
                    Debug.Log("Created loop, (Filled: " + loop.filled + ") :: " + listString);
                }
            }

            // now that we've created all loops that intersect the edge of the triangle, we can start on loops that float as islands
            List <Vertex> unusedVertices = new List <Vertex>();

            foreach (Vertex intersection in internalIntersections)
            {
                if (!intersection.usedInLoop)
                {
                    unusedVertices.Add(intersection);
                }
            }

            Debug.Log(unusedVertices.Count);
            while (unusedVertices.Count > 0)
            {
                Vertex currentVertex = unusedVertices[unusedVertices.Count - 1];
                unusedVertices.RemoveAt(unusedVertices.Count - 1);
                DiscoverInternalLoop(currentVertex, unusedVertices, loops);
            }

            foreach (EdgeLoop loop in loops)
            {
                EdgeLoop nestedLoop   = loop.nestedLoop;
                EdgeLoop previousLoop = loop;
                while (nestedLoop != null)
                {
                    nestedLoop.filled = !previousLoop.filled;
                    previousLoop      = nestedLoop;
                    nestedLoop        = nestedLoop.nestedLoop;
                }
            }


            return(loops);
        }