/// <summary> /// Add one loop of vertices that will define a boundary loop of the current face. /// </summary> /// <param name="id">The id of the IFCEntity, for error reporting.</param> /// <param name="loopVertices">The list of vertices.</param> /// <returns>True if the operation succeeded, false oherwise.</returns> public bool AddLoopVertices(int id, IList <XYZ> loopVertices) { int vertexCount = (loopVertices == null) ? 0 : loopVertices.Count; if (vertexCount < 3) { Importer.TheLog.LogComment(id, "Too few distinct loop vertices, ignoring.", false); return(false); } IList <XYZ> adjustedLoopVertices = new List <XYZ>(); IDictionary <IFCFuzzyXYZ, int> createdVertices = new SortedDictionary <IFCFuzzyXYZ, int>(); int numCreated = 0; for (int ii = 0; ii < vertexCount; ii++) { IFCFuzzyXYZ fuzzyXYZ = new IFCFuzzyXYZ(loopVertices[ii]); int createdVertexIndex = -1; if (createdVertices.TryGetValue(fuzzyXYZ, out createdVertexIndex)) { // We will allow the first and last point to be equivalent, or the current and last point. Otherwise we will throw. if (((createdVertexIndex == 0) && (ii == vertexCount - 1)) || (createdVertexIndex == numCreated - 1)) { continue; } Importer.TheLog.LogComment(id, "Loop is self-intersecting, ignoring.", false); return(false); } XYZ adjustedXYZ; if (!m_TessellatedFaceVertices.TryGetValue(fuzzyXYZ, out adjustedXYZ)) { adjustedXYZ = m_TessellatedFaceVertices[fuzzyXYZ] = loopVertices[ii]; } adjustedLoopVertices.Add(adjustedXYZ); createdVertices[new IFCFuzzyXYZ(adjustedXYZ)] = numCreated; numCreated++; } // Checking start and end points should be covered above. if (numCreated < 3) { Importer.TheLog.LogComment(id, "Loop has less than 3 distinct vertices, ignoring.", false); return(false); } m_TessellatedFaceBoundary.Add(adjustedLoopVertices); return(true); }
/// <summary> /// Add one loop of vertices that will define a boundary loop of the current face. /// </summary> /// <param name="id">The id of the IFCEntity, for error reporting.</param> /// <param name="loopVertices">The list of vertices.</param> /// <returns>True if the operation succeeded, false oherwise.</returns> public bool AddLoopVertices(int id, List <XYZ> loopVertices) { int vertexCount = (loopVertices == null) ? 0 : loopVertices.Count; if (vertexCount < 3) { Importer.TheLog.LogComment(id, "Too few distinct loop vertices, ignoring.", false); return(false); } List <XYZ> adjustedLoopVertices = null; IList <Tuple <int, int> > interiorLoops = null; int numOuterCreated = 0; bool succeeded = false; for (int pass = 0; pass < 2 && !succeeded; pass++) { // If we have AnyGeometry as a target, we are using Solid tolerances on a first pass. // If that would fail, try again using Mesh tolerances. if (pass == 1 && !RevertToMeshIfPossible()) { break; } succeeded = true; // numOuterCreated is the size of the main "outer" loop after removing duplicates // and self-intersecting loops. In all valid cases, numOuterCreated = numTotalCreated. numOuterCreated = 0; // The total number of non-duplicate loops. This can differ if we are trying to create // a solid vs. a mesh. int numTotalCreated = 0; // The vertices of the main (presumably outer) loop. adjustedLoopVertices = new List <XYZ>(); // The list of vertices of the self-intersecting loops. // Note that we will check that the self-interecting loops do not themselves self-intersect. interiorLoops = new List <Tuple <int, int> >(); int lastInteriorLoopIndex = -1; IDictionary <IFCFuzzyXYZ, int> createdVertices = new SortedDictionary <IFCFuzzyXYZ, int>(); for (int ii = 0; ii < vertexCount; ii++) { IFCFuzzyXYZ fuzzyXYZ = new IFCFuzzyXYZ(loopVertices[ii]); int createdVertexIndex = -1; if (createdVertices.TryGetValue(fuzzyXYZ, out createdVertexIndex)) { // We will allow the first and last point to be equivalent, or the current and last point. Otherwise we will throw. if (((createdVertexIndex == 0) && (ii == vertexCount - 1)) || (createdVertexIndex == numTotalCreated - 1)) { continue; } // If we have a real self-intersection, mark the loop created by the intersection // for removal later. if (loopVertices[ii].DistanceTo(loopVertices[createdVertexIndex]) < MathUtil.SmallGap()) { if (lastInteriorLoopIndex > createdVertexIndex) { // The interior loops overlap; this is probably too much to try to fix. succeeded = false; break; } // Sorted in reverse order so we can more easily create the interior loops later. int numToRemove = ii - createdVertexIndex; interiorLoops.Insert(0, new Tuple <int, int>(createdVertexIndex, numToRemove)); lastInteriorLoopIndex = ii; numOuterCreated -= numToRemove; continue; } // Note that if pass == 1, CanRevertToMesh will be false. if (!CanRevertToMesh()) { Importer.TheLog.LogWarning(id, "Loop is self-intersecting, truncating.", false); } succeeded = false; break; } XYZ adjustedXYZ; if (!m_TessellatedFaceVertices.TryGetValue(fuzzyXYZ, out adjustedXYZ)) { adjustedXYZ = m_TessellatedFaceVertices[fuzzyXYZ] = loopVertices[ii]; } adjustedLoopVertices.Add(adjustedXYZ); createdVertices[new IFCFuzzyXYZ(adjustedXYZ)] = numTotalCreated; numTotalCreated++; numOuterCreated++; } if (numOuterCreated < 3) { succeeded = false; } } // Checking start and end points should be covered above. if (numOuterCreated < 3) { Importer.TheLog.LogComment(id, "Loop has less than 3 distinct vertices, ignoring.", false); return(false); } // Remove the interior loops from the loop boundary, in reverse order, and add them // to the tessellated face boundary. foreach (Tuple <int, int> interiorLoop in interiorLoops) { int startIndex = interiorLoop.Item1; int count = interiorLoop.Item2; if (count >= 3) { m_TessellatedFaceBoundary.Add(loopVertices.GetRange(startIndex, count)); } adjustedLoopVertices.RemoveRange(startIndex, count); } if (interiorLoops.Count > 0) { Importer.TheLog.LogWarning(id, "Loop is self-intersecting, fixing.", false); } m_TessellatedFaceBoundary.Add(adjustedLoopVertices); return(true); }