Esempio n. 1
0
        /// <summary>
        /// Create geometry for a particular representation item.
        /// </summary>
        /// <param name="shapeEditScope">The geometry creation scope.</param>
        /// <param name="lcs">Local coordinate system for the geometry, without scale.</param>
        /// <param name="scaledLcs">Local coordinate system for the geometry, including scale, potentially non-uniform.</param>
        /// <param name="guid">The guid of an element for which represntation is being created.</param>
        protected override void CreateShapeInternal(IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid)
        {
            if (shapeEditScope.BuilderType != IFCShapeBuilderType.TessellatedShapeBuilder)
            {
                throw new InvalidOperationException("Currently BrepBuilder is only used to support IFCAdvancedFace");
            }

            base.CreateShapeInternal(shapeEditScope, lcs, scaledLcs, guid);

            // we would only be in this code if we are not processing and IfcAdvancedBrep, since IfcAdvancedBrep must have IfcAdvancedFace
            if (shapeEditScope.BuilderScope == null)
            {
                throw new InvalidOperationException("BuilderScope has not been initialized");
            }
            TessellatedShapeBuilderScope tsBuilderScope = shapeEditScope.BuilderScope as TessellatedShapeBuilderScope;

            bool      addFace        = true;
            bool      canTriangulate = (Bounds.Count == 1);
            ElementId materialId     = GetMaterialElementId(shapeEditScope);

            // We can only really triangulate faces with one boundary with 4 vertices,
            // but we don't really know how many vertices the boundary has until later.
            // So this is just the first block.  Later, we can try to extend to generic
            // polygons.
            tsBuilderScope.StartCollectingFace(materialId, canTriangulate);

            foreach (IFCFaceBound faceBound in Bounds)
            {
                faceBound.CreateShape(shapeEditScope, lcs, scaledLcs, guid);

                // If we can't create the outer face boundary, we will abort the creation of this face.
                // In that case, return, unless we can triangulate it.
                if (!tsBuilderScope.HaveActiveFace())
                {
                    addFace = false;
                    break;
                }
            }

            tsBuilderScope.StopCollectingFace(addFace, false);

            IList <List <XYZ> > delayedFaceBoundaries = CreateTriangulation(tsBuilderScope.DelayedFaceBoundary);

            if (delayedFaceBoundaries != null)
            {
                bool extraFace = false;
                foreach (List <XYZ> delayedBoundary in delayedFaceBoundaries)
                {
                    bool addTriangulatedFace = true;
                    tsBuilderScope.StartCollectingFace(GetMaterialElementId(shapeEditScope), false);
                    if (!tsBuilderScope.AddLoopVertices(Id, delayedBoundary))
                    {
                        Importer.TheLog.LogComment(Id, "Bounded loop plane is slightly non-planar, couldn't triangulate.", false);
                        addTriangulatedFace = false;
                    }
                    tsBuilderScope.StopCollectingFace(addTriangulatedFace, extraFace);
                    extraFace = true;
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Return geometry for a particular representation item.
        /// </summary>
        /// <param name="shapeEditScope">The shape edit scope.</param>
        /// <param name="lcs">Local coordinate system for the geometry, without scale.</param>
        /// <param name="scaledLcs">Local coordinate system for the geometry, including scale, potentially non-uniform.</param>
        /// <param name="guid">The guid of an element for which represntation is being created.</param>
        /// <returns>The created geometry.</returns>
        /// <remarks>As this doesn't inherit from IfcSolidModel, this is a non-virtual CreateGeometry function.</remarks>
        protected IList <GeometryObject> CreateGeometry(IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid)
        {
            if (Shells.Count == 0)
            {
                return(null);
            }

            IList <GeometryObject> geomObjs = null;

            using (BuilderScope bs = shapeEditScope.InitializeBuilder(IFCShapeBuilderType.TessellatedShapeBuilder))
            {
                TessellatedShapeBuilderScope tsBuilderScope = bs as TessellatedShapeBuilderScope;
                tsBuilderScope.StartCollectingFaceSet();

                foreach (IFCConnectedFaceSet faceSet in Shells)
                {
                    faceSet.CreateShape(shapeEditScope, lcs, scaledLcs, guid);
                }

                geomObjs = tsBuilderScope.CreateGeometry(guid);
            }
            if (geomObjs == null || geomObjs.Count == 0)
            {
                return(null);
            }

            return(geomObjs);
        }
Esempio n. 3
0
        /// <summary>
        /// Create geometry for a particular representation item.
        /// </summary>
        /// <param name="shapeEditScope">The geometry creation scope.</param>
        /// <param name="lcs">Local coordinate system for the geometry, without scale.</param>
        /// <param name="scaledLcs">Local coordinate system for the geometry, including scale, potentially non-uniform.</param>
        /// <param name="guid">The guid of an element for which represntation is being created.</param>
        protected override void CreateShapeInternal(IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid)
        {
            if (shapeEditScope.BuilderType != IFCShapeBuilderType.TessellatedShapeBuilder)
            {
                throw new InvalidOperationException("Currently BrepBuilder is only used to support IFCAdvancedFace");
            }

            base.CreateShapeInternal(shapeEditScope, lcs, scaledLcs, guid);

            // we would only be in this code if we are not processing and IfcAdvancedBrep, since IfcAdvancedBrep must have IfcAdvancedFace
            if (shapeEditScope.BuilderScope == null)
            {
                throw new InvalidOperationException("BuilderScope has not been initialized");
            }
            TessellatedShapeBuilderScope tsBuilderScope = shapeEditScope.BuilderScope as TessellatedShapeBuilderScope;

            tsBuilderScope.StartCollectingFace(GetMaterialElementId(shapeEditScope));

            foreach (IFCFaceBound faceBound in Bounds)
            {
                faceBound.CreateShape(shapeEditScope, lcs, scaledLcs, guid);

                // If we can't create the outer face boundary, we will abort the creation of this face.  In that case, return.
                if (!tsBuilderScope.HaveActiveFace())
                {
                    tsBuilderScope.AbortCurrentFace();
                    return;
                }
            }
            tsBuilderScope.StopCollectingFace();
        }
Esempio n. 4
0
        private Tuple <IList <GeometryObject>, bool> CollectFaces(IFCImportShapeEditScope shapeEditScope,
                                                                  Transform lcs, Transform scaledLcs, string guid)
        {
            using (BuilderScope bs = shapeEditScope.InitializeBuilder(IFCShapeBuilderType.TessellatedShapeBuilder))
            {
                TessellatedShapeBuilderScope tsBuilderScope = bs as TessellatedShapeBuilderScope;

                tsBuilderScope.StartCollectingFaceSet();
                Outer.CreateShape(shapeEditScope, lcs, scaledLcs, guid);

                IList <GeometryObject> geomObjs = null;
                bool canRevertToMesh            = tsBuilderScope.CanRevertToMesh();

                int numCreatedFaces  = tsBuilderScope.CreatedFacesCount;
                int numExpectedFaces = Outer.Faces.Count;

                if (numCreatedFaces == numExpectedFaces || (!canRevertToMesh && numCreatedFaces > 0))
                {
                    geomObjs = tsBuilderScope.CreateGeometry(guid);

                    if (numCreatedFaces < numExpectedFaces)
                    {
                        Importer.TheLog.LogWarning(Outer.Id,
                                                   "Processing " + numCreatedFaces + " valid faces out of " + numExpectedFaces + " total.", false);
                    }
                }

                return(Tuple.Create(geomObjs, canRevertToMesh));
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Return geometry for a particular representation item.
        /// </summary>
        /// <param name="shapeEditScope">The shape edit scope.</param>
        /// <param name="lcs">Local coordinate system for the geometry, without scale.</param>
        /// <param name="scaledLcs">Local coordinate system for the geometry, including scale, potentially non-uniform.</param>
        /// <param name="guid">The guid of an element for which represntation is being created.</param>
        /// <returns>The created geometry.</returns>
        protected override IList <GeometryObject> CreateGeometryInternal(
            IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid)
        {
            if (Outer == null || Outer.Faces.Count == 0)
            {
                return(null);
            }

            IList <GeometryObject> geomObjs = null;
            bool canRevertToMesh            = false;

            using (BuilderScope bs = shapeEditScope.InitializeBuilder(IFCShapeBuilderType.TessellatedShapeBuilder))
            {
                TessellatedShapeBuilderScope tsBuilderScope = bs as TessellatedShapeBuilderScope;

                tsBuilderScope.StartCollectingFaceSet();
                Outer.CreateShape(shapeEditScope, lcs, scaledLcs, guid);

                if (tsBuilderScope.CreatedFacesCount == Outer.Faces.Count)
                {
                    geomObjs = tsBuilderScope.CreateGeometry(guid);
                }

                canRevertToMesh = tsBuilderScope.CanRevertToMesh();
            }


            if (geomObjs == null || geomObjs.Count == 0)
            {
                if (canRevertToMesh)
                {
                    using (IFCImportShapeEditScope.BuildPreferenceSetter setter =
                               new IFCImportShapeEditScope.BuildPreferenceSetter(shapeEditScope, IFCImportShapeEditScope.BuildPreferenceType.AnyMesh))
                    {
                        using (BuilderScope newBuilderScope = shapeEditScope.InitializeBuilder(IFCShapeBuilderType.TessellatedShapeBuilder))
                        {
                            TessellatedShapeBuilderScope newTsBuilderScope = newBuilderScope as TessellatedShapeBuilderScope;
                            // Let's see if we can loosen the requirements a bit, and try again.
                            newTsBuilderScope.StartCollectingFaceSet();

                            Outer.CreateShape(shapeEditScope, lcs, scaledLcs, guid);

                            // This needs to be in scope so that we keep the mesh tolerance for vertices.
                            if (newTsBuilderScope.CreatedFacesCount != 0)
                            {
                                if (newTsBuilderScope.CreatedFacesCount != Outer.Faces.Count)
                                {
                                    Importer.TheLog.LogWarning
                                        (Outer.Id, "Processing " + newTsBuilderScope.CreatedFacesCount + " valid faces out of " + Outer.Faces.Count + " total.", false);
                                }

                                geomObjs = newTsBuilderScope.CreateGeometry(guid);
                            }
                        }
                    }
                }
            }

            if (geomObjs == null || geomObjs.Count == 0)
            {
                // Couldn't use fallback, or fallback didn't work.
                Importer.TheLog.LogWarning(Id, "Couldn't create any geometry.", false);
                return(null);
            }

            return(geomObjs);
        }
Esempio n. 6
0
        /// <summary>
        /// Return geometry for a particular representation item.
        /// </summary>
        /// <param name="shapeEditScope">The shape edit scope.</param>
        /// <param name="lcs">Local coordinate system for the geometry, without scale.</param>
        /// <param name="scaledLcs">Local coordinate system for the geometry, including scale, potentially non-uniform.</param>
        /// <param name="guid">The guid of an element for which represntation is being created.</param>
        /// <returns>The created geometry.</returns>
        /// <remarks>As this doesn't inherit from IfcSolidModel, this is a non-virtual CreateSolid function.</remarks>
        protected IList <GeometryObject> CreateGeometry(
            IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid)
        {
            if (Shells.Count == 0)
            {
                return(null);
            }

            IList <GeometryObject> geomObjs = null;
            int numExpectedFaces            = 0;

            foreach (IFCConnectedFaceSet faceSet in Shells)
            {
                numExpectedFaces += faceSet.Faces.Count;
            }

            // We are going to start by trying to create a Solid, even if we are passed a shell-based model, since we can frequently
            // do so.  However, if we have even one missing face, we'll loosen the requirements and revert to mesh only.
            for (int pass = 0; pass < 2; pass++)
            {
                IFCImportShapeEditScope.BuildPreferenceType target =
                    (pass == 0) ? IFCImportShapeEditScope.BuildPreferenceType.AnyGeometry : IFCImportShapeEditScope.BuildPreferenceType.AnyMesh;
                using (IFCImportShapeEditScope.BuildPreferenceSetter setter =
                           new IFCImportShapeEditScope.BuildPreferenceSetter(shapeEditScope, target))
                {
                    using (BuilderScope bs = shapeEditScope.InitializeBuilder(IFCShapeBuilderType.TessellatedShapeBuilder))
                    {
                        TessellatedShapeBuilderScope tsBuilderScope = shapeEditScope.BuilderScope as TessellatedShapeBuilderScope;

                        tsBuilderScope.StartCollectingFaceSet();

                        foreach (IFCConnectedFaceSet faceSet in Shells)
                        {
                            faceSet.CreateShape(shapeEditScope, lcs, scaledLcs, guid);
                        }

                        // If we are on our first pass, try again.  If we are on our second pass, warn and create the best geometry we can.
                        if (tsBuilderScope.CreatedFacesCount != numExpectedFaces)
                        {
                            if (pass == 0)
                            {
                                continue;
                            }

                            Importer.TheLog.LogWarning
                                (Id, "Processing " + tsBuilderScope.CreatedFacesCount + " valid faces out of " + numExpectedFaces + " total.", false);
                        }

                        geomObjs = tsBuilderScope.CreateGeometry(guid);

                        WarnOnTooFewCreatedFaces(geomObjs, numExpectedFaces);

                        break;
                    }
                }
            }

            if (geomObjs == null || geomObjs.Count == 0)
            {
                if (numExpectedFaces != 0)
                {
                    Importer.TheLog.LogError
                        (Id, "No valid geometry found.  This may be due to slivery triangles or other similar geometric issues.", false);
                    return(null);
                }
            }

            return(geomObjs);
        }
Esempio n. 7
0
        private void CreateTessellatedShapeInternal(IFCImportShapeEditScope shapeEditScope, Transform scaledLcs)
        {
            TessellatedShapeBuilderScope tsBuilderScope = shapeEditScope.BuilderScope as TessellatedShapeBuilderScope;

            if (tsBuilderScope == null)
            {
                throw new InvalidOperationException("Expect a TessellatedShapeBuilderScope, but get a BrepBuilderScope instead");
            }

            IList <XYZ> loopVertices = Bound.LoopVertices;
            int         count        = 0;

            if (loopVertices == null || ((count = loopVertices.Count) == 0))
            {
                throw new InvalidOperationException("#" + Id + ": missing loop vertices, ignoring.");
            }

            if (count < 3)
            {
                throw new InvalidOperationException("#" + Id + ": too few loop vertices (" + count + "), ignoring.");
            }

            if (!Orientation)
            {
                loopVertices.Reverse();
            }

            // Apply the transform
            IList <XYZ> transformedVertices = new List <XYZ>();

            foreach (XYZ vertex in loopVertices)
            {
                transformedVertices.Add(scaledLcs.OfPoint(vertex));
            }

            // Check that the loop vertices don't contain points that are very close to one another;
            // if so, throw the point away and hope that the TessellatedShapeBuilder can repair the result.
            // Warn in this case.  If the entire boundary is bad, report an error and don't add the loop vertices.

            IList <XYZ> validVertices;

            IFCGeometryUtil.CheckAnyDistanceVerticesWithinTolerance(Id, shapeEditScope, transformedVertices, out validVertices);

            // We are going to catch any exceptions if the loop is invalid.
            // We are going to hope that we can heal the parent object in the TessellatedShapeBuilder.
            bool bPotentiallyAbortFace = false;

            count = validVertices.Count;
            if (validVertices.Count < 3)
            {
                Importer.TheLog.LogComment(Id, "Too few distinct loop vertices (" + count + "), ignoring.", false);
                bPotentiallyAbortFace = true;
            }
            else
            {
                if (!tsBuilderScope.AddLoopVertices(Id, validVertices))
                {
                    bPotentiallyAbortFace = true;
                }
            }

            if (bPotentiallyAbortFace && IsOuter)
            {
                tsBuilderScope.AbortCurrentFace();
            }
        }
Esempio n. 8
0
        protected override void CreateShapeInternal(IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid)
        {
            using (BuilderScope bs = shapeEditScope.InitializeBuilder(IFCShapeBuilderType.TessellatedShapeBuilder))
            {
                base.CreateShapeInternal(shapeEditScope, lcs, scaledLcs, guid);

                TessellatedShapeBuilderScope tsBuilderScope = bs as TessellatedShapeBuilderScope;

                tsBuilderScope.StartCollectingFaceSet();

                // Create triangle face set from CoordIndex. We do not support the Normals yet at this point
                foreach (List <int> triIndex in CoordIndex)
                {
                    // This is a defensive check in an unlikely situation that the index is larger than the data
                    if (triIndex[0] > Coordinates.CoordList.Count || triIndex[1] > Coordinates.CoordList.Count || triIndex[2] > Coordinates.CoordList.Count)
                    {
                        continue;
                    }

                    tsBuilderScope.StartCollectingFace(GetMaterialElementId(shapeEditScope));

                    IList <XYZ> loopVertices = new List <XYZ>();

                    for (int ii = 0; ii < 3; ++ii)
                    {
                        int actualVIdx = triIndex[ii] - 1;
                        if (PnIndex != null)
                        {
                            actualVIdx = PnIndex[actualVIdx] - 1;
                        }
                        IList <double> v = Coordinates.CoordList[actualVIdx];
                        loopVertices.Add(new XYZ(v[0], v[1], v[2]));
                    }

                    IList <XYZ> transformedVertices = new List <XYZ>();
                    foreach (XYZ vertex in loopVertices)
                    {
                        // Need to apply the project unit scaling here
                        XYZ scaledVertex = applyProjectUnitScaleVertex(vertex);
                        transformedVertices.Add(scaledLcs.OfPoint(scaledVertex));
                    }

                    // Check triangle that is too narrow (2 vertices are within the tolerance
                    IList <XYZ> validVertices;
                    IFCGeometryUtil.CheckAnyDistanceVerticesWithinTolerance(Id, shapeEditScope, transformedVertices, out validVertices);

                    // We are going to catch any exceptions if the loop is invalid.
                    // We are going to hope that we can heal the parent object in the TessellatedShapeBuilder.
                    bool bPotentiallyAbortFace = false;

                    int count = validVertices.Count;
                    if (validVertices.Count < 3)
                    {
                        Importer.TheLog.LogComment(Id, "Too few distinct loop vertices (" + count + "), ignoring.", false);
                        bPotentiallyAbortFace = true;
                    }
                    else
                    {
                        if (!tsBuilderScope.AddLoopVertices(Id, validVertices))
                        {
                            bPotentiallyAbortFace = true;
                        }
                    }

                    if (bPotentiallyAbortFace)
                    {
                        tsBuilderScope.AbortCurrentFace();
                    }
                    else
                    {
                        tsBuilderScope.StopCollectingFace();
                    }
                }

                IList <GeometryObject> createdGeometries = tsBuilderScope.CreateGeometry(guid);
                if (createdGeometries != null)
                {
                    foreach (GeometryObject createdGeometry in createdGeometries)
                    {
                        shapeEditScope.AddGeometry(IFCSolidInfo.Create(Id, createdGeometry));
                    }
                }
            }
        }
Esempio n. 9
0
        protected override void CreateShapeInternal(IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid)
        {
            using (BuilderScope bs = shapeEditScope.InitializeBuilder(IFCShapeBuilderType.TessellatedShapeBuilder))
            {
                base.CreateShapeInternal(shapeEditScope, lcs, scaledLcs, guid);

                TessellatedShapeBuilderScope tsBuilderScope = bs as TessellatedShapeBuilderScope;

                tsBuilderScope.StartCollectingFaceSet();

                // Create the face set from IFCIndexedPolygonalFace
                foreach (IFCIndexedPolygonalFace face in Faces)
                {
                    // TODO: Consider adding ability to triangulate here.
                    tsBuilderScope.StartCollectingFace(GetMaterialElementId(shapeEditScope), false);

                    IList <XYZ> loopVertices = new List <XYZ>();
                    foreach (int vertInd in face.CoordIndex)
                    {
                        int actualVIdx = vertInd - 1; // IFC starts the list position at 1
                        if (PnIndex != null)
                        {
                            actualVIdx = PnIndex[actualVIdx] - 1;
                        }
                        XYZ vertex = Coordinates.CoordList[actualVIdx];
                        loopVertices.Add(scaledLcs.OfPoint(vertex));
                    }
                    List <XYZ> validVertices;
                    IFCGeometryUtil.CheckAnyDistanceVerticesWithinTolerance(Id, shapeEditScope, loopVertices, out validVertices);

                    bool bPotentiallyAbortFace = false;
                    if (!tsBuilderScope.AddLoopVertices(Id, validVertices))
                    {
                        bPotentiallyAbortFace = true;
                    }

                    // Handle holes
                    if (face.InnerCoordIndices != null)
                    {
                        foreach (IList <int> innerLoop in face.InnerCoordIndices)
                        {
                            IList <XYZ> innerLoopVertices = new List <XYZ>();
                            foreach (int innerVerIdx in innerLoop)
                            {
                                int actualVIdx = innerVerIdx - 1;
                                if (PnIndex != null)
                                {
                                    actualVIdx = PnIndex[actualVIdx] - 1;
                                }
                                XYZ vertex = Coordinates.CoordList[actualVIdx];
                                // add vertex to the loop
                                innerLoopVertices.Add(scaledLcs.OfPoint(vertex));
                            }
                            List <XYZ> validInnerV;
                            IFCGeometryUtil.CheckAnyDistanceVerticesWithinTolerance(Id, shapeEditScope, innerLoopVertices, out validInnerV);

                            if (!tsBuilderScope.AddLoopVertices(Id, validInnerV))
                            {
                                bPotentiallyAbortFace = true;
                            }
                        }
                    }

                    tsBuilderScope.StopCollectingFace(!bPotentiallyAbortFace, false);
                }

                IList <GeometryObject> createdGeometries = tsBuilderScope.CreateGeometry(guid);
                if (createdGeometries != null)
                {
                    foreach (GeometryObject createdGeometry in createdGeometries)
                    {
                        shapeEditScope.AddGeometry(IFCSolidInfo.Create(Id, createdGeometry));
                    }
                }
            }
        }
Esempio n. 10
0
        private void CreateTessellatedShapeInternal(IFCImportShapeEditScope shapeEditScope, Transform scaledLcs)
        {
            TessellatedShapeBuilderScope tsBuilderScope = shapeEditScope.BuilderScope as TessellatedShapeBuilderScope;

            if (tsBuilderScope == null)
            {
                throw new InvalidOperationException("Expect a TessellatedShapeBuilderScope, but get a BrepBuilderScope instead");
            }

            IList <XYZ> loopVertices = Bound.LoopVertices;
            int         count        = 0;

            if (loopVertices == null || ((count = loopVertices.Count) == 0))
            {
                throw new InvalidOperationException("#" + Id + ": missing loop vertices, ignoring.");
            }

            if (count < 3)
            {
                throw new InvalidOperationException("#" + Id + ": too few loop vertices (" + count + "), ignoring.");
            }

            if (!Orientation)
            {
                loopVertices.Reverse();
            }

            // Apply the transform
            IList <XYZ> transformedVertices = new List <XYZ>();

            foreach (XYZ vertex in loopVertices)
            {
                transformedVertices.Add(scaledLcs.OfPoint(vertex));
            }

            // Check that the loop vertices don't contain points that are very close to one another;
            // if so, throw the point away and hope that the TessellatedShapeBuilder can repair the result.
            // Warn in this case.  If the entire boundary is bad, report an error and don't add the loop vertices.
            List <XYZ> validVertices = null;

            for (int pass = 0; pass < 2; pass++)
            {
                if (pass == 1 && !tsBuilderScope.RevertToMeshIfPossible())
                {
                    break;
                }

                IFCGeometryUtil.CheckAnyDistanceVerticesWithinTolerance(Id, shapeEditScope, transformedVertices, out validVertices);
                count = validVertices.Count;
                if (count >= 3 || !IsOuter)
                {
                    break;
                }
            }

            // We are going to catch any exceptions if the loop is invalid.
            // We are going to hope that we can heal the parent object in the TessellatedShapeBuilder.
            bool bPotentiallyAbortFace = (count < 3);

            if (bPotentiallyAbortFace)
            {
                Importer.TheLog.LogComment(Id, "Too few distinct loop vertices (" + count + "), ignoring.", false);
            }
            else
            {
                bool maybeTryToTriangulate = tsBuilderScope.CanProcessDelayedFaceBoundary && (count == 4);
                bool tryToTriangulate      = false;

                // Last check: check to see if the vertices are actually planar.
                // We are not going to be particularly fancy about how we pick the plane.
                if (count > 3)
                {
                    XYZ planeNormal = null;

                    XYZ    firstPoint  = validVertices[0];
                    XYZ    secondPoint = validVertices[1];
                    XYZ    firstDir    = secondPoint - firstPoint;
                    double bestLength  = 0;

                    for (int index = 2; index <= count; index++)
                    {
                        XYZ    thirdPoint         = validVertices[(index % count)];
                        XYZ    currentPlaneNormal = firstDir.CrossProduct(thirdPoint - firstPoint);
                        double planeNormalLength  = currentPlaneNormal.GetLength();
                        if (planeNormalLength > 0.01)
                        {
                            planeNormal = currentPlaneNormal.Normalize();
                            break;
                        }
                        else if (maybeTryToTriangulate && (planeNormalLength > bestLength))
                        {
                            planeNormal = currentPlaneNormal.Normalize();
                            bestLength  = planeNormalLength;
                        }

                        firstPoint  = secondPoint;
                        secondPoint = thirdPoint;
                        firstDir    = secondPoint - firstPoint;
                    }

                    if (planeNormal == null)
                    {
                        // Even if we don't find a good normal, we will still see if the internal function can make sense of it.
                        Importer.TheLog.LogComment(Id, "Bounded loop plane is likely non-planar, may triangulate.", false);
                    }
                    else
                    {
                        double vertexEps = IFCImportFile.TheFile.VertexTolerance;

                        for (int index = 0; index < count; index++)
                        {
                            XYZ pointOnPlane = validVertices[index] -
                                               (validVertices[index] - firstPoint).DotProduct(planeNormal) * planeNormal;
                            double distance = pointOnPlane.DistanceTo(validVertices[index]);
                            if (distance > vertexEps * 10.0)
                            {
                                Importer.TheLog.LogComment(Id, "Bounded loop plane is non-planar, may triangulate.", false);
                                tryToTriangulate      = maybeTryToTriangulate;
                                bPotentiallyAbortFace = !tryToTriangulate;
                                break;
                            }
                            else if (distance > vertexEps)
                            {
                                if (!maybeTryToTriangulate)
                                {
                                    Importer.TheLog.LogComment(Id, "Bounded loop plane is slightly non-planar, correcting.", false);
                                    validVertices[index] = pointOnPlane;
                                }
                                else
                                {
                                    Importer.TheLog.LogComment(Id, "Bounded loop plane is slightly non-planar, will triangulate.", false);
                                    tryToTriangulate = maybeTryToTriangulate;
                                }
                            }
                        }
                    }
                }

                if (!bPotentiallyAbortFace)
                {
                    if (tryToTriangulate)
                    {
                        tsBuilderScope.DelayedFaceBoundary = validVertices;
                    }
                    else
                    {
                        bPotentiallyAbortFace = !tsBuilderScope.AddLoopVertices(Id, validVertices);
                    }
                }
            }

            if (bPotentiallyAbortFace && IsOuter)
            {
                tsBuilderScope.AbortCurrentFace();
            }
        }
Esempio n. 11
0
        private void CreateTessellatedShapeInternal(IFCImportShapeEditScope shapeEditScope, Transform scaledLcs)
        {
            TessellatedShapeBuilderScope tsBuilderScope = shapeEditScope.BuilderScope as TessellatedShapeBuilderScope;

            if (tsBuilderScope == null)
            {
                throw new InvalidOperationException("Expect a TessellatedShapeBuilderScope, but get a BrepBuilderScope instead");
            }

            IList <XYZ> loopVertices = Bound.LoopVertices;
            int         count        = 0;

            if (loopVertices == null || ((count = loopVertices.Count) == 0))
            {
                throw new InvalidOperationException("#" + Id + ": missing loop vertices, ignoring.");
            }

            if (count < 3)
            {
                throw new InvalidOperationException("#" + Id + ": too few loop vertices (" + count + "), ignoring.");
            }

            if (!Orientation)
            {
                loopVertices.Reverse();
            }

            // Apply the transform
            IList <XYZ> transformedVertices = new List <XYZ>();

            foreach (XYZ vertex in loopVertices)
            {
                transformedVertices.Add(scaledLcs.OfPoint(vertex));
            }

            // Check that the loop vertices don't contain points that are very close to one another;
            // if so, throw the point away and hope that the TessellatedShapeBuilder can repair the result.
            // Warn in this case.  If the entire boundary is bad, report an error and don't add the loop vertices.

            IList <XYZ> validVertices;

            IFCGeometryUtil.CheckAnyDistanceVerticesWithinTolerance(Id, shapeEditScope, transformedVertices, out validVertices);

            // We are going to catch any exceptions if the loop is invalid.
            // We are going to hope that we can heal the parent object in the TessellatedShapeBuilder.
            bool bPotentiallyAbortFace = false;

            count = validVertices.Count;
            if (count < 3)
            {
                Importer.TheLog.LogComment(Id, "Too few distinct loop vertices (" + count + "), ignoring.", false);
                bPotentiallyAbortFace = true;
            }
            else
            {
                // Last check: check to see if the vertices are actually planar.  If not, for the vertices to be planar.
                // We are not going to be particularly fancy about how we pick the plane.
                XYZ  planeNormal = null;
                bool foundNormal = false;

                XYZ firstPoint  = validVertices[0];
                XYZ secondPoint = validVertices[1];
                XYZ firstDir    = secondPoint - firstPoint;

                int thirdPointIndex = 2;
                for (; thirdPointIndex < count; thirdPointIndex++)
                {
                    XYZ thirdPoint = validVertices[thirdPointIndex];
                    planeNormal = firstDir.CrossProduct(thirdPoint - firstPoint);
                    if (!planeNormal.IsZeroLength())
                    {
                        planeNormal = planeNormal.Normalize();
                        foundNormal = true;
                        break;
                    }
                }

                if (!foundNormal)
                {
                    Importer.TheLog.LogComment(Id, "Loop is degenerate, ignoring.", false);
                    bPotentiallyAbortFace = true;
                }
                else
                {
                    double vertexEps = IFCImportFile.TheFile.Document.Application.VertexTolerance;

                    for (++thirdPointIndex; thirdPointIndex < count; thirdPointIndex++)
                    {
                        XYZ pointOnPlane = validVertices[thirdPointIndex] -
                                           (validVertices[thirdPointIndex] - firstPoint).DotProduct(planeNormal) * planeNormal;
                        if (pointOnPlane.DistanceTo(validVertices[thirdPointIndex]) > vertexEps)
                        {
                            Importer.TheLog.LogComment(Id, "Bounded loop plane is slightly non-planar, correcting.", false);
                            validVertices[thirdPointIndex] = pointOnPlane;
                        }
                    }

                    if (!tsBuilderScope.AddLoopVertices(Id, validVertices))
                    {
                        bPotentiallyAbortFace = true;
                    }
                }
            }

            if (bPotentiallyAbortFace && IsOuter)
            {
                tsBuilderScope.AbortCurrentFace();
            }
        }