Ejemplo n.º 1
0
        /// <summary>
        /// Revert to using a mesh representation if that's allowed.
        /// </summary>
        /// <returns>True if the change is made.</returns>
        public bool RevertToMeshIfPossible()
        {
            // Note that CanRevertToMesh() is redundant, but a trivial enough check.
            if (!CanRevertToMesh())
            {
                return(false);
            }

            SetTargetAndFallbackGeometry(TessellatedShapeBuilderTarget.Mesh, TessellatedShapeBuilderFallback.Salvage);

            // We also need to reset the Comparer for TessellatedFaceVertices to a new tolerance.
            // Note that since we are always lowering the tolerance, there should be no concern that
            // previous entries would disappear.  That isn't always true; see the remarks of
            // IFCFuzzyXYZSet.
            TessellatedFaceVertices.ResetTolerance(GetVertexTolerance());
            return(true);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Stop collecting faces to create a BRep solid.
        /// </summary>
        public void StopCollectingFaceSet()
        {
            if (TessellatedShapeBuilder == null)
            {
                throw new InvalidOperationException("StartCollectingFaceSet has not been called.");
            }

            TessellatedShapeBuilder.CloseConnectedFaceSet();

            if (TessellatedFaceBoundary != null)
            {
                TessellatedFaceBoundary.Clear();
            }

            if (TessellatedFaceVertices != null)
            {
                TessellatedFaceVertices.Clear();
            }

            FaceMaterialId = ElementId.InvalidElementId;
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Start collecting faces to create a BRep solid.
        /// </summary>
        public void StartCollectingFaceSet()
        {
            if (TessellatedShapeBuilder == null)
            {
                TessellatedShapeBuilder = new TessellatedShapeBuilder();
            }

            TessellatedShapeBuilder.OpenConnectedFaceSet(false);
            ResetCreatedFacesCount();

            if (TessellatedFaceVertices != null)
            {
                TessellatedFaceVertices.Clear();
            }

            if (TessellatedFaceBoundary != null)
            {
                TessellatedFaceBoundary.Clear();
            }

            FaceMaterialId = ElementId.InvalidElementId;
        }
Ejemplo n.º 4
0
        /// <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 <XYZ, int> createdVertices =
                    new SortedDictionary <XYZ, int>(new IFCXYZFuzzyComparer(GetVertexTolerance()));

                for (int ii = 0; ii < vertexCount; ii++)
                {
                    XYZ loopVertex = loopVertices[ii];

                    int createdVertexIndex = -1;
                    if (createdVertices.TryGetValue(loopVertex, 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 (loopVertex.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, Tuple.Create(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 = TessellatedFaceVertices.FindOrAdd(loopVertex);

                    adjustedLoopVertices.Add(adjustedXYZ);
                    createdVertices[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)
                {
                    TessellatedFaceBoundary.Add(loopVertices.GetRange(startIndex, count));
                }
                adjustedLoopVertices.RemoveRange(startIndex, count);
            }

            if (interiorLoops.Count > 0)
            {
                Importer.TheLog.LogWarning(id, "Loop is self-intersecting, fixing.", false);
            }

            TessellatedFaceBoundary.Add(adjustedLoopVertices);
            return(true);
        }