Пример #1
0
            IList <IndexSegment> setupEdges(IList <int> vertxIndices)
            {
                IList <IndexSegment> indexList = new List <IndexSegment>();
                int boundLinesDictOffset       = 0;

                if (boundaryLinesDict == null)
                {
                    IEqualityComparer <IndexSegment> segCompare = new SegmentComparer(false /*compareBothDirections*/);
                    boundaryLinesDict = new Dictionary <IndexSegment, int>(segCompare);
                }
                else
                {
                    boundLinesDictOffset = boundaryLinesDict.Count();
                }

                for (int ii = 0; ii < vertxIndices.Count; ++ii)
                {
                    IndexSegment segm;
                    if (ii == vertxIndices.Count - 1)
                    {
                        segm = new IndexSegment(vertxIndices[ii], vertxIndices[0]);
                    }
                    else
                    {
                        segm = new IndexSegment(vertxIndices[ii], vertxIndices[ii + 1]);
                    }
                    indexList.Add(segm);
                    boundaryLinesDict.Add(segm, ii + boundLinesDictOffset);  // boundaryLinesDict is a dictionary for the combined outer and inner boundaries, the values should be sequential
                }

                return(indexList);
            }
Пример #2
0
        void SetupEdges(IList <int> vertxIndices, int idxOffset)
        {
            int boundLinesDictOffset = 0;

            if (BoundaryLinesDict == null)
            {
                IEqualityComparer <IndexSegment> segCompare = new SegmentComparer(false /*compareBothDirections*/);
                BoundaryLinesDict = new Dictionary <IndexSegment, int>(segCompare);
            }
            else
            {
                boundLinesDictOffset = BoundaryLinesDict.Count();
            }

            int prevIdx   = 0;
            int idx       = 0;
            int vertCount = vertxIndices.Count;

            foreach (int vIdx in vertxIndices)
            {
                IndexSegment segm = null;
                if (idx > 0)
                {
                    segm = new IndexSegment(prevIdx, vIdx);
                    OuterAndInnerBoundaries.Add(idx - 1 + idxOffset, segm);
                    BoundaryLinesDict.Add(segm, (idx - 1 + boundLinesDictOffset)); // boundaryLinesDict is a dictionary for the combined outer and inner boundaries, the values should be sequential
                }
                if (idx == vertCount - 1)                                          // The last index. Close the loop by connecing it to the first index
                {
                    segm = new IndexSegment(vIdx, vertxIndices[0]);
                    OuterAndInnerBoundaries.Add((idx + idxOffset), segm);
                    BoundaryLinesDict.Add(segm, (idx + boundLinesDictOffset));  // boundaryLinesDict is a dictionary for the combined outer and inner boundaries, the values should be sequential
                }
                prevIdx = vIdx;
                idx++;
            }
        }
