예제 #1
0
            IList <IndexSegment> setupEdges(IList <int> vertxIndices)
            {
                IList <IndexSegment> indexList = new List <IndexSegment>();
                int boundLinesDictOffset       = 0;

                if (boundaryLinesDict == null)
                {
                    IEqualityComparer <IndexSegment> segCompare = new SegmentCompare();
                    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
        /// <summary>
        /// Find matched line segment in the face boundaries
        /// </summary>
        /// <param name="inpSeg">Input line segment as vertex indices</param>
        /// <returns>Return index of the matched segment</returns>
        public int FindMatchedIndexSegment(IndexSegment inpSeg)
        {
            int idx;

            if (BoundaryLinesDict.TryGetValue(inpSeg, out idx))
            {
                return(idx);
            }
            else
            {
                return(-1);
            }
        }
예제 #3
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++;
            }
        }
예제 #4
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);
                }
            }
        }
예제 #5
0
 /// <summary>
 /// Test whether a line segment coincides with this one (must be exactly the same start - end, or end - start)
 /// </summary>
 /// <param name="inputSegment">Line segment to test for coincidence</param>
 /// <param name="compareBothDirections">Whether to check if the input segment is the reverse of this one</param>
 /// <returns>True if coincide</returns>
 public bool Coincide(IndexSegment inputSegment, bool compareBothDirections)
 {
     return((StartPindex == inputSegment.StartPindex && EndPIndex == inputSegment.EndPIndex) ||
            (compareBothDirections && (EndPIndex == inputSegment.StartPindex && StartPindex == inputSegment.EndPIndex)));
 }
예제 #6
0
 /// <summary>
 /// Test whether a line segment coincides with this one (must be exactly the same start - end, or end - start)
 /// </summary>
 /// <param name="inputSegment"></param>
 /// <returns>True if coincide</returns>
 public bool coincide(IndexSegment inputSegment)
 {
     return((startPindex == inputSegment.startPindex && endPIndex == inputSegment.endPIndex) ||
            (endPIndex == inputSegment.startPindex && startPindex == inputSegment.endPIndex));
 }
예제 #7
0
 /// <summary>
 /// Test whether a line segment coincides with this one (must be exactly the same start - end, or end - start)
 /// </summary>
 /// <param name="inputSegment">Line segment to test for coincidence</param>
 /// <param name="compareBothDirections">Whether to check if the input segment is the reverse of this one</param>
 /// <returns>True if coincide</returns>
 public bool coincide(IndexSegment inputSegment, bool compareBothDirections)
 {
     return((startPindex == inputSegment.startPindex && endPIndex == inputSegment.endPIndex) ||
            (compareBothDirections && (endPIndex == inputSegment.startPindex && startPindex == inputSegment.endPIndex)));
 }
