/// <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; }
/// <summary> /// Return 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> /// <returns>The created geometry.</returns> public IList<GeometryObject> CreateGeometry( IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid) { IList<GeometryObject> firstSolids = FirstOperand.CreateGeometry(shapeEditScope, lcs, scaledLcs, guid); if (firstSolids != null) { foreach (GeometryObject potentialSolid in firstSolids) { if (!(potentialSolid is Solid)) { Importer.TheLog.LogError((FirstOperand as IFCRepresentationItem).Id, "Can't perform Boolean operation on a Mesh.", false); return firstSolids; } } } IList<GeometryObject> secondSolids = null; if (SecondOperand != null) { try { using (IFCImportShapeEditScope.BuildPreferenceSetter setter = new IFCImportShapeEditScope.BuildPreferenceSetter(shapeEditScope, IFCImportShapeEditScope.BuildPreferenceType.ForceSolid)) { // Before we process the second operand, we are going to see if there is a uniform material set for the first operand // (corresponding to the solid in the Boolean operation). We will try to suggest the same material for the voids to avoid arbitrary // setting of material information for the cut faces. IFCStyledItem firstOperandStyledItem = GetStyledItemFromOperand(FirstOperand as IFCRepresentationItem); using (IFCImportShapeEditScope.IFCMaterialStack stack = new IFCImportShapeEditScope.IFCMaterialStack(shapeEditScope, firstOperandStyledItem, null)) { secondSolids = SecondOperand.CreateGeometry(shapeEditScope, lcs, scaledLcs, guid); } } } catch (Exception ex) { // We will allow something to be imported, in the case where the second operand is invalid. // If the first (base) operand is invalid, we will still fail the import of this solid. if (SecondOperand is IFCRepresentationItem) Importer.TheLog.LogError((SecondOperand as IFCRepresentationItem).Id, ex.Message, false); else throw ex; secondSolids = null; } } IList<GeometryObject> resultSolids = null; if (firstSolids == null) { resultSolids = secondSolids; } else if (secondSolids == null || BooleanOperator == null) { if (BooleanOperator == null) Importer.TheLog.LogError(Id, "Invalid BooleanOperationsType.", false); resultSolids = firstSolids; } else { BooleanOperationsType booleanOperationsType = BooleanOperationsType.Difference; switch (BooleanOperator) { case IFCBooleanOperator.Difference: booleanOperationsType = BooleanOperationsType.Difference; break; case IFCBooleanOperator.Intersection: booleanOperationsType = BooleanOperationsType.Intersect; break; case IFCBooleanOperator.Union: booleanOperationsType = BooleanOperationsType.Union; break; default: Importer.TheLog.LogError(Id, "Invalid BooleanOperationsType.", true); break; } resultSolids = new List<GeometryObject>(); foreach (GeometryObject firstSolid in firstSolids) { Solid resultSolid = (firstSolid as Solid); int secondId = (SecondOperand == null) ? -1 : (SecondOperand as IFCRepresentationItem).Id; XYZ suggestedShiftDirection = (SecondOperand == null) ? null : SecondOperand.GetSuggestedShiftDirection(lcs); foreach (GeometryObject secondSolid in secondSolids) { resultSolid = IFCGeometryUtil.ExecuteSafeBooleanOperation(Id, secondId, resultSolid, secondSolid as Solid, booleanOperationsType, suggestedShiftDirection); if (resultSolid == null) break; } if (resultSolid != null) resultSolids.Add(resultSolid); } } return resultSolids; }
/// <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; }