Пример #3
0
        /// <summary>
        /// Go through the input face list that share the same vertex and has the same normal (coplannar).
        /// </summary>
        /// <param name="inputFaceList"></param>
        /// <param name="outputFaceList"></param>
        /// <returns>True if done successfully</returns>
        void TryMergeFaces(List <int> inputFaceList, out List <int> outputFaceList)
        {
            outputFaceList = new List <int>();
            IndexFace firstF       = m_FacesCollDict[inputFaceList[0]];
            int       currProcFace = inputFaceList[0];

            inputFaceList.RemoveAt(0); // remove the first face from the list
            bool merged = false;

            IEqualityComparer <IndexSegment> segCompare = new SegmentComparer(false /*compareBothDirections*/);
            IDictionary <IndexSegment, Tuple <int, int> > segmentOfFaceDict = new Dictionary <IndexSegment, Tuple <int, int> >(segCompare);
            IList <int> discardList = new List <int>();

            foreach (int fidx in inputFaceList)
            {
                if (!SegmentOfFaceToDict(ref segmentOfFaceDict, fidx))
                {
                    discardList.Add(fidx);
                }
            }

            // Remove bad face from the input list, if any
            if (discardList.Count > 0)
            {
                foreach (int fidx in discardList)
                {
                    inputFaceList.Remove(fidx);
                }
            }
            discardList.Clear();

            while (inputFaceList.Count > 0)
            {
                IndexFace mergedFace = null;
                for (int currEdgeIdx = 0; currEdgeIdx < firstF.OuterAndInnerBoundaries.Count; currEdgeIdx++)
                {
                    IndexSegment currEdge     = firstF.OuterAndInnerBoundaries[currEdgeIdx];
                    IndexSegment reversedEdge = currEdge.Reverse();

                    IndexFace        currFace    = null;
                    int              currFaceIdx = -1;
                    int              idx         = -1;
                    Tuple <int, int> pairedFace  = null;

                    if (!segmentOfFaceDict.TryGetValue(reversedEdge, out pairedFace))
                    {
                        if (!segmentOfFaceDict.TryGetValue(currEdge, out pairedFace))
                        {
                            merged = false;
                            continue;
                        }
                        else
                        {
                            currFaceIdx = pairedFace.Item1;
                            currFace    = m_FacesCollDict[currFaceIdx];

                            // Need to reverse the face boundaries. Remove the entries in the Dict first, reverse the face, and add them back
                            for (int cidx = 0; cidx < currFace.OuterAndInnerBoundaries.Count; ++cidx)
                            {
                                segmentOfFaceDict.Remove(currFace.OuterAndInnerBoundaries[cidx]);
                            }
                            currFace.Reverse();
                            if (!SegmentOfFaceToDict(ref segmentOfFaceDict, currFaceIdx))
                            {
                                // Something is wrong with this face (should not be here in the normal circumstance), discard it and continue
                                inputFaceList.Remove(currFaceIdx);
                                merged = false;
                                continue;
                            }
                            if (!segmentOfFaceDict.TryGetValue(reversedEdge, out pairedFace))
                            {
                                if (!segmentOfFaceDict.TryGetValue(currEdge, out pairedFace))
                                {
                                    // Should not be here. If somehow here, discard the face and continue
                                    inputFaceList.Remove(currFaceIdx);
                                    merged = false;
                                    continue;
                                }
                            }
                            idx = pairedFace.Item2;
                        }
                    }
                    else
                    {
                        currFaceIdx = pairedFace.Item1;
                        currFace    = m_FacesCollDict[currFaceIdx];
                        idx         = pairedFace.Item2;
                    }

                    // Now we need to check other edges of this face whether there is other coincide edge (this is in the case of hole(s))
                    List <int> fFaceIdxList    = new List <int>();
                    List <int> currFaceIdxList = new List <int>();
                    int        ci = -1;
                    foreach (KeyValuePair <int, IndexSegment> idxSeg in currFace.OuterAndInnerBoundaries)
                    {
                        ci++;
                        if (ci == idx)
                        {
                            continue; // skip already known coincide edge
                        }
                        int          ffIdx = -1;
                        IndexSegment reL   = new IndexSegment(idxSeg.Value.EndPIndex, idxSeg.Value.StartPindex);
                        ffIdx = firstF.FindMatchedIndexSegment(reL);
                        if (ffIdx > 0)
                        {
                            fFaceIdxList.Add(ffIdx); // List of edges to skip when merging
                            currFaceIdxList.Add(ci); // List of edges to skip when merging
                        }
                    }

                    // Now we will remove the paired edges and merge the faces
                    List <IndexSegment> newFaceEdges = new List <IndexSegment>();
                    for (int ii = 0; ii < currEdgeIdx; ii++)
                    {
                        bool toSkip = false;
                        if (fFaceIdxList.Count > 0)
                        {
                            toSkip = fFaceIdxList.Contains(ii);
                        }
                        if (!toSkip)
                        {
                            newFaceEdges.Add(firstF.OuterAndInnerBoundaries[ii]); // add the previous edges from the firstF faces first. This will skip the currEdge
                        }
                    }

                    // Add the next-in-sequence edges from the second face
                    for (int ii = idx + 1; ii < currFace.OuterAndInnerBoundaries.Count; ii++)
                    {
                        bool toSkip = false;
                        if (currFaceIdxList.Count > 0)
                        {
                            toSkip = currFaceIdxList.Contains(ii);
                        }
                        if (!toSkip)
                        {
                            newFaceEdges.Add(currFace.OuterAndInnerBoundaries[ii]);
                        }
                    }
                    for (int ii = 0; ii < idx; ii++)
                    {
                        bool toSkip = false;
                        if (currFaceIdxList.Count > 0)
                        {
                            toSkip = currFaceIdxList.Contains(ii);
                        }
                        if (!toSkip)
                        {
                            newFaceEdges.Add(currFace.OuterAndInnerBoundaries[ii]);
                        }
                    }

                    for (int ii = currEdgeIdx + 1; ii < firstF.OuterAndInnerBoundaries.Count; ii++)
                    {
                        bool toSkip = false;
                        if (fFaceIdxList.Count > 0)
                        {
                            toSkip = fFaceIdxList.Contains(ii);
                        }
                        if (!toSkip)
                        {
                            newFaceEdges.Add(firstF.OuterAndInnerBoundaries[ii]);
                        }
                    }

                    // Build a new face
                    // Important to note that the list of edges may not be continuous if there is a hole. We need to go through the list here to identify whether there is any such
                    //   discontinuity and collect the edges into their respective loops
                    List <List <IndexSegment> > loops = new List <List <IndexSegment> >();

                    List <IndexSegment> loopEdges = new List <IndexSegment>();
                    loops.Add(loopEdges);

                    IndexSegment prevSegm = newFaceEdges[0];
                    foreach (IndexSegment idxSeg in newFaceEdges)
                    {
                        if (prevSegm == idxSeg)
                        {
                            loopEdges.Add(idxSeg);
                        }
                        else
                        {
                            if (idxSeg.StartPindex == prevSegm.EndPIndex)
                            {
                                loopEdges.Add(idxSeg);
                            }
                            else
                            {
                                // Discontinuity detected
                                loopEdges = new List <IndexSegment>(); // start new loop
                                loops.Add(loopEdges);
                                loopEdges.Add(idxSeg);
                            }
                        }
                        prevSegm = idxSeg;
                    }

                    List <List <IndexSegment> > finalLoops = new List <List <IndexSegment> >();
                    {
                        while (loops.Count > 1)
                        {
                            // There are more than 1 loops, need to consolidate if there are fragments to combine due to their continuity between the fragments
                            int toDelIdx = -1;
                            for (int ii = 1; ii < loops.Count; ii++)
                            {
                                if (loops[0][loops[0].Count - 1].EndPIndex == loops[ii][0].StartPindex)
                                {
                                    // found continuity, merge the loops
                                    List <IndexSegment> newLoop = new List <IndexSegment>(loops[0]);
                                    newLoop.AddRange(loops[ii]);
                                    finalLoops.Add(newLoop);
                                    toDelIdx = ii;
                                    break;
                                }
                            }
                            if (toDelIdx > 0)
                            {
                                loops.RemoveAt(toDelIdx); // !!!! Important to remove the later member first before removing the first one
                                loops.RemoveAt(0);
                            }
                            else
                            {
                                // No continuity found, copy the first loop to the final loop
                                List <IndexSegment> newLoop = new List <IndexSegment>(loops[0]);
                                finalLoops.Add(newLoop);
                                loops.RemoveAt(0);
                            }
                        }
                        if (loops.Count > 0)
                        {
                            // Add remaining list into the final loops
                            finalLoops.AddRange(loops);
                        }
                    }

                    if (finalLoops.Count > 1)
                    {
                        // Find the largest loop and put it in the first position signifying the outer loop and the rest are the inner loops
                        int    largestPerimeterIdx = 0;
                        double largestPerimeter    = 0.0;
                        for (int i = 0; i < finalLoops.Count; i++)
                        {
                            double loopPerimeter = 0.0;
                            foreach (IndexSegment line in finalLoops[i])
                            {
                                loopPerimeter += line.Extent(ref m_MeshVertices);
                            }
                            if (loopPerimeter > largestPerimeter)
                            {
                                largestPerimeter    = loopPerimeter;
                                largestPerimeterIdx = i;
                            }
                        }
                        // We need to move the largest loop into the head if it is not
                        if (largestPerimeterIdx > 0)
                        {
                            List <IndexSegment> largestLoop = new List <IndexSegment>(finalLoops[largestPerimeterIdx]);
                            finalLoops.RemoveAt(largestPerimeterIdx);
                            finalLoops.Insert(0, largestLoop);
                        }
                    }

                    // Collect the vertices from the list of Edges into list of list of vertices starting with the outer loop (largest loop) following the finalLoop
                    IList <IList <int> > newFaceVertsLoops = new List <IList <int> >();
                    foreach (List <IndexSegment> loop in finalLoops)
                    {
                        IList <int> newFaceVerts = new List <int>();
                        foreach (IndexSegment idxSeg in loop)
                        {
                            newFaceVerts.Add(idxSeg.StartPindex);
                        }

                        if (newFaceVerts.Count > 0)
                        {
                            if (newFaceVerts.Count >= 3)
                            {
                                newFaceVertsLoops.Add(newFaceVerts);
                            }
                            else
                            {
                                // Something wrong, a face cannot have less than 3 vertices
                                Debug.WriteLine("Something went wrong when merging faces resulting with a loop that has less than 3 vertices");
                            }
                        }
                    }

                    mergedFace = new IndexFace(newFaceVertsLoops, ref m_MeshVertices);
                    inputFaceList.Remove(currFaceIdx);

                    // Remove the merged face from segmentOfFaceDict
                    foreach (KeyValuePair <int, IndexSegment> idxSeg in m_FacesCollDict[currFaceIdx].OuterAndInnerBoundaries)
                    {
                        segmentOfFaceDict.Remove(idxSeg.Value);
                    }
                    if (m_FacesCollDict.ContainsKey(currFaceIdx))
                    {
                        m_FacesCollDict.Remove(currFaceIdx);
                    }

                    merged = true;
                    break; // Once there is an edge merged, create a new face and continue the process of merging
                }

                int lastFaceID = faceIdxOffset++; // The new index is always the next one in the collection was inserted based on the seq order
                if (mergedFace != null)
                {
                    m_FacesCollDict.Add(lastFaceID, mergedFace);
                }

                if (!merged)
                {
                    // No edge match for this face, add the face into the output face list and move to the next face in the input list
                    outputFaceList.Add(currProcFace);

                    if (inputFaceList.Count > 0)
                    {
                        firstF = m_FacesCollDict[inputFaceList[0]];

                        // Remove the merged face from segmentOfFaceDict
                        foreach (KeyValuePair <int, IndexSegment> idxSeg in firstF.OuterAndInnerBoundaries)
                        {
                            segmentOfFaceDict.Remove(idxSeg.Value);
                        }
                        currProcFace = inputFaceList[0]; // keep the last processed item
                        inputFaceList.RemoveAt(0);       // remove the first face from the list
                        merged = false;

                        // If there is no more face to process, add the merged face into the output list
                        if (inputFaceList.Count == 0)
                        {
                            outputFaceList.Add(currProcFace);
                        }
                    }
                }
                else
                {
                    // If there is no more face to process, add the merged face into the output list
                    if (inputFaceList.Count == 0)
                    {
                        outputFaceList.Add(lastFaceID);
                    }

                    // Remove merged face from the Dict
                    if (m_FacesCollDict.ContainsKey(currProcFace))
                    {
                        m_FacesCollDict.Remove(currProcFace);
                    }

                    if (inputFaceList.Count > 0)
                    {
                        // use the current face as the next face as a merge candidate
                        firstF       = mergedFace;
                        currProcFace = lastFaceID;
                        merged       = false;
                    }
                }
            }

            // Finally, there may be multiple faces left because there are multiple disconnected faces at the same normal. Collect them and return
            if (segmentOfFaceDict.Count > 0)
            {
                HashSet <int> indexFaces = new HashSet <int>();
                foreach (KeyValuePair <IndexSegment, Tuple <int, int> > segmentFace in segmentOfFaceDict)
                {
                    indexFaces.Add(segmentFace.Value.Item1);
                }
                foreach (int idxFace in indexFaces)
                {
                    outputFaceList.Add(idxFace);
                }
            }
        }