private static HandleAndAnalyzer CreateExtrusionWithClippingAndOpening(ExporterIFC exporterIFC, Element element, ElementId catId, Solid solid, Plane plane, XYZ projDir, IFCRange range, out bool completelyClipped, out bool hasClippingResult, out bool hasBooleanResult, out ElementId materialId) { completelyClipped = false; materialId = ElementId.InvalidElementId; hasClippingResult = false; hasBooleanResult = false; HandleAndAnalyzer nullVal = new HandleAndAnalyzer(); HandleAndAnalyzer retVal = new HandleAndAnalyzer(); try { ExtrusionAnalyzer elementAnalyzer = ExtrusionAnalyzer.Create(solid, plane, projDir); retVal.Analyzer = elementAnalyzer; Document document = element.Document; XYZ planeOrig = plane.Origin; XYZ baseLoopOffset = null; if (!MathUtil.IsAlmostZero(elementAnalyzer.StartParameter)) baseLoopOffset = elementAnalyzer.StartParameter * projDir; Face extrusionBase = elementAnalyzer.GetExtrusionBase(); IList<GeometryUtil.FaceBoundaryType> boundaryTypes; IList<CurveLoop> extrusionBoundaryLoops = GeometryUtil.GetFaceBoundaries(extrusionBase, baseLoopOffset, out boundaryTypes); // Return if we get any CurveLoops that are complex, as we don't want to export an approximation of the boundary here. foreach (GeometryUtil.FaceBoundaryType boundaryType in boundaryTypes) { if (boundaryType == GeometryUtil.FaceBoundaryType.Complex) return nullVal; } // Move base plane to start parameter location. Plane extrusionBasePlane = null; try { extrusionBasePlane = extrusionBoundaryLoops[0].GetPlane(); } catch { return nullVal; } double extrusionLength = elementAnalyzer.EndParameter - elementAnalyzer.StartParameter; double baseOffset = extrusionBasePlane.Origin.DotProduct(projDir); IFCRange extrusionRange = new IFCRange(baseOffset, extrusionLength + baseOffset); double startParam = planeOrig.DotProduct(projDir); double endParam = planeOrig.DotProduct(projDir) + extrusionLength; if ((range != null) && (startParam >= range.End || endParam <= range.Start)) { completelyClipped = true; return nullVal; } double scaledExtrusionDepth = UnitUtil.ScaleLength(extrusionLength); string profileName = null; if (element != null) { ElementType type = element.Document.GetElement(element.GetTypeId()) as ElementType; if (type != null) profileName = type.Name; } // We use a sub-transaction here in case we are able to generate the base body but not the clippings. IFCFile file = exporterIFC.GetFile(); IFCAnyHandle finalExtrusionBodyItemHnd = null; using (IFCTransaction tr = new IFCTransaction(file)) { // For creating the actual extrusion, we want to use the calculated extrusion plane, not the input plane. IFCAnyHandle extrusionBodyItemHnd = ExtrusionExporter.CreateExtrudedSolidFromCurveLoop(exporterIFC, profileName, extrusionBoundaryLoops, extrusionBasePlane, projDir, scaledExtrusionDepth); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(extrusionBodyItemHnd)) { retVal.BaseExtrusions.Add(extrusionBodyItemHnd); finalExtrusionBodyItemHnd = extrusionBodyItemHnd; IDictionary<ElementId, ICollection<ICollection<Face>>> elementCutouts = GeometryUtil.GetCuttingElementFaces(element, elementAnalyzer); foreach (KeyValuePair<ElementId, ICollection<ICollection<Face>>> elementCutoutsForElement in elementCutouts) { // process clippings first, then openings ICollection<ICollection<Face>> unhandledElementCutoutsForElement = new List<ICollection<Face>>(); Element cuttingElement = document.GetElement(elementCutoutsForElement.Key); foreach (ICollection<Face> elementCutout in elementCutoutsForElement.Value) { ICollection<Face> skippedFaces = null; bool unhandledClipping = false; try { // The skippedFaces may represent openings that will be dealt with below. finalExtrusionBodyItemHnd = GeometryUtil.CreateClippingFromFaces(exporterIFC, cuttingElement, extrusionBasePlane, projDir, elementCutout, extrusionRange, finalExtrusionBodyItemHnd, out skippedFaces); } catch { skippedFaces = null; unhandledClipping = true; } if (finalExtrusionBodyItemHnd == null || unhandledClipping) { unhandledElementCutoutsForElement.Add(elementCutout); } else { if (finalExtrusionBodyItemHnd != extrusionBodyItemHnd) hasClippingResult = true; // Even if we created a clipping, we may have faces to further process as openings. if (skippedFaces != null && skippedFaces.Count != 0) unhandledElementCutoutsForElement.Add(skippedFaces); } } IFCAnyHandle finalExtrusionClippingBodyItemHnd = finalExtrusionBodyItemHnd; foreach (ICollection<Face> elementCutout in unhandledElementCutoutsForElement) { bool unhandledOpening = false; try { finalExtrusionBodyItemHnd = GeometryUtil.CreateOpeningFromFaces(exporterIFC, cuttingElement, extrusionBasePlane, projDir, elementCutout, extrusionRange, finalExtrusionBodyItemHnd); } catch { unhandledOpening = true; } if (finalExtrusionBodyItemHnd == null || unhandledOpening) { // Item is completely clipped. We use this only when we are certain: // 1. finalExtrusionBodyItemHnd is null. // 2. range is not null (i.e., we expect the possibility of clipping) // 3. unhandledOpening is not true (i.e., we didn't abort the operation). // If completelyClipped is true, we won't export the item, so we want to make sure // that we don't actually want to try a backup method instead. completelyClipped = (finalExtrusionBodyItemHnd == null) && (range != null) && (!unhandledOpening); tr.RollBack(); return nullVal; } else if (finalExtrusionBodyItemHnd != finalExtrusionClippingBodyItemHnd) { hasBooleanResult = true; } } } materialId = BodyExporter.GetBestMaterialIdFromGeometryOrParameter(solid, exporterIFC, element); BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, document, extrusionBodyItemHnd, materialId); } tr.Commit(); } retVal.Handle = finalExtrusionBodyItemHnd; return retVal; } catch { return nullVal; } }
private static HandleAndAnalyzer CreateExtrusionWithClippingBase(ExporterIFC exporterIFC, Element element, ElementId catId, IList<Solid> solids, Plane plane, XYZ projDir, IFCRange range, out bool completelyClipped, out HashSet<ElementId> materialIds) { IFCFile file = exporterIFC.GetFile(); bool mustUseTessellation = false; using (IFCTransaction tr = new IFCTransaction(file)) { completelyClipped = false; materialIds = new HashSet<ElementId>(); HandleAndAnalyzer retVal = new HandleAndAnalyzer(); HashSet<IFCAnyHandle> extrusionBodyItems = new HashSet<IFCAnyHandle>(); HashSet<IFCAnyHandle> extrusionBooleanBodyItems = new HashSet<IFCAnyHandle>(); HashSet<IFCAnyHandle> extrusionClippingBodyItems = new HashSet<IFCAnyHandle>(); foreach (Solid solid in solids) { bool hasClippingResult = false; bool hasBooleanResult = false; ElementId materialId = ElementId.InvalidElementId; HandleAndAnalyzer currRetVal = CreateExtrusionWithClippingAndOpening(exporterIFC, element, catId, solid, plane, projDir, range, out completelyClipped, out hasClippingResult, out hasBooleanResult, out materialId); if (currRetVal != null && currRetVal.Handle != null) { // If any of the solid is of the type of Clipping or Boolean and export is for Reference View, exit the loop and collect the geometries entirely // for TriangulatedFaceSet if (ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView && (hasClippingResult || hasBooleanResult)) { mustUseTessellation = true; break; } materialIds.Add(materialId); IFCAnyHandle repHandle = currRetVal.Handle; if (hasBooleanResult) // if both have boolean and clipping result, use boolean one. extrusionBooleanBodyItems.Add(repHandle); else if (hasClippingResult) extrusionClippingBodyItems.Add(repHandle); else extrusionBodyItems.Add(repHandle); } else { tr.RollBack(); // TODO: include this cleanup in RollBack(), to avoid issues. ExporterCacheManager.MaterialIdToStyleHandleCache.RemoveInvalidHandles(materialIds, IFCEntityType.IfcSurfaceStyle); ExporterCacheManager.PresentationStyleAssignmentCache.RemoveInvalidHandles(materialIds); return retVal; } // currRetVal will only have one extrusion. Use the analyzer from the "last" extrusion. Should only really be used for one extrusion. retVal.Analyzer = currRetVal.Analyzer; retVal.BaseExtrusions.Add(currRetVal.BaseExtrusions[0]); } IFCAnyHandle contextOfItemsBody = exporterIFC.Get3DContextHandle("Body"); // Handle Tessellation here for Reference View export. If all are extrusions, it should not get in here if (mustUseTessellation) { BodyExporterOptions options = new BodyExporterOptions(true); Document document = element.Document; ElementId materialId = ElementId.InvalidElementId; materialIds.Clear(); extrusionBodyItems.Clear(); foreach (Solid solid in solids) { IFCAnyHandle triangulatedBodyItem = BodyExporter.ExportBodyAsTriangulatedFaceSet(exporterIFC, element, options, solid); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(triangulatedBodyItem)) extrusionBodyItems.Add(triangulatedBodyItem); materialId = BodyExporter.GetBestMaterialIdFromGeometryOrParameter(solid, exporterIFC, element); materialIds.Add(materialId); BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, document, triangulatedBodyItem, materialId); } retVal.Handle = RepresentationUtil.CreateTessellatedRep(exporterIFC, element, catId, contextOfItemsBody, extrusionBodyItems, null); retVal.ShapeRepresentationType = ShapeRepresentationType.Tessellation; } else { if (extrusionBodyItems.Count > 0 && (extrusionClippingBodyItems.Count == 0 && extrusionBooleanBodyItems.Count == 0)) { retVal.Handle = RepresentationUtil.CreateSweptSolidRep(exporterIFC, element, catId, contextOfItemsBody, extrusionBodyItems, null); retVal.ShapeRepresentationType = ShapeRepresentationType.SweptSolid; } else if (extrusionClippingBodyItems.Count > 0 && (extrusionBodyItems.Count == 0 && extrusionBooleanBodyItems.Count == 0)) { retVal.Handle = RepresentationUtil.CreateClippingRep(exporterIFC, element, catId, contextOfItemsBody, extrusionClippingBodyItems); retVal.ShapeRepresentationType = ShapeRepresentationType.Clipping; } else if (extrusionBooleanBodyItems.Count > 0 && (extrusionBodyItems.Count == 0 && extrusionClippingBodyItems.Count == 0)) { retVal.Handle = RepresentationUtil.CreateCSGRep(exporterIFC, element, catId, contextOfItemsBody, extrusionBooleanBodyItems); retVal.ShapeRepresentationType = ShapeRepresentationType.CSG; } else { IFCAnyHandle finalBodyItemHnd = null; ICollection<IFCAnyHandle> booleanBodyItems = extrusionClippingBodyItems.Union<IFCAnyHandle>(extrusionBooleanBodyItems).ToList(); finalBodyItemHnd = booleanBodyItems.ElementAt(0); booleanBodyItems.Remove(finalBodyItemHnd); // union non-boolean result first with a boolean result foreach (IFCAnyHandle bodyRep in extrusionBodyItems) { finalBodyItemHnd = IFCInstanceExporter.CreateBooleanResult(exporterIFC.GetFile(), IFCBooleanOperator.Union, finalBodyItemHnd, bodyRep); } foreach (IFCAnyHandle bodyRep in booleanBodyItems) { finalBodyItemHnd = IFCInstanceExporter.CreateBooleanResult(exporterIFC.GetFile(), IFCBooleanOperator.Union, finalBodyItemHnd, bodyRep); } extrusionBodyItems.Clear(); extrusionBodyItems.Add(finalBodyItemHnd); retVal.Handle = RepresentationUtil.CreateCSGRep(exporterIFC, element, catId, contextOfItemsBody, extrusionBodyItems); retVal.ShapeRepresentationType = ShapeRepresentationType.CSG; } } tr.Commit(); return retVal; } }
private static HandleAndAnalyzer CreateExtrusionWithClippingBase(ExporterIFC exporterIFC, Element element, ElementId catId, Solid solid, Plane plane, XYZ projDir, IFCRange range, out bool completelyClipped) { completelyClipped = false; HandleAndAnalyzer nullVal = new HandleAndAnalyzer(); HandleAndAnalyzer retVal = new HandleAndAnalyzer(); try { ExtrusionAnalyzer elementAnalyzer = ExtrusionAnalyzer.Create(solid, plane, projDir); retVal.Analyzer = elementAnalyzer; IFCAnyHandle contextOfItemsBody = exporterIFC.Get3DContextHandle("Body"); IFCAnyHandle bodyRep = null; Document document = element.Document; double scale = exporterIFC.LinearScale; XYZ planeOrig = plane.Origin; XYZ baseLoopOffset = null; if (!MathUtil.IsAlmostZero(elementAnalyzer.StartParameter)) baseLoopOffset = elementAnalyzer.StartParameter * projDir; Face extrusionBase = elementAnalyzer.GetExtrusionBase(); IList<GeometryUtil.FaceBoundaryType> boundaryTypes; IList<CurveLoop> extrusionBoundaryLoops = GeometryUtil.GetFaceBoundaries(extrusionBase, baseLoopOffset, out boundaryTypes); // Return if we get any CurveLoops that are complex, as we don't want to export an approximation of the boundary here. foreach (GeometryUtil.FaceBoundaryType boundaryType in boundaryTypes) { if (boundaryType == GeometryUtil.FaceBoundaryType.Complex) return nullVal; } // Move base plane to start parameter location. Plane extrusionBasePlane = null; try { extrusionBasePlane = extrusionBoundaryLoops[0].GetPlane(); } catch { return nullVal; } double extrusionLength = elementAnalyzer.EndParameter - elementAnalyzer.StartParameter; double baseOffset = extrusionBasePlane.Origin.DotProduct(projDir); IFCRange extrusionRange = new IFCRange(baseOffset, extrusionLength + baseOffset); double startParam = planeOrig.DotProduct(projDir); double endParam = planeOrig.DotProduct(projDir) + extrusionLength; if ((range != null) && (startParam >= range.End || endParam <= range.Start)) { completelyClipped = true; return nullVal; } double scaledExtrusionDepth = extrusionLength * scale; string profileName = null; if (element != null) { ElementType type = element.Document.GetElement(element.GetTypeId()) as ElementType; if (type != null) profileName = type.Name; } // We use a sub-transaction here in case we are able to generate the base body but not the clippings. IFCFile file = exporterIFC.GetFile(); using (IFCTransaction tr = new IFCTransaction(file)) { // For creating the actual extrusion, we want to use the calculated extrusion plane, not the input plane. IFCAnyHandle extrusionBodyItemHnd = ExtrusionExporter.CreateExtrudedSolidFromCurveLoop(exporterIFC, profileName, extrusionBoundaryLoops, extrusionBasePlane, projDir, scaledExtrusionDepth); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(extrusionBodyItemHnd)) { IFCAnyHandle finalExtrusionBodyItemHnd = extrusionBodyItemHnd; IDictionary<ElementId, ICollection<ICollection<Face>>> elementCutouts = GeometryUtil.GetCuttingElementFaces(element, elementAnalyzer); foreach (KeyValuePair<ElementId, ICollection<ICollection<Face>>> elementCutoutsForElement in elementCutouts) { Element cuttingElement = document.GetElement(elementCutoutsForElement.Key); foreach (ICollection<Face> elementCutout in elementCutoutsForElement.Value) { bool unhandledClipping = false; try { finalExtrusionBodyItemHnd = GeometryUtil.ProcessFaceCollection(exporterIFC, cuttingElement, extrusionBasePlane, projDir, elementCutout, extrusionRange, finalExtrusionBodyItemHnd); } catch { unhandledClipping = true; } if (finalExtrusionBodyItemHnd == null || unhandledClipping) { // Item is completely clipped. completelyClipped = (finalExtrusionBodyItemHnd == null); tr.RollBack(); return nullVal; } } } IFCAnyHandle extrusionStyledItemHnd = BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, document, extrusionBodyItemHnd, ElementId.InvalidElementId); HashSet<IFCAnyHandle> extrusionBodyItems = new HashSet<IFCAnyHandle>(); extrusionBodyItems.Add(finalExtrusionBodyItemHnd); if (extrusionBodyItemHnd == finalExtrusionBodyItemHnd) { bodyRep = RepresentationUtil.CreateSweptSolidRep(exporterIFC, element, catId, contextOfItemsBody, extrusionBodyItems, null); } else { bodyRep = RepresentationUtil.CreateClippingRep(exporterIFC, element, catId, contextOfItemsBody, extrusionBodyItems); } } tr.Commit(); } retVal.Handle = bodyRep; return retVal; } catch { return nullVal; } }
private static HandleAndAnalyzer CreateExtrusionWithClippingBase(ExporterIFC exporterIFC, Element element, ElementId catId, IList<Solid> solids, Plane plane, XYZ projDir, IFCRange range, out bool completelyClipped, out HashSet<ElementId> materialIds) { IFCFile file = exporterIFC.GetFile(); using (IFCTransaction tr = new IFCTransaction(file)) { completelyClipped = false; materialIds = new HashSet<ElementId>(); HandleAndAnalyzer retVal = new HandleAndAnalyzer(); HashSet<IFCAnyHandle> extrusionBodyItems = new HashSet<IFCAnyHandle>(); HashSet<IFCAnyHandle> extrusionBooleanBodyItems = new HashSet<IFCAnyHandle>(); HashSet<IFCAnyHandle> extrusionClippingBodyItems = new HashSet<IFCAnyHandle>(); foreach (Solid solid in solids) { bool hasClippingResult = false; bool hasBooleanResult = false; ElementId materialId = ElementId.InvalidElementId; retVal = CreateExtrsionWithClippingAndOpening(exporterIFC, element, catId, solid, plane, projDir, range, out completelyClipped, out hasClippingResult, out hasBooleanResult, out materialId); if (retVal != null && retVal.Handle != null) { materialIds.Add(materialId); IFCAnyHandle repHandle = retVal.Handle; if (hasBooleanResult) // if both have boolean and clipping result, use boolean one. extrusionBooleanBodyItems.Add(repHandle); else if (hasClippingResult) extrusionClippingBodyItems.Add(repHandle); else extrusionBodyItems.Add(repHandle); } else { tr.RollBack(); return retVal; } } IFCAnyHandle contextOfItemsBody = exporterIFC.Get3DContextHandle("Body"); if (extrusionBodyItems.Count > 0 && (extrusionClippingBodyItems.Count == 0 && extrusionBooleanBodyItems.Count == 0)) { retVal.Handle = RepresentationUtil.CreateSweptSolidRep(exporterIFC, element, catId, contextOfItemsBody, extrusionBodyItems, null); } else if (extrusionClippingBodyItems.Count > 0 && (extrusionBodyItems.Count == 0 && extrusionBooleanBodyItems.Count == 0)) { retVal.Handle = RepresentationUtil.CreateClippingRep(exporterIFC, element, catId, contextOfItemsBody, extrusionClippingBodyItems); } else if (extrusionBooleanBodyItems.Count > 0 && (extrusionBodyItems.Count == 0 && extrusionClippingBodyItems.Count == 0)) { retVal.Handle = RepresentationUtil.CreateCSGRep(exporterIFC, element, catId, contextOfItemsBody, extrusionBooleanBodyItems); } else { IFCAnyHandle finalBodyItemHnd = null; ICollection<IFCAnyHandle> booleanBodyItems = extrusionClippingBodyItems.Union<IFCAnyHandle>(extrusionBooleanBodyItems).ToList(); finalBodyItemHnd = booleanBodyItems.ElementAt(0); booleanBodyItems.Remove(finalBodyItemHnd); // union non-boolean result first with a boolean result foreach (IFCAnyHandle bodyRep in extrusionBodyItems) { finalBodyItemHnd = IFCInstanceExporter.CreateBooleanResult(exporterIFC.GetFile(), IFCBooleanOperator.Union, finalBodyItemHnd, bodyRep); } foreach (IFCAnyHandle bodyRep in booleanBodyItems) { finalBodyItemHnd = IFCInstanceExporter.CreateBooleanResult(exporterIFC.GetFile(), IFCBooleanOperator.Union, finalBodyItemHnd, bodyRep); } extrusionBodyItems.Clear(); extrusionBodyItems.Add(finalBodyItemHnd); retVal.Handle = RepresentationUtil.CreateCSGRep(exporterIFC, element, catId, contextOfItemsBody, extrusionBodyItems); } tr.Commit(); return retVal; } }
private static HandleAndAnalyzer CreateExtrusionWithClippingBase(ExporterIFC exporterIFC, Element element, ElementId catId, IList<Solid> solids, Plane plane, XYZ projDir, IFCRange range, out bool completelyClipped, out HashSet<ElementId> materialIds) { IFCFile file = exporterIFC.GetFile(); using (IFCTransaction tr = new IFCTransaction(file)) { completelyClipped = false; materialIds = new HashSet<ElementId>(); HandleAndAnalyzer retVal = new HandleAndAnalyzer(); HashSet<IFCAnyHandle> extrusionBodyItems = new HashSet<IFCAnyHandle>(); HashSet<IFCAnyHandle> extrusionBooleanBodyItems = new HashSet<IFCAnyHandle>(); HashSet<IFCAnyHandle> extrusionClippingBodyItems = new HashSet<IFCAnyHandle>(); foreach (Solid solid in solids) { bool hasClippingResult = false; bool hasBooleanResult = false; ElementId materialId = ElementId.InvalidElementId; HandleAndAnalyzer currRetVal = CreateExtrusionWithClippingAndOpening(exporterIFC, element, catId, solid, plane, projDir, range, out completelyClipped, out hasClippingResult, out hasBooleanResult, out materialId); if (currRetVal != null && currRetVal.Handle != null) { materialIds.Add(materialId); IFCAnyHandle repHandle = currRetVal.Handle; if (hasBooleanResult) // if both have boolean and clipping result, use boolean one. extrusionBooleanBodyItems.Add(repHandle); else if (hasClippingResult) extrusionClippingBodyItems.Add(repHandle); else extrusionBodyItems.Add(repHandle); } else { tr.RollBack(); // TODO: include this cleanup in RollBack(), to avoid issues. ExporterCacheManager.MaterialIdToStyleHandleCache.RemoveInvalidHandles(materialIds, IFCEntityType.IfcSurfaceStyle); ExporterCacheManager.PresentationStyleAssignmentCache.RemoveInvalidHandles(materialIds); return retVal; } // currRetVal will only have one extrusion. Use the analyzer from the "last" extrusion. Should only really be used for one extrusion. retVal.Analyzer = currRetVal.Analyzer; retVal.BaseExtrusions.Add(currRetVal.BaseExtrusions[0]); } IFCAnyHandle contextOfItemsBody = exporterIFC.Get3DContextHandle("Body"); if (extrusionBodyItems.Count > 0 && (extrusionClippingBodyItems.Count == 0 && extrusionBooleanBodyItems.Count == 0)) { retVal.Handle = RepresentationUtil.CreateSweptSolidRep(exporterIFC, element, catId, contextOfItemsBody, extrusionBodyItems, null); retVal.ShapeRepresentationType = ShapeRepresentationType.SweptSolid; } else if (extrusionClippingBodyItems.Count > 0 && (extrusionBodyItems.Count == 0 && extrusionBooleanBodyItems.Count == 0)) { retVal.Handle = RepresentationUtil.CreateClippingRep(exporterIFC, element, catId, contextOfItemsBody, extrusionClippingBodyItems); retVal.ShapeRepresentationType = ShapeRepresentationType.Clipping; } else if (extrusionBooleanBodyItems.Count > 0 && (extrusionBodyItems.Count == 0 && extrusionClippingBodyItems.Count == 0)) { retVal.Handle = RepresentationUtil.CreateCSGRep(exporterIFC, element, catId, contextOfItemsBody, extrusionBooleanBodyItems); retVal.ShapeRepresentationType = ShapeRepresentationType.CSG; } else { IFCAnyHandle finalBodyItemHnd = null; ICollection<IFCAnyHandle> booleanBodyItems = extrusionClippingBodyItems.Union<IFCAnyHandle>(extrusionBooleanBodyItems).ToList(); finalBodyItemHnd = booleanBodyItems.ElementAt(0); booleanBodyItems.Remove(finalBodyItemHnd); // union non-boolean result first with a boolean result foreach (IFCAnyHandle bodyRep in extrusionBodyItems) { finalBodyItemHnd = IFCInstanceExporter.CreateBooleanResult(exporterIFC.GetFile(), IFCBooleanOperator.Union, finalBodyItemHnd, bodyRep); } foreach (IFCAnyHandle bodyRep in booleanBodyItems) { finalBodyItemHnd = IFCInstanceExporter.CreateBooleanResult(exporterIFC.GetFile(), IFCBooleanOperator.Union, finalBodyItemHnd, bodyRep); } extrusionBodyItems.Clear(); extrusionBodyItems.Add(finalBodyItemHnd); retVal.Handle = RepresentationUtil.CreateCSGRep(exporterIFC, element, catId, contextOfItemsBody, extrusionBodyItems); retVal.ShapeRepresentationType = ShapeRepresentationType.CSG; } tr.Commit(); return retVal; } }