예제 #8
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>
        bool TryMergeFaces(List <int> inputFaceList, out List <int> outputFaceList)
        {
            outputFaceList = new List <int>();
            IndexFace firstF = facesColl[inputFaceList[0]];
            //int prevFirstFIdx = 0;
            HashSet <int> mergedFacesIdxList = new HashSet <int>();

            mergedFacesIdxList.Add(inputFaceList[0]);

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

            IEqualityComparer <IndexSegment> segCompare = new SegmentCompare();
            IDictionary <IndexSegment, Tuple <IndexFace, int, int> > segmentOfFaceDict = new Dictionary <IndexSegment, Tuple <IndexFace, int, int> >(segCompare);
            IList <int> discardList = new List <int>();

            for (int iFace = 0; iFace < inputFaceList.Count; ++iFace)
            {
                int       fidx    = inputFaceList[iFace];
                IndexFace IdxFace = facesColl[fidx];
                if (!segmentOfFaceToDict(ref segmentOfFaceDict, ref IdxFace, 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 (currEdgeIdx < firstF.outerAndInnerBoundaries.Count && inputFaceList.Count > 0)
            {
                IndexSegment currEdge     = firstF.outerAndInnerBoundaries[currEdgeIdx];
                IndexSegment reversedEdge = currEdge.reverse();

                {
                    IndexFace currFace    = null;
                    int       currFaceIdx = -1;
                    int       idx         = -1;
                    Tuple <IndexFace, int, int> pairedFace = null;
                    if (!segmentOfFaceDict.TryGetValue(reversedEdge, out pairedFace))
                    {
                        if (!segmentOfFaceDict.TryGetValue(currEdge, out pairedFace))
                        {
                            currEdgeIdx++;
                            merged = false;
                            continue;
                        }
                        else
                        {
                            currFace    = pairedFace.Item1;
                            currFaceIdx = pairedFace.Item2;

                            // 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, ref currFace, currFaceIdx))
                            {
                                // Something is wrong with this face (should not be here in the normal circumstance), discard it and continue
                                inputFaceList.Remove(currFaceIdx);
                                currEdgeIdx++;
                                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);
                                    currEdgeIdx++;
                                    merged = false;
                                    continue;
                                }
                            }
                            idx = pairedFace.Item3;
                        }
                    }
                    else
                    {
                        currFace    = pairedFace.Item1;
                        currFaceIdx = pairedFace.Item2;
                        idx         = pairedFace.Item3;
                    }

                    // 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>();
                    for (int ci = 0; ci < currFace.outerAndInnerBoundaries.Count; ci++)
                    {
                        if (ci == idx)
                        {
                            continue; // skip already known coincide edge
                        }
                        int          ffIdx = -1;
                        IndexSegment reL   = new IndexSegment(currFace.outerAndInnerBoundaries[ci].endPIndex, currFace.outerAndInnerBoundaries[ci].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);
                    for (int ii = 0; ii < newFaceEdges.Count; ii++)
                    {
                        if (ii == 0)
                        {
                            loopEdges.Add(newFaceEdges[ii]);
                        }
                        else
                        {
                            if (newFaceEdges[ii].startPindex == newFaceEdges[ii - 1].endPIndex)
                            {
                                loopEdges.Add(newFaceEdges[ii]);
                            }
                            else
                            {
                                // Discontinuity detected
                                loopEdges = new List <IndexSegment>(); // start new loop
                                loops.Add(loopEdges);
                                loopEdges.Add(newFaceEdges[ii]);
                            }
                        }
                    }

                    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;
                            }
                            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>();
                        for (int ii = 0; ii < loop.Count; ii++)
                        {
                            if (ii == 0)
                            {
                                newFaceVerts.Add(loop[ii].startPindex);
                                newFaceVerts.Add(loop[ii].endPIndex);
                            }
                            else if (ii == loop.Count - 1) // Last
                            {
                                // Add nothing as the last segment ends at the first vertex
                            }
                            else
                            {
                                newFaceVerts.Add(loop[ii].endPIndex);
                            }
                        }
                        // close the loop with end point from the starting point (it is important to mark the end of loop and if there is any other vertex follow, they start the inner loop)
                        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");
                            }
                        }
                    }

                    firstF = new IndexFace(newFaceVertsLoops);

                    currEdgeIdx  = 0;
                    reversedEdge = new IndexSegment(firstF.outerAndInnerBoundaries[currEdgeIdx].endPIndex, firstF.outerAndInnerBoundaries[currEdgeIdx].startPindex);

                    mergedFacesIdxList.Add(currFaceIdx);
                    inputFaceList.Remove(currFaceIdx);

                    // Remove the merged face from segmentOfFaceDict
                    IList <IndexSegment> rem = facesColl[currFaceIdx].outerAndInnerBoundaries;
                    for (int cidx = 0; cidx < rem.Count; ++cidx)
                    {
                        segmentOfFaceDict.Remove(rem[cidx]);
                    }

                    merged = true;
                }

                if (!merged)
                {
                    currEdgeIdx++;
                }
                if (merged || currEdgeIdx == firstF.outerAndInnerBoundaries.Count)
                {
                    int lastFaceID = facesColl.Count; // The new index is always the next one in the collection was inserted based on the seq order

                    facesColl.Add(lastFaceID, firstF);
                    //prevFirstFIdx = lastFaceID;

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

                    // Now loop through all the dictionary of the sortedVert and replace all merged face indexes with the new one
                    foreach (KeyValuePair <int, HashSet <int> > v in sortedFVert)
                    {
                        HashSet <int> fIndexes = v.Value;
                        bool          replaced = false;
                        foreach (int Idx in mergedFacesIdxList)
                        {
                            replaced |= fIndexes.Remove(Idx);
                            _mergedFaceList.Remove(Idx); // Remove the idx face also from _mergeFaceList as some faces might be left unmerged in the previous step(s)
                        }
                        if (replaced)
                        {
                            fIndexes.Add(lastFaceID); // replace the merged face indexes with the new merged face index
                        }
                    }

                    if (inputFaceList.Count > 0)
                    {
                        firstF = facesColl[inputFaceList[0]];
                        mergedFacesIdxList.Clear();
                        mergedFacesIdxList.Add(inputFaceList[0]);

                        // Remove the merged face from segmentOfFaceDict
                        IList <IndexSegment> rem = firstF.outerAndInnerBoundaries;
                        for (int cidx = 0; cidx < rem.Count; ++cidx)
                        {
                            segmentOfFaceDict.Remove(rem[cidx]);
                        }
                        inputFaceList.RemoveAt(0); // remove the first face from the list
                        currEdgeIdx = 0;
                        merged      = false;

                        // If there is still more face to process, add the merged face into the list to be processed futher
                        // Add new face to segmentOfFaceDict
                        IndexFace newFace = facesColl[lastFaceID];
                        if (segmentOfFaceToDict(ref segmentOfFaceDict, ref newFace, lastFaceID))
                        {
                            inputFaceList.Add(lastFaceID);
                        }
                    }
                }
            }

            return(merged);
        }