/// <summary> /// Exports an element as IFC railing. /// </summary> /// <param name="exporterIFC"> /// The ExporterIFC object. /// </param> /// <param name="element"> /// The element to be exported. /// </param> /// <param name="geometryElement"> /// The geometry element. /// </param> /// <param name="productWrapper"> /// The ProductWrapper. /// </param> public static void ExportRailing(ExporterIFC exporterIFC, Element element, GeometryElement geomElem, string ifcEnumType, ProductWrapper productWrapper) { // Check the intended IFC entity or type name is in the exclude list specified in the UI Common.Enums.IFCEntityType elementClassTypeEnum = Common.Enums.IFCEntityType.IfcRailing; if (ExporterCacheManager.ExportOptionsCache.IsElementInExcludeList(elementClassTypeEnum)) { return; } ElementType elemType = element.Document.GetElement(element.GetTypeId()) as ElementType; IFCFile file = exporterIFC.GetFile(); Options geomOptions = GeometryUtil.GetIFCExportGeometryOptions(); using (IFCTransaction transaction = new IFCTransaction(file)) { using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, element)) { using (IFCExtrusionCreationData ecData = new IFCExtrusionCreationData()) { IFCAnyHandle localPlacement = setter.LocalPlacement; StairRampContainerInfo stairRampInfo = null; ElementId hostId = GetStairOrRampHostId(exporterIFC, element as Railing); Transform inverseTrf = Transform.Identity; if (hostId != ElementId.InvalidElementId) { stairRampInfo = ExporterCacheManager.StairRampContainerInfoCache.GetStairRampContainerInfo(hostId); IFCAnyHandle stairRampLocalPlacement = stairRampInfo.LocalPlacements[0]; Transform relTrf = ExporterIFCUtils.GetRelativeLocalPlacementOffsetTransform(stairRampLocalPlacement, localPlacement); inverseTrf = relTrf.Inverse; IFCAnyHandle railingLocalPlacement = ExporterUtil.CreateLocalPlacement(file, stairRampLocalPlacement, inverseTrf.Origin, inverseTrf.BasisZ, inverseTrf.BasisX); localPlacement = railingLocalPlacement; } ecData.SetLocalPlacement(localPlacement); SolidMeshGeometryInfo solidMeshInfo = GeometryUtil.GetSplitSolidMeshGeometry(geomElem); IList <Solid> solids = solidMeshInfo.GetSolids(); IList <Mesh> meshes = solidMeshInfo.GetMeshes(); Railing railingElem = element as Railing; IList <ElementId> subElementIds = CollectSubElements(railingElem); foreach (ElementId subElementId in subElementIds) { Element subElement = railingElem.Document.GetElement(subElementId); if (subElement != null) { GeometryElement subElementGeom = GeometryUtil.GetOneLevelGeometryElement(subElement.get_Geometry(geomOptions), 0); SolidMeshGeometryInfo subElementSolidMeshInfo = GeometryUtil.GetSplitSolidMeshGeometry(subElementGeom); IList <Solid> subElementSolids = subElementSolidMeshInfo.GetSolids(); IList <Mesh> subElementMeshes = subElementSolidMeshInfo.GetMeshes(); foreach (Solid subElementSolid in subElementSolids) { solids.Add(subElementSolid); } foreach (Mesh subElementMesh in subElementMeshes) { meshes.Add(subElementMesh); } } } ElementId catId = CategoryUtil.GetSafeCategoryId(element); BodyData bodyData = null; BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true, ExportOptionsCache.ExportTessellationLevel.Medium); //bodyExporterOptions.UseGroupsIfPossible = true; //bodyExporterOptions.UseMappedGeometriesIfPossible = true; if (solids.Count > 0 || meshes.Count > 0) { bodyData = BodyExporter.ExportBody(exporterIFC, element, catId, ElementId.InvalidElementId, solids, meshes, bodyExporterOptions, ecData); } else { IList <GeometryObject> geomlist = new List <GeometryObject>(); geomlist.Add(geomElem); bodyData = BodyExporter.ExportBody(exporterIFC, element, catId, ElementId.InvalidElementId, geomlist, bodyExporterOptions, ecData); } IFCAnyHandle bodyRep = bodyData.RepresentationHnd; if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep)) { if (ecData != null) { ecData.ClearOpenings(); } return; } IList <IFCAnyHandle> representations = new List <IFCAnyHandle>(); representations.Add(bodyRep); IList <GeometryObject> geomObjects = new List <GeometryObject>(); foreach (Solid solid in solids) { geomObjects.Add(solid); } foreach (Mesh mesh in meshes) { geomObjects.Add(mesh); } Transform boundingBoxTrf = (bodyData.OffsetTransform != null) ? bodyData.OffsetTransform.Inverse : Transform.Identity; boundingBoxTrf = inverseTrf.Multiply(boundingBoxTrf); IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geomObjects, boundingBoxTrf); if (boundingBoxRep != null) { representations.Add(boundingBoxRep); } IFCAnyHandle prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations); IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle; string instanceGUID = GUIDUtil.CreateGUID(element); //string railingType = IFCValidateEntry.GetValidIFCPredefinedType(element, ifcEnumType); IFCAnyHandle railing = IFCInstanceExporter.CreateRailing(exporterIFC, element, instanceGUID, ownerHistory, ecData.GetLocalPlacement(), prodRep, ifcEnumType); bool associateToLevel = (hostId == ElementId.InvalidElementId); productWrapper.AddElement(element, railing, setter, ecData, associateToLevel); OpeningUtil.CreateOpeningsIfNecessary(railing, element, ecData, bodyData.OffsetTransform, exporterIFC, ecData.GetLocalPlacement(), setter, productWrapper); CategoryUtil.CreateMaterialAssociation(exporterIFC, railing, bodyData.MaterialIds); // Create multi-story duplicates of this railing. if (stairRampInfo != null) { stairRampInfo.AddComponent(0, railing); List <IFCAnyHandle> stairHandles = stairRampInfo.StairOrRampHandles; for (int ii = 1; ii < stairHandles.Count; ii++) { IFCAnyHandle railingLocalPlacement = stairRampInfo.LocalPlacements[ii]; if (!IFCAnyHandleUtil.IsNullOrHasNoValue(railingLocalPlacement)) { IFCAnyHandle railingHndCopy = CopyRailingHandle(exporterIFC, element, catId, railingLocalPlacement, railing); stairRampInfo.AddComponent(ii, railingHndCopy); productWrapper.AddElement(element, railingHndCopy, (IFCLevelInfo)null, ecData, false); CategoryUtil.CreateMaterialAssociation(exporterIFC, railingHndCopy, bodyData.MaterialIds); } } ExporterCacheManager.StairRampContainerInfoCache.AddStairRampContainerInfo(hostId, stairRampInfo); } } transaction.Commit(); } } }
/// <summary> /// Export the individual part (IfcBuildingElementPart). /// </summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="partElement">The part element to export.</param> /// <param name="geometryElement">The geometry of part.</param> /// <param name="productWrapper">The ProductWrapper object.</param> /// <param name="placementSetter"></param> /// <param name="originalPlacement"></param> /// <param name="range"></param> /// <param name="ifcExtrusionAxes"></param> /// <param name="hostElement">The host of the part. This can be null.</param> /// <param name="overrideLevelId">The id of the level that the part is one, overridding other sources.</param> /// <param name="asBuildingElement">If true, export the Part as a building element instead of an IfcElementPart.</param> public static void ExportPart(ExporterIFC exporterIFC, Element partElement, ProductWrapper productWrapper, PlacementSetter placementSetter, IFCAnyHandle originalPlacement, IFCRange range, IFCExtrusionAxes ifcExtrusionAxes, Element hostElement, ElementId overrideLevelId, bool asBuildingElement) { if (!ElementFilteringUtil.IsElementVisible(partElement)) { return; } Part part = partElement as Part; if (part == null) { return; } // We don't know how to export a part as a building element if we don't know it's host. if (asBuildingElement && (hostElement == null)) { return; } if (!asBuildingElement) { // Check the intended IFC entity or type name is in the exclude list specified in the UI Common.Enums.IFCEntityType elementClassTypeEnum = Common.Enums.IFCEntityType.IfcBuildingElementPart; if (ExporterCacheManager.ExportOptionsCache.IsElementInExcludeList(elementClassTypeEnum)) { return; } } else { string ifcEnumType = null; IFCExportInfoPair exportType = ExporterUtil.GetExportType(exporterIFC, hostElement, out ifcEnumType); // Check the intended IFC entity or type name is in the exclude list specified in the UI Common.Enums.IFCEntityType elementClassTypeEnum; if (Enum.TryParse <Common.Enums.IFCEntityType>(exportType.ToString(), out elementClassTypeEnum)) { if (ExporterCacheManager.ExportOptionsCache.IsElementInExcludeList(elementClassTypeEnum)) { return; } } } PlacementSetter standalonePlacementSetter = null; bool standaloneExport = hostElement == null || asBuildingElement; ElementId partExportLevelId = (overrideLevelId != null) ? overrideLevelId : null; if (partExportLevelId == null && standaloneExport) { partExportLevelId = partElement.LevelId; } if (partExportLevelId == null) { if (hostElement == null || (part.OriginalCategoryId != hostElement.Category.Id)) { return; } partExportLevelId = hostElement.LevelId; } if (ExporterCacheManager.PartExportedCache.HasExported(partElement.Id, partExportLevelId)) { return; } Options options = GeometryUtil.GetIFCExportGeometryOptions(); View ownerView = partElement.Document.GetElement(partElement.OwnerViewId) as View; if (ownerView != null) { options.View = ownerView; } GeometryElement geometryElement = partElement.get_Geometry(options); if (geometryElement == null) { return; } try { IFCFile file = exporterIFC.GetFile(); using (IFCTransaction transaction = new IFCTransaction(file)) { IFCAnyHandle partPlacement = null; if (standaloneExport) { Transform orientationTrf = Transform.Identity; IFCAnyHandle overrideContainerHnd = null; ElementId overrideContainerId = ParameterUtil.OverrideContainmentParameter(exporterIFC, partElement, out overrideContainerHnd); if (overrideContainerId != ElementId.InvalidElementId && (partExportLevelId == null || partExportLevelId == ElementId.InvalidElementId)) { partExportLevelId = overrideContainerId; } standalonePlacementSetter = PlacementSetter.Create(exporterIFC, partElement, null, orientationTrf, partExportLevelId, overrideContainerHnd); partPlacement = standalonePlacementSetter.LocalPlacement; } else { //partPlacement = ExporterUtil.CreateLocalPlacement(file, null, null); partPlacement = ExporterUtil.CreateLocalPlacement(file, originalPlacement, null); } bool validRange = (range != null && !MathUtil.IsAlmostZero(range.Start - range.End)); SolidMeshGeometryInfo solidMeshInfo; if (validRange) { solidMeshInfo = GeometryUtil.GetSplitClippedSolidMeshGeometry(geometryElement, range); if (solidMeshInfo.GetSolids().Count == 0 && solidMeshInfo.GetMeshes().Count == 0) { return; } } else { solidMeshInfo = GeometryUtil.GetSplitSolidMeshGeometry(geometryElement); } using (IFCExtrusionCreationData extrusionCreationData = new IFCExtrusionCreationData()) { extrusionCreationData.SetLocalPlacement(partPlacement); extrusionCreationData.ReuseLocalPlacement = false; extrusionCreationData.PossibleExtrusionAxes = ifcExtrusionAxes; IList <Solid> solids = new List <Solid>();; IList <Mesh> meshes = new List <Mesh>(); IList <GeometryObject> gObjs = FamilyExporterUtil.RemoveInvisibleSolidsAndMeshes(partElement.Document, exporterIFC, solidMeshInfo.GetSolids(), solidMeshInfo.GetMeshes()); foreach (GeometryObject gObj in gObjs) { if (gObj is Solid) { solids.Add(gObj as Solid); } else if (gObj is Mesh) { meshes.Add(gObj as Mesh); } } ElementId catId = CategoryUtil.GetSafeCategoryId(partElement); ElementId hostCatId = CategoryUtil.GetSafeCategoryId(hostElement); BodyData bodyData = null; BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true, ExportOptionsCache.ExportTessellationLevel.ExtraLow); if (solids.Count > 0 || meshes.Count > 0) { bodyData = BodyExporter.ExportBody(exporterIFC, partElement, catId, ElementId.InvalidElementId, solids, meshes, bodyExporterOptions, extrusionCreationData); } else { IList <GeometryObject> geomlist = new List <GeometryObject>(); geomlist.Add(geometryElement); bodyData = BodyExporter.ExportBody(exporterIFC, partElement, catId, ElementId.InvalidElementId, geomlist, bodyExporterOptions, extrusionCreationData); } IFCAnyHandle bodyRep = bodyData.RepresentationHnd; if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep)) { extrusionCreationData.ClearOpenings(); return; } IList <IFCAnyHandle> representations = new List <IFCAnyHandle>(); representations.Add(bodyRep); IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geometryElement, Transform.Identity); if (boundingBoxRep != null) { representations.Add(boundingBoxRep); } IFCAnyHandle prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations); IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle; string partGUID = GUIDUtil.CreateGUID(partElement); string ifcEnumType = null; IFCExportInfoPair exportType = ExporterUtil.GetExportType(exporterIFC, hostElement, out ifcEnumType); IFCAnyHandle ifcPart = null; if (!asBuildingElement) { ifcPart = IFCInstanceExporter.CreateBuildingElementPart(exporterIFC, partElement, partGUID, ownerHistory, extrusionCreationData.GetLocalPlacement(), prodRep); } else { switch (exportType.ExportInstance) { case IFCEntityType.IfcColumn: ifcPart = IFCInstanceExporter.CreateColumn(exporterIFC, partElement, partGUID, ownerHistory, extrusionCreationData.GetLocalPlacement(), prodRep, ifcEnumType); break; case IFCEntityType.IfcCovering: ifcPart = IFCInstanceExporter.CreateCovering(exporterIFC, partElement, partGUID, ownerHistory, extrusionCreationData.GetLocalPlacement(), prodRep, ifcEnumType); break; case IFCEntityType.IfcFooting: ifcPart = IFCInstanceExporter.CreateFooting(exporterIFC, partElement, partGUID, ownerHistory, extrusionCreationData.GetLocalPlacement(), prodRep, ifcEnumType); break; case IFCEntityType.IfcPile: ifcPart = IFCInstanceExporter.CreatePile(exporterIFC, partElement, partGUID, ownerHistory, extrusionCreationData.GetLocalPlacement(), prodRep, ifcEnumType, null); break; case IFCEntityType.IfcRoof: ifcPart = IFCInstanceExporter.CreateRoof(exporterIFC, partElement, partGUID, ownerHistory, extrusionCreationData.GetLocalPlacement(), prodRep, ifcEnumType); break; case IFCEntityType.IfcSlab: { // TODO: fix this elsewhere. if (ExporterUtil.IsNotDefined(ifcEnumType)) { if (hostCatId == new ElementId(BuiltInCategory.OST_Floors)) { ifcEnumType = "FLOOR"; } else if (hostCatId == new ElementId(BuiltInCategory.OST_Roofs)) { ifcEnumType = "ROOF"; } } ifcPart = IFCInstanceExporter.CreateSlab(exporterIFC, partElement, partGUID, ownerHistory, extrusionCreationData.GetLocalPlacement(), prodRep, ifcEnumType); } break; case IFCEntityType.IfcWall: ifcPart = IFCInstanceExporter.CreateWall(exporterIFC, partElement, partGUID, ownerHistory, extrusionCreationData.GetLocalPlacement(), prodRep, ifcEnumType); break; default: ifcPart = IFCInstanceExporter.CreateBuildingElementProxy(exporterIFC, partElement, partGUID, ownerHistory, extrusionCreationData.GetLocalPlacement(), prodRep, exportType.ValidatedPredefinedType); break; } } bool containedInLevel = standaloneExport; PlacementSetter whichPlacementSetter = containedInLevel ? standalonePlacementSetter : placementSetter; productWrapper.AddElement(partElement, ifcPart, whichPlacementSetter, extrusionCreationData, containedInLevel, exportType); OpeningUtil.CreateOpeningsIfNecessary(ifcPart, partElement, extrusionCreationData, bodyData.OffsetTransform, exporterIFC, extrusionCreationData.GetLocalPlacement(), whichPlacementSetter, productWrapper); //Add the exported part to exported cache. TraceExportedParts(partElement, partExportLevelId, standaloneExport ? ElementId.InvalidElementId : hostElement.Id); CategoryUtil.CreateMaterialAssociation(exporterIFC, ifcPart, bodyData.MaterialIds); transaction.Commit(); } } } finally { if (standalonePlacementSetter != null) { standalonePlacementSetter.Dispose(); } } }
/// <summary> /// Copies a BodyData object. /// </summary> /// <param name="representationHnd"> /// The representation handle. /// </param> /// <param name="offsetTransform"> /// The offset transform. /// </param> /// <param name="materialIds"> /// The material ids. /// </param> public BodyData(BodyData bodyData) { this.m_RepresentationHnd = bodyData.RepresentationHnd; this.m_ShapeRepresentationType = bodyData.m_ShapeRepresentationType; this.m_OffsetTransform = bodyData.OffsetTransform; this.m_MaterialIds = bodyData.MaterialIds; }
/// <summary> /// Exports a MEP family instance. /// </summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="element">The element.</param> /// <param name="geometryElement">The geometry element.</param> /// <param name="exportType">The export type of the element. /// <param name="ifcEnumType">The sub-type of the element.</param></param> /// <param name="productWrapper">The ProductWrapper.</param> /// <returns>True if an entity was created, false otherwise.</returns> public static bool Export(ExporterIFC exporterIFC, Element element, GeometryElement geometryElement, IFCExportInfoPair exportType, string ifcEnumType, ProductWrapper productWrapper) { IFCFile file = exporterIFC.GetFile(); using (IFCTransaction tr = new IFCTransaction(file)) { // CQ_TODO: Clean up this code by at least factoring it out. // If we are exporting a duct segment, we may need to split it into parts by level. Create a list of ranges. IList <ElementId> levels = new List <ElementId>(); IList <IFCRange> ranges = new List <IFCRange>(); // We will not split duct segments if the assemblyId is set, as we would like to keep the original duct segment // associated with the assembly, on the level of the assembly. if ((exportType.ExportType == IFCEntityType.IfcDuctSegmentType) && (ExporterCacheManager.ExportOptionsCache.WallAndColumnSplitting) && (element.AssemblyInstanceId == ElementId.InvalidElementId)) { LevelUtil.CreateSplitLevelRangesForElement(exporterIFC, exportType, element, out levels, out ranges); } int numPartsToExport = ranges.Count; { ElementId catId = CategoryUtil.GetSafeCategoryId(element); BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true, ExportOptionsCache.ExportTessellationLevel.ExtraLow); if (0 == numPartsToExport) { // Check for containment override IFCAnyHandle overrideContainerHnd = null; ElementId overrideContainerId = ParameterUtil.OverrideContainmentParameter(exporterIFC, element, out overrideContainerHnd); using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, element, null, null, overrideContainerId, overrideContainerHnd)) { IFCAnyHandle localPlacementToUse = setter.LocalPlacement; BodyData bodyData = null; using (IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData()) { extraParams.SetLocalPlacement(localPlacementToUse); IFCAnyHandle productRepresentation = RepresentationUtil.CreateAppropriateProductDefinitionShape( exporterIFC, element, catId, geometryElement, bodyExporterOptions, null, extraParams, out bodyData); if (IFCAnyHandleUtil.IsNullOrHasNoValue(productRepresentation)) { extraParams.ClearOpenings(); return(false); } ExportAsMappedItem(exporterIFC, element, file, exportType, ifcEnumType, extraParams, setter, localPlacementToUse, productRepresentation, productWrapper); } } } else { for (int ii = 0; ii < numPartsToExport; ii++) { // Check for containment override IFCAnyHandle overrideContainerHnd = null; ParameterUtil.OverrideContainmentParameter(exporterIFC, element, out overrideContainerHnd); using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, element, null, null, levels[ii], overrideContainerHnd)) { IFCAnyHandle localPlacementToUse = setter.LocalPlacement; using (IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData()) { SolidMeshGeometryInfo solidMeshCapsule = GeometryUtil.GetClippedSolidMeshGeometry(geometryElement, ranges[ii]); IList <Solid> solids = solidMeshCapsule.GetSolids(); IList <Mesh> polyMeshes = solidMeshCapsule.GetMeshes(); IList <GeometryObject> geomObjects = FamilyExporterUtil.RemoveInvisibleSolidsAndMeshes(element.Document, exporterIFC, ref solids, ref polyMeshes); if (geomObjects.Count == 0 && (solids.Count > 0 || polyMeshes.Count > 0)) { return(false); } bool tryToExportAsExtrusion = (!exporterIFC.ExportAs2x2 || (exportType.ExportInstance == IFCEntityType.IfcColumn)); if (exportType.ExportInstance == IFCEntityType.IfcColumn) { extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ; } else { extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryXYZ; } BodyData bodyData = null; if (geomObjects.Count > 0) { bodyData = BodyExporter.ExportBody(exporterIFC, element, catId, ElementId.InvalidElementId, geomObjects, bodyExporterOptions, extraParams); } else { IList <GeometryObject> exportedGeometries = new List <GeometryObject>(); exportedGeometries.Add(geometryElement); bodyData = BodyExporter.ExportBody(exporterIFC, element, catId, ElementId.InvalidElementId, exportedGeometries, bodyExporterOptions, extraParams); } List <IFCAnyHandle> bodyReps = new List <IFCAnyHandle>(); bodyReps.Add(bodyData.RepresentationHnd); IFCAnyHandle productRepresentation = IFCInstanceExporter.CreateProductDefinitionShape(exporterIFC.GetFile(), null, null, bodyReps); if (IFCAnyHandleUtil.IsNullOrHasNoValue(productRepresentation)) { extraParams.ClearOpenings(); return(false); } ExportAsMappedItem(exporterIFC, element, file, exportType, ifcEnumType, extraParams, setter, localPlacementToUse, productRepresentation, productWrapper); } } } } } tr.Commit(); } return(true); }
/// <summary> /// Creates a SweptSolid, Brep, SolidModel or SurfaceModel product definition shape representation, based on the geometry and IFC version. /// </summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="categoryId">The category id.</param> /// <param name="geometryElement">The geometry element.</param> /// <param name="bodyExporterOptions">The body exporter options.</param> /// <param name="extraReps">Extra representations (e.g. Axis, Boundary). May be null.</param> /// <param name="extrusionCreationData">The extrusion creation data.</param> /// <param name="bodyData">The body data.</param> /// <returns>The handle.</returns> public static IFCAnyHandle CreateAppropriateProductDefinitionShape(ExporterIFC exporterIFC, Element element, ElementId categoryId, GeometryElement geometryElement, BodyExporterOptions bodyExporterOptions, IList<IFCAnyHandle> extraReps, IFCExtrusionCreationData extrusionCreationData, out BodyData bodyData) { bodyData = null; SolidMeshGeometryInfo info = null; IList<GeometryObject> geometryList = new List<GeometryObject>(); if (!ExporterCacheManager.ExportOptionsCache.ExportAs2x2) { info = GeometryUtil.GetSplitSolidMeshGeometry(geometryElement, Transform.Identity); IList<Mesh> meshes = info.GetMeshes(); if (meshes.Count == 0) { IList<Solid> solidList = info.GetSolids(); foreach (Solid solid in solidList) { geometryList.Add(solid); } } } if (geometryList.Count == 0) geometryList.Add(geometryElement); else bodyExporterOptions.TryToExportAsExtrusion = true; bodyData = BodyExporter.ExportBody(exporterIFC, element, categoryId, ElementId.InvalidElementId, geometryList, bodyExporterOptions, extrusionCreationData); IFCAnyHandle bodyRep = bodyData.RepresentationHnd; List<IFCAnyHandle> bodyReps = new List<IFCAnyHandle>(); if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep)) { if (extrusionCreationData != null) extrusionCreationData.ClearOpenings(); } else bodyReps.Add(bodyRep); if (extraReps != null) { foreach (IFCAnyHandle hnd in extraReps) bodyReps.Add(hnd); } Transform boundingBoxTrf = (bodyData.OffsetTransform != null) ? bodyData.OffsetTransform.Inverse : Transform.Identity; IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geometryElement, boundingBoxTrf); if (boundingBoxRep != null) bodyReps.Add(boundingBoxRep); if (bodyReps.Count == 0) return null; return IFCInstanceExporter.CreateProductDefinitionShape(exporterIFC.GetFile(), null, null, bodyReps); }
private static bool ExportGenericElementAsMappedItem(ExporterIFC exporterIFC, Element element, GeometryElement geomElem, IFCExportInfoPair exportType, ProductWrapper wrapper) { GeometryInstance geometryInstance = GetTheGeometryInstance(geomElem); if (geometryInstance == null) { return(false); } GeometryElement exportGeometry = geometryInstance.GetSymbolGeometry(); if (exportGeometry == null) { return(false); } ElementId symbolId = geometryInstance.GetSymbolGeometryId()?.SymbolId ?? ElementId.InvalidElementId; ElementType elementType = element.Document.GetElement(symbolId) as ElementType; if (elementType == null) { return(false); } Transform originalTrf = geometryInstance.Transform; // Can't handle mirrored transforms yet. if (originalTrf.HasReflection) { return(false); } ElementId categoryId = CategoryUtil.GetSafeCategoryId(element); IFCFile file = exporterIFC.GetFile(); IList <Transform> repMapTrfList = new List <Transform>(); BodyData bodyData = null; FamilyTypeInfo typeInfo = new FamilyTypeInfo(); IFCExtrusionCreationData extraParams = typeInfo.extraParams; Transform offsetTransform = Transform.Identity; // We will create a new mapped type if we haven't already created the type. FamilyTypeInfo currentTypeInfo = ExporterCacheManager.FamilySymbolToTypeInfoCache.Find(symbolId, false, exportType); bool found = currentTypeInfo.IsValid(); if (!found) { IList <IFCAnyHandle> representations3D = new List <IFCAnyHandle>(); IFCAnyHandle dummyPlacement = ExporterUtil.CreateLocalPlacement(file, null, null); extraParams.SetLocalPlacement(dummyPlacement); using (TransformSetter trfSetter = TransformSetter.Create()) { BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(false, ExportOptionsCache.ExportTessellationLevel.ExtraLow); bodyData = BodyExporter.ExportBody(exporterIFC, element, categoryId, ExporterUtil.GetSingleMaterial(element), exportGeometry, bodyExporterOptions, extraParams); typeInfo.MaterialIdList = bodyData.MaterialIds; offsetTransform = bodyData.OffsetTransform; // This code does not handle openings yet. // The intention for this is FabricationParts and DirectShapes which do not // currently have opening. // If they can have openings in the future, we can add this. IFCAnyHandle bodyRepHnd = bodyData.RepresentationHnd; if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRepHnd) || extraParams.GetOpenings().Count > 0) { return(false); } representations3D.Add(bodyRepHnd); repMapTrfList.Add(null); } typeInfo.StyleTransform = ExporterIFCUtils.GetUnscaledTransform(exporterIFC, extraParams.GetLocalPlacement()); IFCAnyHandle typeStyle = FamilyInstanceExporter.CreateTypeEntityHandle(exporterIFC, ref typeInfo, null, representations3D, repMapTrfList, null, element, elementType, elementType, false, false, exportType, out HashSet <IFCAnyHandle> propertySets); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(typeStyle)) { wrapper.RegisterHandleWithElementType(elementType, exportType, typeStyle, propertySets); typeInfo.Style = typeStyle; CategoryUtil.TryToCreateMaterialAssocation(exporterIFC, bodyData, elementType, element, exportGeometry, typeStyle, typeInfo); // Create other generic classification from ClassificationCode(s) ClassificationUtil.CreateClassification(exporterIFC, file, elementType, typeStyle); ClassificationUtil.CreateUniformatClassification(exporterIFC, file, elementType, typeStyle); } } if (found && !typeInfo.IsValid()) { typeInfo = currentTypeInfo; } // we'll pretend we succeeded, but we'll do nothing. if (!typeInfo.IsValid()) { return(false); } extraParams = typeInfo.extraParams; // We expect no openings, so always add to map. ExporterCacheManager.FamilySymbolToTypeInfoCache.Register(symbolId, false, exportType, typeInfo); XYZ scaledMapOrigin = XYZ.Zero; Transform scaledTrf = originalTrf.Multiply(typeInfo.StyleTransform); // create instance. IList <IFCAnyHandle> shapeReps = FamilyInstanceExporter.CreateShapeRepresentations(exporterIFC, file, element, categoryId, typeInfo, scaledMapOrigin); if (shapeReps == null) { return(false); } Transform boundingBoxTrf = (offsetTransform != null) ? offsetTransform.Inverse : Transform.Identity; boundingBoxTrf = boundingBoxTrf.Multiply(scaledTrf.Inverse); IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geomElem, boundingBoxTrf); if (boundingBoxRep != null) { shapeReps.Add(boundingBoxRep); } IFCAnyHandle repHnd = (shapeReps.Count > 0) ? IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, shapeReps) : null; using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, element, scaledTrf, null)) { IFCAnyHandle instanceHandle = null; IFCAnyHandle localPlacement = setter.LocalPlacement; bool materialAlreadyAssociated = false; // We won't create the instance if: // (1) we are exporting to CV2.0/RV, (2) we have no 2D, 3D, or bounding box geometry, and (3) we aren't exporting parts. if (!(repHnd == null && (ExporterCacheManager.ExportOptionsCache.ExportAsCoordinationView2 || ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView))) { string instanceGUID = GUIDUtil.CreateGUID(element); bool isChildInContainer = element.AssemblyInstanceId != ElementId.InvalidElementId; if (IFCAnyHandleUtil.IsNullOrHasNoValue(instanceHandle)) { bool isBuildingElementProxy = ((exportType.ExportInstance == IFCEntityType.IfcBuildingElementProxy) || (exportType.ExportType == IFCEntityType.IfcBuildingElementProxyType)); ElementId roomId = setter.UpdateRoomRelativeCoordinates(element, out IFCAnyHandle localPlacementToUse); bool containedInSpace = (roomId != ElementId.InvalidElementId) && (exportType.ExportInstance != IFCEntityType.IfcSystemFurnitureElement); IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle; if (!isBuildingElementProxy) { instanceHandle = IFCInstanceExporter.CreateGenericIFCEntity(exportType, exporterIFC, element, instanceGUID, ownerHistory, localPlacementToUse, repHnd); } else { instanceHandle = IFCInstanceExporter.CreateBuildingElementProxy(exporterIFC, element, instanceGUID, ownerHistory, localPlacementToUse, repHnd, exportType.ValidatedPredefinedType); } bool associateToLevel = !containedInSpace && !isChildInContainer; wrapper.AddElement(element, instanceHandle, setter, extraParams, associateToLevel, exportType); if (containedInSpace) { ExporterCacheManager.SpaceInfoCache.RelateToSpace(roomId, instanceHandle); } } if (!IFCAnyHandleUtil.IsNullOrHasNoValue(instanceHandle)) { if (ElementFilteringUtil.IsMEPType(exportType) || ElementFilteringUtil.ProxyForMEPType(element, exportType)) { ExporterCacheManager.MEPCache.Register(element, instanceHandle); } ExporterCacheManager.HandleToElementCache.Register(instanceHandle, element.Id); if (!materialAlreadyAssociated) { // Create material association for the instance only if the the istance geometry is different from the type // or the type does not have any material association IFCAnyHandle constituentSetHnd = ExporterCacheManager.MaterialSetCache.FindConstituentSetHnd(symbolId); if (IFCAnyHandleUtil.IsNullOrHasNoValue(constituentSetHnd) && bodyData != null && bodyData.RepresentationItemInfo != null && bodyData.RepresentationItemInfo.Count > 0) { CategoryUtil.CreateMaterialAssociationWithShapeAspect(exporterIFC, element, instanceHandle, bodyData.RepresentationItemInfo); } else { // Create material association in case if bodyData is null CategoryUtil.CreateMaterialAssociation(exporterIFC, instanceHandle, typeInfo.MaterialIdList); } } if (!IFCAnyHandleUtil.IsNullOrHasNoValue(typeInfo.Style)) { ExporterCacheManager.TypeRelationsCache.Add(typeInfo.Style, instanceHandle); } } } } return(true); }
/// <summary> /// Exports a beam to IFC beam if it has an axis representation and only one Solid as its geometry, ideally as an extrusion, potentially with clippings and openings. /// </summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="element">The element to be exported.</param> /// <param name="geometryElement">The geometry element.</param> /// <param name="productWrapper">The ProductWrapper.</param> /// <param name="dontExport">An output value that says that the element shouldn't be exported at all.</param> /// <returns>The created handle.</returns> /// <remarks>In the original implementation, the ExportBeam function would export each beam as its own individual geometry (that is, not use representation maps). /// For non-standard beams, this could result in massive IFC files. Now, we use the ExportBeamAsStandardElement function and limit its scope, and instead /// resort to the standard FamilyInstanceExporter.ExportFamilyInstanceAsMappedItem for more complicated objects categorized as beams. This has the following pros and cons: /// Pro: possiblity for massively reduced file sizes for files containing repeated complex beam families /// Con: some beams that may have had an "Axis" representation before will no longer have them, although this possibility is minimized. /// Con: some beams that have 1 Solid and an axis, but that Solid will be heavily faceted, won't be helped by this improvement. /// It is intended that we phase out this routine entirely and instead teach ExportFamilyInstanceAsMappedItem how to sometimes export the Axis representation for beams.</remarks> public static IFCAnyHandle ExportBeamAsStandardElement(ExporterIFC exporterIFC, Element element, GeometryElement geometryElement, ProductWrapper productWrapper, out bool dontExport) { dontExport = true; IList <GeometryObject> geomObjects = BeamGeometryToExport(exporterIFC, element, geometryElement, out dontExport); if (dontExport) { return(null); } IFCAnyHandle beam = null; IFCFile file = exporterIFC.GetFile(); using (IFCTransaction transaction = new IFCTransaction(file)) { BeamAxisInfo axisInfo = GetBeamAxisTransform(element); bool canExportAxis = (axisInfo != null); Curve curve = canExportAxis ? axisInfo.Axis : null; XYZ beamDirection = canExportAxis ? axisInfo.AxisDirection : null; Transform orientTrf = canExportAxis ? axisInfo.LCSAsTransform : null; using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, element, null, orientTrf)) { IFCAnyHandle localPlacement = setter.LocalPlacement; using (IFCExtrusionCreationData extrusionCreationData = new IFCExtrusionCreationData()) { extrusionCreationData.SetLocalPlacement(localPlacement); if (canExportAxis && (orientTrf.BasisX != null)) { extrusionCreationData.CustomAxis = beamDirection; extrusionCreationData.PossibleExtrusionAxes = IFCExtrusionAxes.TryCustom; } else { extrusionCreationData.PossibleExtrusionAxes = IFCExtrusionAxes.TryXY; } ElementId catId = CategoryUtil.GetSafeCategoryId(element); // There may be an offset to make the local coordinate system // be near the origin. This offset will be used to move the axis to the new LCS. Transform offsetTransform = null; // The list of materials in the solids or meshes. ICollection <ElementId> materialIds = null; // The representation handle generated from one of the methods below. BeamBodyAsExtrusionInfo extrusionInfo = CreateBeamGeometryAsExtrusion(exporterIFC, element, catId, geomObjects, axisInfo); if (extrusionInfo != null && extrusionInfo.DontExport) { dontExport = true; return(null); } IFCAnyHandle repHnd = (extrusionInfo != null) ? extrusionInfo.RepresentationHandle : null; if (!IFCAnyHandleUtil.IsNullOrHasNoValue(repHnd)) { materialIds = extrusionInfo.Materials; extrusionCreationData.Slope = extrusionInfo.Slope; } else { // Here is where we limit the scope of how complex a case we will still try to export as a standard element. // This is explicitly added so that many curved beams that can be represented by a reasonable facetation because of the // SweptSolidExporter can still have an Axis representation. BodyData bodyData = null; BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true, ExportOptionsCache.ExportTessellationLevel.ExtraLow); if (geomObjects != null && geomObjects.Count == 1 && geomObjects[0] is Solid) { bodyData = BodyExporter.ExportBody(exporterIFC, element, catId, ElementId.InvalidElementId, geomObjects[0], bodyExporterOptions, extrusionCreationData); repHnd = bodyData.RepresentationHnd; materialIds = bodyData.MaterialIds; offsetTransform = bodyData.OffsetTransform; } } if (IFCAnyHandleUtil.IsNullOrHasNoValue(repHnd)) { extrusionCreationData.ClearOpenings(); return(null); } IList <IFCAnyHandle> representations = new List <IFCAnyHandle>(); IFCAnyHandle axisRep = CreateBeamAxis(exporterIFC, element, catId, axisInfo, offsetTransform); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(axisRep)) { representations.Add(axisRep); } representations.Add(repHnd); Transform boundingBoxTrf = (offsetTransform == null) ? Transform.Identity : offsetTransform.Inverse; IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geometryElement, boundingBoxTrf); if (boundingBoxRep != null) { representations.Add(boundingBoxRep); } IFCAnyHandle prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations); string instanceGUID = GUIDUtil.CreateGUID(element); string instanceName = NamingUtil.GetNameOverride(element, NamingUtil.GetIFCName(element)); string instanceDescription = NamingUtil.GetDescriptionOverride(element, null); string instanceObjectType = NamingUtil.GetObjectTypeOverride(element, NamingUtil.CreateIFCObjectName(exporterIFC, element)); string instanceTag = NamingUtil.GetTagOverride(element, NamingUtil.CreateIFCElementId(element)); string preDefinedType = "BEAM"; // Default predefined type for Beam preDefinedType = IFCValidateEntry.GetValidIFCType(element, preDefinedType); beam = IFCInstanceExporter.CreateBeam(file, instanceGUID, ExporterCacheManager.OwnerHistoryHandle, instanceName, instanceDescription, instanceObjectType, extrusionCreationData.GetLocalPlacement(), prodRep, instanceTag, preDefinedType); productWrapper.AddElement(element, beam, setter, extrusionCreationData, true); OpeningUtil.CreateOpeningsIfNecessary(beam, element, extrusionCreationData, offsetTransform, exporterIFC, extrusionCreationData.GetLocalPlacement(), setter, productWrapper); FamilyTypeInfo typeInfo = new FamilyTypeInfo(); typeInfo.ScaledDepth = extrusionCreationData.ScaledLength; typeInfo.ScaledArea = extrusionCreationData.ScaledArea; typeInfo.ScaledInnerPerimeter = extrusionCreationData.ScaledInnerPerimeter; typeInfo.ScaledOuterPerimeter = extrusionCreationData.ScaledOuterPerimeter; PropertyUtil.CreateBeamColumnBaseQuantities(exporterIFC, beam, element, typeInfo, null); if (materialIds.Count != 0) { CategoryUtil.CreateMaterialAssociations(exporterIFC, beam, materialIds); } // Register the beam's IFC handle for later use by truss and beam system export. ExporterCacheManager.ElementToHandleCache.Register(element.Id, beam); } } transaction.Commit(); return(beam); } }
/// <summary> /// Exports a roof to IfcRoof. /// </summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="roof">The roof element.</param> /// <param name="geometryElement">The geometry element.</param> /// <param name="productWrapper">The ProductWrapper.</param> /// <param name="exportRoofAsSingleGeometry">Export roof as single geometry.</param> public static void ExportRoof(ExporterIFC exporterIFC, Element roof, ref GeometryElement geometryElement, ProductWrapper productWrapper, bool exportRoofAsSingleGeometry = false) { if (roof == null || geometryElement == null) { return; } string ifcEnumType; IFCExportInfoPair roofExportType = ExporterUtil.GetProductExportType(exporterIFC, roof, out ifcEnumType); if (roofExportType.IsUnKnown) { roofExportType = new IFCExportInfoPair(IFCEntityType.IfcRoof, ""); } MaterialLayerSetInfo layersetInfo = new MaterialLayerSetInfo(exporterIFC, roof, productWrapper); IFCFile file = exporterIFC.GetFile(); Document doc = roof.Document; using (SubTransaction tempPartTransaction = new SubTransaction(doc)) { // For IFC4RV export, Roof will be split into its parts(temporarily) in order to export the roof by its parts ExporterUtil.CreateParts(roof, layersetInfo.MaterialIds.Count, ref geometryElement); bool exportByComponents = ExporterUtil.CanExportByComponentsOrParts(roof) == ExporterUtil.ExportPartAs.ShapeAspect; using (IFCTransaction tr = new IFCTransaction(file)) { // Check for containment override IFCAnyHandle overrideContainerHnd = null; ElementId overrideContainerId = ParameterUtil.OverrideContainmentParameter(exporterIFC, roof, out overrideContainerHnd); using (PlacementSetter placementSetter = PlacementSetter.Create(exporterIFC, roof, null, null, overrideContainerId, overrideContainerHnd)) { using (IFCExtrusionCreationData ecData = new IFCExtrusionCreationData()) { // If the roof is an in-place family, we will allow any arbitrary orientation. While this may result in some // in-place "cubes" exporting with the wrong direction, it is unlikely that an in-place family would be // used for this reason in the first place. ecData.PossibleExtrusionAxes = (roof is FamilyInstance) ? IFCExtrusionAxes.TryXYZ : IFCExtrusionAxes.TryZ; ecData.AreInnerRegionsOpenings = true; ecData.SetLocalPlacement(placementSetter.LocalPlacement); ElementId categoryId = CategoryUtil.GetSafeCategoryId(roof); BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true, ExportOptionsCache.ExportTessellationLevel.ExtraLow); BodyData bodyData = null; IFCAnyHandle prodRep = null; IList <IFCAnyHandle> representations = new List <IFCAnyHandle>(); IList <ElementId> materialIds = new List <ElementId>(); if (!exportByComponents) { prodRep = RepresentationUtil.CreateAppropriateProductDefinitionShape(exporterIFC, roof, categoryId, geometryElement, bodyExporterOptions, null, ecData, out bodyData); if (bodyData != null && bodyData.MaterialIds != null) { materialIds = bodyData.MaterialIds; } } else { prodRep = RepresentationUtil.CreateProductDefinitionShapeWithoutBodyRep(exporterIFC, roof, categoryId, geometryElement, representations); } if (IFCAnyHandleUtil.IsNullOrHasNoValue(prodRep)) { ecData.ClearOpenings(); return; } bool exportSlab = ((ecData.ScaledLength > MathUtil.Eps() || exportByComponents) && roofExportType.ExportInstance == IFCEntityType.IfcRoof && !exportRoofAsSingleGeometry); string guid = GUIDUtil.CreateGUID(roof); IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle; IFCAnyHandle localPlacement = ecData.GetLocalPlacement(); IFCAnyHandle roofHnd = IFCInstanceExporter.CreateGenericIFCEntity( roofExportType, exporterIFC, roof, guid, ownerHistory, localPlacement, exportSlab ? null : prodRep); IFCAnyHandle typeHnd = ExporterUtil.CreateGenericTypeFromElement(roof, roofExportType, file, ownerHistory, roofExportType.ValidatedPredefinedType, productWrapper); ExporterCacheManager.TypeRelationsCache.Add(typeHnd, roofHnd); productWrapper.AddElement(roof, roofHnd, placementSetter.LevelInfo, ecData, true, roofExportType); if (!(roof is RoofBase)) { CategoryUtil.CreateMaterialAssociation(exporterIFC, roofHnd, materialIds); } if (exportByComponents && (exportSlab || exportRoofAsSingleGeometry)) { IFCAnyHandle hostShapeRepFromParts = PartExporter.ExportHostPartAsShapeAspects(exporterIFC, roof, prodRep, productWrapper, placementSetter, localPlacement, ElementId.InvalidElementId, layersetInfo, ecData); } Transform offsetTransform = (bodyData != null) ? bodyData.OffsetTransform : Transform.Identity; if (exportSlab) { string slabGUID = GUIDUtil.CreateSubElementGUID(roof, (int)IFCRoofSubElements.RoofSlabStart); IFCAnyHandle slabLocalPlacementHnd = ExporterUtil.CopyLocalPlacement(file, localPlacement); string slabName = IFCAnyHandleUtil.GetStringAttribute(roofHnd, "Name") + ":1"; IFCAnyHandle slabHnd = IFCInstanceExporter.CreateSlab(exporterIFC, roof, slabGUID, ownerHistory, slabLocalPlacementHnd, prodRep, slabRoofPredefinedType); IFCAnyHandleUtil.OverrideNameAttribute(slabHnd, slabName); OpeningUtil.CreateOpeningsIfNecessary(slabHnd, roof, ecData, offsetTransform, exporterIFC, slabLocalPlacementHnd, placementSetter, productWrapper); ExporterUtil.RelateObject(exporterIFC, roofHnd, slabHnd); IFCExportInfoPair slabRoofExportType = new IFCExportInfoPair(IFCEntityType.IfcSlab, slabRoofPredefinedType); productWrapper.AddElement(null, slabHnd, placementSetter.LevelInfo, ecData, false, slabRoofExportType); // Create type IFCAnyHandle slabRoofTypeHnd = ExporterUtil.CreateGenericTypeFromElement(roof, slabRoofExportType, exporterIFC.GetFile(), ownerHistory, slabRoofPredefinedType, productWrapper); ExporterCacheManager.TypeRelationsCache.Add(slabRoofTypeHnd, slabHnd); ExporterUtil.AddIntoComplexPropertyCache(slabHnd, layersetInfo); // For earlier than IFC4 version of IFC export, the material association will be done at the Roof host level with MaterialSetUsage // This one is only for IFC4 and above if ((roof is RoofBase) && !ExporterCacheManager.ExportOptionsCache.ExportAsOlderThanIFC4) { if (layersetInfo != null && !IFCAnyHandleUtil.IsNullOrHasNoValue(layersetInfo.MaterialLayerSetHandle)) { CategoryUtil.CreateMaterialAssociation(exporterIFC, slabHnd, layersetInfo.MaterialLayerSetHandle); } else if (bodyData != null) { CategoryUtil.CreateMaterialAssociation(exporterIFC, slabHnd, bodyData.MaterialIds); } } } else { OpeningUtil.CreateOpeningsIfNecessary(roofHnd, roof, ecData, offsetTransform, exporterIFC, localPlacement, placementSetter, productWrapper); // For earlier than IFC4 version of IFC export, the material association will be done at the Roof host level with MaterialSetUsage // This one is only for IFC4 and above if ((roof is RoofBase) && !ExporterCacheManager.ExportOptionsCache.ExportAsOlderThanIFC4) { if (layersetInfo != null && !IFCAnyHandleUtil.IsNullOrHasNoValue(layersetInfo.MaterialLayerSetHandle)) { CategoryUtil.CreateMaterialAssociation(exporterIFC, roofHnd, layersetInfo.MaterialLayerSetHandle); } else if (layersetInfo != null && layersetInfo.MaterialIds != null) { materialIds = layersetInfo.MaterialIds.Select(x => x.m_baseMatId).ToList(); CategoryUtil.CreateMaterialAssociation(exporterIFC, roofHnd, materialIds); } } } } tr.Commit(); } } } }
/// <summary> /// Exports a MEP family instance. /// </summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="element">The element.</param> /// <param name="geometryElement">The geometry element.</param> /// <param name="exportType">The export type of the element. /// <param name="ifcEnumType">The sub-type of the element.</param></param> /// <param name="productWrapper">The ProductWrapper.</param> /// <returns>True if an entity was created, false otherwise.</returns> public static bool Export(ExporterIFC exporterIFC, Element element, GeometryElement geometryElement, IFCExportType exportType, string ifcEnumType, ProductWrapper productWrapper) { IFCFile file = exporterIFC.GetFile(); using (IFCTransaction tr = new IFCTransaction(file)) { using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, element)) { IFCAnyHandle localPlacementToUse = setter.LocalPlacement; using (IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData()) { extraParams.SetLocalPlacement(localPlacementToUse); ElementId catId = CategoryUtil.GetSafeCategoryId(element); BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true); BodyData bodyData = null; IFCAnyHandle productRepresentation = RepresentationUtil.CreateAppropriateProductDefinitionShape(exporterIFC, element, catId, geometryElement, bodyExporterOptions, null, extraParams, out bodyData); if (IFCAnyHandleUtil.IsNullOrHasNoValue(productRepresentation)) { extraParams.ClearOpenings(); return(false); } IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle(); ElementId typeId = element.GetTypeId(); ElementType type = element.Document.GetElement(typeId) as ElementType; FamilyTypeInfo currentTypeInfo = ExporterCacheManager.TypeObjectsCache.Find(typeId, false); bool found = currentTypeInfo.IsValid(); if (!found) { string typeGUID = GUIDUtil.CreateGUID(type); string typeName = NamingUtil.GetNameOverride(type, NamingUtil.GetIFCName(type)); string typeObjectType = NamingUtil.GetObjectTypeOverride(type, NamingUtil.CreateIFCObjectName(exporterIFC, type)); string applicableOccurence = NamingUtil.GetOverrideStringValue(type, "IfcApplicableOccurrence", typeObjectType); string typeDescription = NamingUtil.GetDescriptionOverride(type, null); string typeTag = NamingUtil.GetTagOverride(type, NamingUtil.CreateIFCElementId(type)); string typeElementType = NamingUtil.GetOverrideStringValue(type, "IfcElementType", typeName); IList <IFCAnyHandle> repMapListOpt = new List <IFCAnyHandle>(); IFCAnyHandle styleHandle = FamilyExporterUtil.ExportGenericType(exporterIFC, exportType, ifcEnumType, typeGUID, typeName, typeDescription, applicableOccurence, null, repMapListOpt, typeTag, typeElementType, element, type); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(styleHandle)) { productWrapper.RegisterHandleWithElementType(type, styleHandle, null); currentTypeInfo.Style = styleHandle; ExporterCacheManager.TypeObjectsCache.Register(typeId, false, currentTypeInfo); } } string instanceGUID = GUIDUtil.CreateGUID(element); string instanceName = NamingUtil.GetNameOverride(element, NamingUtil.GetIFCName(element)); string instanceObjectType = NamingUtil.GetObjectTypeOverride(element, NamingUtil.CreateIFCObjectName(exporterIFC, element)); string instanceDescription = NamingUtil.GetDescriptionOverride(element, null); string instanceTag = NamingUtil.GetTagOverride(element, NamingUtil.CreateIFCElementId(element)); bool roomRelated = !FamilyExporterUtil.IsDistributionFlowElementSubType(exportType); ElementId roomId = ElementId.InvalidElementId; if (roomRelated) { roomId = setter.UpdateRoomRelativeCoordinates(element, out localPlacementToUse); } IFCAnyHandle instanceHandle = null; // For MEP objects string exportEntityStr = exportType.ToString(); Common.Enums.IFCEntityType exportEntity; if (String.Compare(exportEntityStr.Substring(exportEntityStr.Length - 4), "Type", true) == 0) { exportEntityStr = exportEntityStr.Substring(0, (exportEntityStr.Length - 4)); } if (Enum.TryParse(exportEntityStr, out exportEntity)) { // For MEP object creation instanceHandle = IFCInstanceExporter.CreateGenericIFCEntity(exportEntity, file, instanceGUID, ownerHistory, instanceName, instanceDescription, instanceObjectType, localPlacementToUse, productRepresentation, instanceTag); } if (IFCAnyHandleUtil.IsNullOrHasNoValue(instanceHandle)) { return(false); } bool relatedToSpace = (roomId != ElementId.InvalidElementId); productWrapper.AddElement(element, instanceHandle, setter, extraParams, !relatedToSpace); if (relatedToSpace) { ExporterCacheManager.SpaceInfoCache.RelateToSpace(roomId, instanceHandle); } OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, element, extraParams, null, exporterIFC, localPlacementToUse, setter, productWrapper); if (currentTypeInfo.IsValid()) { ExporterCacheManager.TypeRelationsCache.Add(currentTypeInfo.Style, instanceHandle); } if (bodyData != null && bodyData.MaterialIds.Count != 0) { CategoryUtil.CreateMaterialAssociations(exporterIFC, instanceHandle, bodyData.MaterialIds); } ExporterCacheManager.MEPCache.Register(element, instanceHandle); tr.Commit(); } } } return(true); }
/// <summary> /// Exports list of geometries to IFC body representation. /// </summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="categoryId">The category id.</param> /// <param name="geometryListIn">The geometry list.</param> /// <param name="options">The settings for how to export the body.</param> /// <param name="exportBodyParams">The extrusion creation data.</param> /// <returns>The BodyData containing the handle, offset and material ids.</returns> public static BodyData ExportBody(ExporterIFC exporterIFC, Element element, ElementId categoryId, ElementId overrideMaterialId, IList<GeometryObject> geometryList, BodyExporterOptions options, IFCExtrusionCreationData exportBodyParams) { BodyData bodyData = new BodyData(); if (geometryList.Count == 0) return bodyData; Document document = element.Document; bool tryToExportAsExtrusion = options.TryToExportAsExtrusion; bool canExportSolidModelRep = tryToExportAsExtrusion && ExporterCacheManager.ExportOptionsCache.CanExportSolidModelRep; bool useCoarseTessellation = (ExporterCacheManager.ExportOptionsCache.LevelOfDetail < 4); bool allowAdvancedBReps = ExporterCacheManager.ExportOptionsCache.ExportAs4 && !ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView; // We will try to export as a swept solid if the option is set, and we are either exporting to a schema that allows it, // or we are using a coarse tessellation, in which case we will export the swept solid as an optimzed BRep. bool tryToExportAsSweptSolid = options.TryToExportAsSweptSolid && (allowAdvancedBReps || useCoarseTessellation); // We will allow exporting swept solids as BReps or TriangulatedFaceSet if we are exporting to a schema before IFC4, or to a Reference View MVD, // and we allow coarse representations. In the future, we may allow more control here. // Note that we disable IFC4 because in IFC4, we will export it as a true swept solid instead, except for the Reference View MVD. bool tryToExportAsSweptSolidAsTessellation = tryToExportAsSweptSolid && useCoarseTessellation && !allowAdvancedBReps; IFCFile file = exporterIFC.GetFile(); IFCAnyHandle contextOfItems = exporterIFC.Get3DContextHandle("Body"); double eps = UnitUtil.ScaleLength(element.Document.Application.VertexTolerance); bool allFaces = true; foreach (GeometryObject geomObject in geometryList) { if (!(geomObject is Face)) { allFaces = false; break; } } IList<IFCAnyHandle> bodyItems = new List<IFCAnyHandle>(); IList<ElementId> materialIdsForExtrusions = new List<ElementId>(); // This is a list of geometries that can be exported using the coarse facetation of the SweptSolidExporter. IList<KeyValuePair<int, SimpleSweptSolidAnalyzer>> exportAsBRep = new List<KeyValuePair<int, SimpleSweptSolidAnalyzer>>(); IList<int> exportAsSweptSolid = new List<int>(); IList<int> exportAsExtrusion = new List<int>(); bool hasExtrusions = false; bool hasSweptSolids = false; bool hasSweptSolidsAsBReps = false; ShapeRepresentationType hasRepresentationType = ShapeRepresentationType.Undefined; BoundingBoxXYZ bbox = GeometryUtil.GetBBoxOfGeometries(geometryList); XYZ unscaledTrfOrig = new XYZ(); int numItems = geometryList.Count; bool tryExtrusionAnalyzer = tryToExportAsExtrusion && (options.ExtrusionLocalCoordinateSystem != null) && (numItems == 1) && (geometryList[0] is Solid); bool supportOffsetTransformForExtrusions = !(tryExtrusionAnalyzer || tryToExportAsSweptSolidAsTessellation); bool useOffsetTransformForExtrusions = (options.AllowOffsetTransform && supportOffsetTransformForExtrusions && (exportBodyParams != null)); using (IFCTransaction tr = new IFCTransaction(file)) { // generate "bottom corner" of bbox; create new local placement if passed in. // need to transform, but not scale, this point to make it the new origin. using (TransformSetter transformSetter = TransformSetter.Create()) { if (useOffsetTransformForExtrusions) bodyData.OffsetTransform = transformSetter.InitializeFromBoundingBox(exporterIFC, bbox, exportBodyParams, out unscaledTrfOrig); // If we passed in an ExtrusionLocalCoordinateSystem, and we have 1 Solid, we will try to create an extrusion using the ExtrusionAnalyzer. // If we succeed, we will skip the rest of the routine, otherwise we will try with the backup extrusion method. // This doesn't yet create fallback information for solid models that are hybrid extrusions and BReps. if (tryToExportAsExtrusion) { if (tryExtrusionAnalyzer) { using (IFCTransaction extrusionTransaction = new IFCTransaction(file)) { Plane extrusionPlane = new Plane( options.ExtrusionLocalCoordinateSystem.BasisY, options.ExtrusionLocalCoordinateSystem.BasisZ, options.ExtrusionLocalCoordinateSystem.Origin); XYZ extrusionDirection = options.ExtrusionLocalCoordinateSystem.BasisX; bool completelyClipped; HandleAndData extrusionData = ExtrusionExporter.CreateExtrusionWithClippingAndProperties(exporterIFC, element, CategoryUtil.GetSafeCategoryId(element), geometryList[0] as Solid, extrusionPlane, extrusionDirection, null, out completelyClipped); if (!completelyClipped && !IFCAnyHandleUtil.IsNullOrHasNoValue(extrusionData.Handle) && extrusionData.BaseExtrusions != null && extrusionData.BaseExtrusions.Count == 1) { HashSet<ElementId> materialIds = extrusionData.MaterialIds; // We skip setting and getting the material id from the exporter as unnecessary. ElementId matIdFromGeom = (materialIds != null && materialIds.Count > 0) ? materialIds.First() : ElementId.InvalidElementId; ElementId matId = (overrideMaterialId != ElementId.InvalidElementId) ? overrideMaterialId : matIdFromGeom; bodyItems.Add(extrusionData.BaseExtrusions[0]); materialIdsForExtrusions.Add(matId); if (matId != ElementId.InvalidElementId) bodyData.AddMaterial(matId); bodyData.RepresentationHnd = extrusionData.Handle; bodyData.ShapeRepresentationType = extrusionData.ShapeRepresentationType; if (exportBodyParams != null && extrusionData.Data != null) { exportBodyParams.Slope = extrusionData.Data.Slope; exportBodyParams.ScaledLength = extrusionData.Data.ScaledLength; exportBodyParams.ExtrusionDirection = extrusionData.Data.ExtrusionDirection; exportBodyParams.ScaledHeight = extrusionData.Data.ScaledHeight; exportBodyParams.ScaledWidth = extrusionData.Data.ScaledWidth; exportBodyParams.ScaledArea = extrusionData.Data.ScaledArea; exportBodyParams.ScaledInnerPerimeter = extrusionData.Data.ScaledInnerPerimeter; exportBodyParams.ScaledOuterPerimeter = extrusionData.Data.ScaledOuterPerimeter; } hasExtrusions = true; extrusionTransaction.Commit(); } else { extrusionTransaction.RollBack(); } } } // Only try if ExtrusionAnalyzer wasn't called, or failed. if (!hasExtrusions) { // Check to see if we have Geometries or GFaces. // We will have the specific all GFaces case and then the generic case. IList<Face> faces = null; if (allFaces) { faces = new List<Face>(); foreach (GeometryObject geometryObject in geometryList) { faces.Add(geometryObject as Face); } } // Options used if we try to export extrusions. IFCExtrusionAxes axesToExtrudeIn = exportBodyParams != null ? exportBodyParams.PossibleExtrusionAxes : IFCExtrusionAxes.TryDefault; XYZ directionToExtrudeIn = XYZ.Zero; if (exportBodyParams != null && exportBodyParams.HasCustomAxis) directionToExtrudeIn = exportBodyParams.CustomAxis; double lengthScale = UnitUtil.ScaleLengthForRevitAPI(); IFCExtrusionCalculatorOptions extrusionOptions = new IFCExtrusionCalculatorOptions(exporterIFC, axesToExtrudeIn, directionToExtrudeIn, lengthScale); int numExtrusionsToCreate = allFaces ? 1 : geometryList.Count; IList<IList<IFCExtrusionData>> extrusionLists = new List<IList<IFCExtrusionData>>(); for (int ii = 0; ii < numExtrusionsToCreate; ii++) { IList<IFCExtrusionData> extrusionList = new List<IFCExtrusionData>(); if (tryToExportAsExtrusion) { if (allFaces) extrusionList = IFCExtrusionCalculatorUtils.CalculateExtrusionData(extrusionOptions, faces); else extrusionList = IFCExtrusionCalculatorUtils.CalculateExtrusionData(extrusionOptions, geometryList[ii]); } if (extrusionList.Count == 0) { // If we are trying to create swept solids, we will keep going, but we won't try to create more extrusions unless we are also exporting a solid model. if (tryToExportAsSweptSolid) { if (!canExportSolidModelRep) tryToExportAsExtrusion = false; exportAsSweptSolid.Add(ii); } else if (!canExportSolidModelRep) { tryToExportAsExtrusion = false; break; } else exportAsBRep.Add(new KeyValuePair<int, SimpleSweptSolidAnalyzer>(ii, null)); } else { extrusionLists.Add(extrusionList); exportAsExtrusion.Add(ii); } } int numCreatedExtrusions = extrusionLists.Count; for (int ii = 0; ii < numCreatedExtrusions && tryToExportAsExtrusion; ii++) { int geomIndex = exportAsExtrusion[ii]; ElementId matId = SetBestMaterialIdInExporter(geometryList[geomIndex], element, overrideMaterialId, exporterIFC); if (matId != ElementId.InvalidElementId) bodyData.AddMaterial(matId); if (exportBodyParams != null && exportBodyParams.AreInnerRegionsOpenings) { IList<CurveLoop> curveLoops = extrusionLists[ii][0].GetLoops(); XYZ extrudedDirection = extrusionLists[ii][0].ExtrusionDirection; int numLoops = curveLoops.Count; for (int jj = numLoops - 1; jj > 0; jj--) { ExtrusionExporter.AddOpeningData(exportBodyParams, extrusionLists[ii][0], curveLoops[jj]); extrusionLists[ii][0].RemoveLoopAt(jj); } } bool exportedAsExtrusion = false; IFCExtrusionBasis whichBasis = extrusionLists[ii][0].ExtrusionBasis; if (whichBasis >= 0) { IFCAnyHandle extrusionHandle = ExtrusionExporter.CreateExtrudedSolidFromExtrusionData(exporterIFC, element, extrusionLists[ii][0]); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(extrusionHandle)) { bodyItems.Add(extrusionHandle); materialIdsForExtrusions.Add(exporterIFC.GetMaterialIdForCurrentExportState()); IList<CurveLoop> curveLoops = extrusionLists[ii][0].GetLoops(); XYZ extrusionDirection = extrusionLists[ii][0].ExtrusionDirection; if (exportBodyParams != null) { exportBodyParams.Slope = GeometryUtil.GetSimpleExtrusionSlope(extrusionDirection, whichBasis); exportBodyParams.ScaledLength = extrusionLists[ii][0].ScaledExtrusionLength; exportBodyParams.ExtrusionDirection = extrusionDirection; for (int kk = 1; kk < extrusionLists[ii].Count; kk++) { ExtrusionExporter.AddOpeningData(exportBodyParams, extrusionLists[ii][kk]); } Plane plane = null; double height = 0.0, width = 0.0; if (ExtrusionExporter.ComputeHeightWidthOfCurveLoop(curveLoops[0], plane, out height, out width)) { exportBodyParams.ScaledHeight = UnitUtil.ScaleLength(height); exportBodyParams.ScaledWidth = UnitUtil.ScaleLength(width); } double area = ExporterIFCUtils.ComputeAreaOfCurveLoops(curveLoops); if (area > 0.0) { exportBodyParams.ScaledArea = UnitUtil.ScaleArea(area); } double innerPerimeter = ExtrusionExporter.ComputeInnerPerimeterOfCurveLoops(curveLoops); double outerPerimeter = ExtrusionExporter.ComputeOuterPerimeterOfCurveLoops(curveLoops); if (innerPerimeter > 0.0) exportBodyParams.ScaledInnerPerimeter = UnitUtil.ScaleLength(innerPerimeter); if (outerPerimeter > 0.0) exportBodyParams.ScaledOuterPerimeter = UnitUtil.ScaleLength(outerPerimeter); } exportedAsExtrusion = true; hasExtrusions = true; } } if (!exportedAsExtrusion) { if (tryToExportAsSweptSolid) exportAsSweptSolid.Add(ii); else if (!canExportSolidModelRep) { tryToExportAsExtrusion = false; break; } else exportAsBRep.Add(new KeyValuePair<int, SimpleSweptSolidAnalyzer>(ii, null)); } } } } if (tryToExportAsSweptSolid) { int numCreatedSweptSolids = exportAsSweptSolid.Count; for (int ii = 0; (ii < numCreatedSweptSolids) && tryToExportAsSweptSolid; ii++) { bool exported = false; int geomIndex = exportAsSweptSolid[ii]; Solid solid = geometryList[geomIndex] as Solid; SimpleSweptSolidAnalyzer simpleSweptSolidAnalyzer = null; // TODO: allFaces to SweptSolid if (solid != null) { // TODO: give normal hint below if we have an idea. simpleSweptSolidAnalyzer = SweptSolidExporter.CanExportAsSweptSolid(exporterIFC, solid, null); // If we are exporting as a BRep, we will keep the analyzer for later, if it isn't null. if (simpleSweptSolidAnalyzer != null) { if (!tryToExportAsSweptSolidAsTessellation) { SweptSolidExporter sweptSolidExporter = SweptSolidExporter.Create(exporterIFC, element, simpleSweptSolidAnalyzer, solid); IFCAnyHandle sweptHandle = (sweptSolidExporter != null) ? sweptSolidExporter.RepresentationItem : null; if (!IFCAnyHandleUtil.IsNullOrHasNoValue(sweptHandle)) { bodyItems.Add(sweptHandle); materialIdsForExtrusions.Add(exporterIFC.GetMaterialIdForCurrentExportState()); exported = true; hasRepresentationType = sweptSolidExporter.RepresentationType; // These are the only two valid cases for true sweep export: either an extrusion or a sweep. // We don't expect regular BReps or triangulated face sets here. if (sweptSolidExporter.isSpecificRepresentationType(ShapeRepresentationType.SweptSolid)) hasExtrusions = true; else if (sweptSolidExporter.isSpecificRepresentationType(ShapeRepresentationType.AdvancedSweptSolid)) hasSweptSolids = true; } else simpleSweptSolidAnalyzer = null; // Didn't work for some reason. } } } if (!exported) { exportAsBRep.Add(new KeyValuePair<int, SimpleSweptSolidAnalyzer>(geomIndex, simpleSweptSolidAnalyzer)); hasSweptSolidsAsBReps |= (simpleSweptSolidAnalyzer != null); } } } bool exportSucceeded = (exportAsBRep.Count == 0) && (tryToExportAsExtrusion || tryToExportAsSweptSolid) && (hasExtrusions || hasSweptSolids || hasRepresentationType != ShapeRepresentationType.Undefined); if (exportSucceeded || canExportSolidModelRep) { int sz = bodyItems.Count(); for (int ii = 0; ii < sz; ii++) BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, document, bodyItems[ii], materialIdsForExtrusions[ii]); if (exportSucceeded) { if (bodyData.RepresentationHnd == null) { HashSet<IFCAnyHandle> bodyItemSet = new HashSet<IFCAnyHandle>(); bodyItemSet.UnionWith(bodyItems); if (hasExtrusions && !hasSweptSolids) { bodyData.RepresentationHnd = RepresentationUtil.CreateSweptSolidRep(exporterIFC, element, categoryId, contextOfItems, bodyItemSet, bodyData.RepresentationHnd); bodyData.ShapeRepresentationType = ShapeRepresentationType.SweptSolid; } else if (hasSweptSolids && !hasExtrusions) { bodyData.RepresentationHnd = RepresentationUtil.CreateAdvancedSweptSolidRep(exporterIFC, element, categoryId, contextOfItems, bodyItemSet, bodyData.RepresentationHnd); bodyData.ShapeRepresentationType = ShapeRepresentationType.AdvancedSweptSolid; } else if (hasRepresentationType == ShapeRepresentationType.Tessellation) { bodyData.RepresentationHnd = RepresentationUtil.CreateTessellatedRep(exporterIFC, element, categoryId, contextOfItems, bodyItemSet, bodyData.RepresentationHnd); bodyData.ShapeRepresentationType = ShapeRepresentationType.Tessellation; } else { bodyData.RepresentationHnd = RepresentationUtil.CreateSolidModelRep(exporterIFC, element, categoryId, contextOfItems, bodyItemSet); bodyData.ShapeRepresentationType = ShapeRepresentationType.SolidModel; } } // TODO: include BRep, CSG, Clipping XYZ lpOrig = ((bodyData != null) && (bodyData.OffsetTransform != null)) ? bodyData.OffsetTransform.Origin : new XYZ(); transformSetter.CreateLocalPlacementFromOffset(exporterIFC, bbox, exportBodyParams, lpOrig, unscaledTrfOrig); tr.Commit(); return bodyData; } } // If we are going to export a solid model, keep the created items. if (!canExportSolidModelRep) tr.RollBack(); else tr.Commit(); } // We couldn't export it as an extrusion; export as a solid, brep, or a surface model. if (!canExportSolidModelRep) { exportAsExtrusion.Clear(); bodyItems.Clear(); if (exportBodyParams != null) exportBodyParams.ClearOpenings(); } if (exportAsExtrusion.Count == 0) { // We used to clear exportAsBRep, but we need the SimpleSweptSolidAnalyzer information, so we will fill out the rest. int numGeoms = geometryList.Count; IList<KeyValuePair<int, SimpleSweptSolidAnalyzer>> newExportAsBRep = new List<KeyValuePair<int, SimpleSweptSolidAnalyzer>>(numGeoms); int exportAsBRepCount = exportAsBRep.Count; int currIndex = 0; for (int ii = 0; ii < numGeoms; ii++) { if ((currIndex < exportAsBRepCount) && (ii == exportAsBRep[currIndex].Key)) { newExportAsBRep.Add(exportAsBRep[currIndex]); currIndex++; } else newExportAsBRep.Add(new KeyValuePair<int, SimpleSweptSolidAnalyzer>(ii, null)); } exportAsBRep = newExportAsBRep; } } // If we created some extrusions that we are using (e.g., creating a solid model), and we didn't use an offset transform for the extrusions, don't do it here either. bool supportOffsetTransformForBreps = !hasSweptSolidsAsBReps; bool disallowOffsetTransformForBreps = (exportAsExtrusion.Count > 0) && !useOffsetTransformForExtrusions; bool useOffsetTransformForBReps = options.AllowOffsetTransform && supportOffsetTransformForBreps && !disallowOffsetTransformForBreps; using (IFCTransaction tr = new IFCTransaction(file)) { using (TransformSetter transformSetter = TransformSetter.Create()) { // Need to do extra work to support offset transforms if we are using the sweep analyzer. if (useOffsetTransformForBReps) bodyData.OffsetTransform = transformSetter.InitializeFromBoundingBox(exporterIFC, bbox, exportBodyParams, out unscaledTrfOrig); BodyData brepBodyData = ExportBodyAsBRep(exporterIFC, geometryList, exportAsBRep, bodyItems, element, categoryId, overrideMaterialId, contextOfItems, eps, options, bodyData); if (brepBodyData == null) tr.RollBack(); else { XYZ lpOrig = ((bodyData != null) && (bodyData.OffsetTransform != null)) ? bodyData.OffsetTransform.Origin : new XYZ(); transformSetter.CreateLocalPlacementFromOffset(exporterIFC, bbox, exportBodyParams, lpOrig, unscaledTrfOrig); tr.Commit(); } return brepBodyData; } } }
private static bool ProcessGroupMembership(ExporterIFC exporterIFC, IFCFile file, Element element, ElementId categoryId, IFCAnyHandle contextOfItems, IList<GeometryObject> geomList, BodyData bodyDataIn, out BodyGroupKey groupKey, out BodyGroupData groupData, out BodyData bodyData) { // Set back to true if all checks are passed. bool useGroupsIfPossible = false; groupKey = null; groupData = null; bodyData = null; Document doc = element.Document; Group group = doc.GetElement(element.GroupId) as Group; if (group != null) { ElementId elementId = element.Id; bool pristineGeometry = true; foreach (GeometryObject geomObject in geomList) { try { ICollection<ElementId> generatingElementIds = element.GetGeneratingElementIds(geomObject); int numGeneratingElements = generatingElementIds.Count; if ((numGeneratingElements > 1) || (numGeneratingElements == 1 && (generatingElementIds.First() != elementId))) { pristineGeometry = false; break; } } catch { pristineGeometry = false; break; } } if (pristineGeometry) { groupKey = new BodyGroupKey(); IList<ElementId> groupMemberIds = group.GetMemberIds(); int numMembers = groupMemberIds.Count; for (int idx = 0; idx < numMembers; idx++) { if (groupMemberIds[idx] == elementId) { groupKey.GroupMemberIndex = idx; break; } } if (groupKey.GroupMemberIndex >= 0) { groupKey.GroupTypeId = group.GetTypeId(); groupData = ExporterCacheManager.GroupElementGeometryCache.Find(groupKey); if (groupData == null) { groupData = new BodyGroupData(); useGroupsIfPossible = true; } else { ISet<IFCAnyHandle> groupBodyItems = new HashSet<IFCAnyHandle>(); foreach (IFCAnyHandle mappedRepHnd in groupData.Handles) { IFCAnyHandle mappedItemHnd = ExporterUtil.CreateDefaultMappedItem(file, mappedRepHnd); groupBodyItems.Add(mappedItemHnd); } bodyData = new BodyData(bodyDataIn); bodyData.RepresentationHnd = RepresentationUtil.CreateBodyMappedItemRep(exporterIFC, element, categoryId, contextOfItems, groupBodyItems); return true; } } } } return useGroupsIfPossible; }
// NOTE: the useMappedGeometriesIfPossible and useGroupsIfPossible options are experimental and do not yet work well. // In shipped code, these are always false, and should be kept false until API support routines are proved to be reliable. private static BodyData ExportBodyAsBRep(ExporterIFC exporterIFC, IList<GeometryObject> splitGeometryList, IList<KeyValuePair<int, SimpleSweptSolidAnalyzer>> exportAsBRep, IList<IFCAnyHandle> bodyItems, Element element, ElementId categoryId, ElementId overrideMaterialId, IFCAnyHandle contextOfItems, double eps, BodyExporterOptions options, BodyData bodyDataIn) { bool exportAsBReps = true; bool hasTriangulatedGeometry = false; bool hasAdvancedBrepGeometry = false; IFCFile file = exporterIFC.GetFile(); Document document = element.Document; // Can't use the optimization functions below if we already have partially populated our body items with extrusions. int numExtrusions = bodyItems.Count; bool useMappedGeometriesIfPossible = options.UseMappedGeometriesIfPossible && (numExtrusions != 0); bool useGroupsIfPossible = options.UseGroupsIfPossible && (numExtrusions != 0); IList<HashSet<IFCAnyHandle>> currentFaceHashSetList = new List<HashSet<IFCAnyHandle>>(); IList<int> startIndexForObject = new List<int>(); BodyData bodyData = new BodyData(bodyDataIn); IDictionary<SolidMetrics, HashSet<Solid>> solidMappingGroups = null; IList<KeyValuePair<int, Transform>> solidMappings = null; IList<ElementId> materialIds = new List<ElementId>(); // This should currently be always false in shipped code. if (useMappedGeometriesIfPossible) { IList<GeometryObject> newGeometryList = null; useMappedGeometriesIfPossible = GatherMappedGeometryGroupings(splitGeometryList, out newGeometryList, out solidMappingGroups, out solidMappings); if (useMappedGeometriesIfPossible && (newGeometryList != null)) splitGeometryList = newGeometryList; } BodyGroupKey groupKey = null; BodyGroupData groupData = null; // This should currently be always false in shipped code. if (useGroupsIfPossible) { BodyData bodyDataOut = null; useGroupsIfPossible = ProcessGroupMembership(exporterIFC, file, element, categoryId, contextOfItems, splitGeometryList, bodyData, out groupKey, out groupData, out bodyDataOut); if (bodyDataOut != null) return bodyDataOut; if (useGroupsIfPossible) useMappedGeometriesIfPossible = true; } bool isCoarse = (options.TessellationLevel == BodyExporterOptions.BodyTessellationLevel.Coarse); int numBRepsToExport = exportAsBRep.Count; bool selectiveBRepExport = (numBRepsToExport > 0); int numGeoms = selectiveBRepExport ? numBRepsToExport : splitGeometryList.Count; bool canExportAsAdvancedGeometry = ExporterCacheManager.ExportOptionsCache.ExportAs4DesignTransferView; bool canExportAsTessellatedFaceSet = ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView; // We will cycle through all of the geometries one at a time, doing the best export we can for each. for (int index = 0; index < numGeoms; index++) { int brepIndex = selectiveBRepExport ? exportAsBRep[index].Key : index; SimpleSweptSolidAnalyzer currAnalyzer = selectiveBRepExport ? exportAsBRep[index].Value : null; GeometryObject geomObject = selectiveBRepExport ? splitGeometryList[brepIndex] : splitGeometryList[index]; // A simple test to see if the geometry is a valid solid. This will save a lot of time in CanCreateClosedShell later. if (exportAsBReps && (geomObject is Solid)) { try { // We don't care what the value is here. What we care about is whether or not it can be calculated. If it can't be calculated, // it is probably not a valid solid. double volume = (geomObject as Solid).Volume; // Current code should already prevent 0 volume solids from coming here, but may as well play it safe. if (volume <= MathUtil.Eps()) exportAsBReps = false; } catch { exportAsBReps = false; } } startIndexForObject.Add(currentFaceHashSetList.Count); ElementId materialId = SetBestMaterialIdInExporter(geomObject, element, overrideMaterialId, exporterIFC); materialIds.Add(materialId); bodyData.AddMaterial(materialId); bool alreadyExported = false; // First, see if this could be represented as a simple swept solid. if (exportAsBReps && (currAnalyzer != null)) { SweptSolidExporter sweptSolidExporter = SweptSolidExporter.Create(exporterIFC, element, currAnalyzer, geomObject); HashSet<IFCAnyHandle> facetHnds = (sweptSolidExporter != null) ? sweptSolidExporter.Facets : null; if (facetHnds != null && facetHnds.Count != 0) { currentFaceHashSetList.Add(facetHnds); alreadyExported = true; } } // Next, try to represent as an AdvancedBRep. if (!alreadyExported && canExportAsAdvancedGeometry) { IFCAnyHandle advancedBrepBodyItem = ExportBodyAsAdvancedBrep(exporterIFC, element, options, geomObject); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(advancedBrepBodyItem)) { bodyItems.Add(advancedBrepBodyItem); alreadyExported = true; hasAdvancedBrepGeometry = true; } } // If we are using the Reference View, try a triangulated face set. // In theory, we could export a tessellated face set for geometry in the Design Transfer View that failed above. // However, FacetedBReps do hold more information (and aren't only triangles). if (!alreadyExported && canExportAsTessellatedFaceSet) { IFCAnyHandle triangulatedBodyItem = ExportBodyAsTriangulatedFaceSet(exporterIFC, element, options, geomObject); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(triangulatedBodyItem)) { bodyItems.Add(triangulatedBodyItem); alreadyExported = true; hasTriangulatedGeometry = true; } // We should log here that we couldn't export a geometry. We aren't allowed to use the traditional methods below. if (!alreadyExported) continue; } // If the above options do not generate any body, do the traditional step for Brep if (!alreadyExported && (exportAsBReps || isCoarse)) alreadyExported = ExportBodyAsSolid(exporterIFC, element, options, currentFaceHashSetList, geomObject); // If all else fails, use the internal routine to go through the faces. This will likely create a surface model. if (!alreadyExported) { IFCGeometryInfo faceListInfo = IFCGeometryInfo.CreateFaceGeometryInfo(eps, isCoarse); ExporterIFCUtils.CollectGeometryInfo(exporterIFC, faceListInfo, geomObject, XYZ.Zero, false); IList<ICollection<IFCAnyHandle>> faceSetList = faceListInfo.GetFaces(); int numBReps = faceSetList.Count; if (numBReps == 0) continue; foreach (ICollection<IFCAnyHandle> currentFaceSet in faceSetList) { if (currentFaceSet.Count == 0) continue; if (exportAsBReps) { bool canExportAsClosedShell = (currentFaceSet.Count >= 4); if (canExportAsClosedShell) { if ((geomObject is Mesh) && (numBReps == 1)) { // use optimized version. canExportAsClosedShell = CanCreateClosedShell(geomObject as Mesh); } else { canExportAsClosedShell = CanCreateClosedShell(currentFaceSet); } } if (!canExportAsClosedShell) { exportAsBReps = false; // We'll need to invalidate the extrusions we created and replace them with BReps. if (selectiveBRepExport && (numGeoms != splitGeometryList.Count)) { for (int fixIndex = 0; fixIndex < numExtrusions; fixIndex++) { bodyItems[0].Delete(); bodyItems.RemoveAt(0); } numExtrusions = 0; numGeoms = splitGeometryList.Count; int currBRepIndex = 0; for (int fixIndex = 0; fixIndex < numGeoms; fixIndex++) { bool outOfRange = (currBRepIndex >= numBRepsToExport); if (!outOfRange && (exportAsBRep[currBRepIndex].Key == fixIndex)) { currBRepIndex++; continue; } SimpleSweptSolidAnalyzer fixAnalyzer = outOfRange ? null : exportAsBRep[currBRepIndex].Value; exportAsBRep.Add(new KeyValuePair<int, SimpleSweptSolidAnalyzer>(fixIndex, fixAnalyzer)); } numBRepsToExport = exportAsBRep.Count; } } } currentFaceHashSetList.Add(new HashSet<IFCAnyHandle>(currentFaceSet)); } } } if (hasTriangulatedGeometry) { HashSet<IFCAnyHandle> bodyItemSet = new HashSet<IFCAnyHandle>(); bodyItemSet.UnionWith(bodyItems); if (bodyItemSet.Count > 0) { bodyData.RepresentationHnd = RepresentationUtil.CreateTessellatedRep(exporterIFC, element, categoryId, contextOfItems, bodyItemSet, null); bodyData.ShapeRepresentationType = ShapeRepresentationType.Tessellation; } } else if (hasAdvancedBrepGeometry) { HashSet<IFCAnyHandle> bodyItemSet = new HashSet<IFCAnyHandle>(); bodyItemSet.UnionWith(bodyItems); if (bodyItemSet.Count > 0) { bodyData.RepresentationHnd = RepresentationUtil.CreateAdvancedBRepRep(exporterIFC, element, categoryId, contextOfItems, bodyItemSet, null); bodyData.ShapeRepresentationType = ShapeRepresentationType.AdvancedBrep; } } else { startIndexForObject.Add(currentFaceHashSetList.Count); // end index for last object. IList<IFCAnyHandle> repMapItems = new List<IFCAnyHandle>(); int size = currentFaceHashSetList.Count; if (exportAsBReps) { int matToUse = -1; for (int ii = 0; ii < size; ii++) { if (startIndexForObject[matToUse + 1] == ii) matToUse++; HashSet<IFCAnyHandle> currentFaceHashSet = currentFaceHashSetList[ii]; ElementId currMatId = materialIds[matToUse]; IFCAnyHandle faceOuter = IFCInstanceExporter.CreateClosedShell(file, currentFaceHashSet); IFCAnyHandle brepHnd = RepresentationUtil.CreateFacetedBRep(exporterIFC, document, faceOuter, currMatId); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(brepHnd)) { if (useMappedGeometriesIfPossible) { IFCAnyHandle currMappedRepHnd = CreateBRepRepresentationMap(exporterIFC, file, element, categoryId, contextOfItems, brepHnd); repMapItems.Add(currMappedRepHnd); IFCAnyHandle mappedItemHnd = ExporterUtil.CreateDefaultMappedItem(file, currMappedRepHnd); bodyItems.Add(mappedItemHnd); } else bodyItems.Add(brepHnd); } } } else { IDictionary<ElementId, HashSet<IFCAnyHandle>> faceSets = new Dictionary<ElementId, HashSet<IFCAnyHandle>>(); int matToUse = -1; for (int ii = 0; ii < size; ii++) { HashSet<IFCAnyHandle> currentFaceHashSet = currentFaceHashSetList[ii]; if (startIndexForObject[matToUse + 1] == ii) matToUse++; IFCAnyHandle faceSetHnd = IFCInstanceExporter.CreateConnectedFaceSet(file, currentFaceHashSet); if (useMappedGeometriesIfPossible) { IFCAnyHandle currMappedRepHnd = CreateSurfaceRepresentationMap(exporterIFC, file, element, categoryId, contextOfItems, faceSetHnd); repMapItems.Add(currMappedRepHnd); IFCAnyHandle mappedItemHnd = ExporterUtil.CreateDefaultMappedItem(file, currMappedRepHnd); bodyItems.Add(mappedItemHnd); } else { HashSet<IFCAnyHandle> surfaceSet = null; if (faceSets.TryGetValue(materialIds[matToUse], out surfaceSet)) { surfaceSet.Add(faceSetHnd); } else { surfaceSet = new HashSet<IFCAnyHandle>(); surfaceSet.Add(faceSetHnd); faceSets[materialIds[matToUse]] = surfaceSet; } } } if (faceSets.Count > 0) { foreach (KeyValuePair<ElementId, HashSet<IFCAnyHandle>> faceSet in faceSets) { IFCAnyHandle surfaceModel = IFCInstanceExporter.CreateFaceBasedSurfaceModel(file, faceSet.Value); BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, document, surfaceModel, faceSet.Key); bodyItems.Add(surfaceModel); } } } if (bodyItems.Count == 0) return bodyData; // Add in mapped items. if (useMappedGeometriesIfPossible && (solidMappings != null)) { foreach (KeyValuePair<int, Transform> mappedItem in solidMappings) { for (int idx = startIndexForObject[mappedItem.Key]; idx < startIndexForObject[mappedItem.Key + 1]; idx++) { IFCAnyHandle mappedItemHnd = ExporterUtil.CreateMappedItemFromTransform(file, repMapItems[idx], mappedItem.Value); bodyItems.Add(mappedItemHnd); } } } HashSet<IFCAnyHandle> bodyItemSet = new HashSet<IFCAnyHandle>(); bodyItemSet.UnionWith(bodyItems); if (useMappedGeometriesIfPossible) { bodyData.RepresentationHnd = RepresentationUtil.CreateBodyMappedItemRep(exporterIFC, element, categoryId, contextOfItems, bodyItemSet); } else if (exportAsBReps) { if (numExtrusions > 0) bodyData.RepresentationHnd = RepresentationUtil.CreateSolidModelRep(exporterIFC, element, categoryId, contextOfItems, bodyItemSet); else bodyData.RepresentationHnd = RepresentationUtil.CreateBRepRep(exporterIFC, element, categoryId, contextOfItems, bodyItemSet); } else bodyData.RepresentationHnd = RepresentationUtil.CreateSurfaceRep(exporterIFC, element, categoryId, contextOfItems, bodyItemSet, false, null); if (useGroupsIfPossible && (groupKey != null) && (groupData != null)) { groupData.Handles = repMapItems; ExporterCacheManager.GroupElementGeometryCache.Register(groupKey, groupData); } bodyData.ShapeRepresentationType = ShapeRepresentationType.Brep; } return bodyData; }
/// <summary> /// Exports a beam to IFC beam. /// </summary> /// <param name="exporterIFC"> /// The ExporterIFC object. /// </param> /// <param name="element"> /// The element to be exported. /// </param> /// <param name="geometryElement"> /// The geometry element. /// </param> /// <param name="productWrapper"> /// The ProductWrapper. /// </param> public static void ExportBeam(ExporterIFC exporterIFC, Element element, GeometryElement geometryElement, ProductWrapper productWrapper) { if (geometryElement == null) { return; } IFCFile file = exporterIFC.GetFile(); using (IFCTransaction transaction = new IFCTransaction(file)) { LocationCurve locCurve = element.Location as LocationCurve; Transform orientTrf = Transform.Identity; bool canExportAxis = (locCurve != null); IFCAnyHandle axisRep = null; XYZ beamDirection = null; XYZ projDir = null; Curve curve = null; Plane plane = null; if (canExportAxis) { curve = locCurve.Curve; if (curve is Line) { Line line = curve as Line; XYZ planeY, planeOrig; planeOrig = line.GetEndPoint(0); beamDirection = line.Direction; if (Math.Abs(beamDirection.Z) < 0.707) // approx 1.0/sqrt(2.0) { planeY = XYZ.BasisZ.CrossProduct(beamDirection); } else { planeY = XYZ.BasisX.CrossProduct(beamDirection); } planeY = planeY.Normalize(); projDir = beamDirection.CrossProduct(planeY); plane = new Plane(beamDirection, planeY, planeOrig); orientTrf.BasisX = beamDirection; orientTrf.BasisY = planeY; orientTrf.BasisZ = projDir; orientTrf.Origin = planeOrig; } else if (curve is Arc) { XYZ yDir, center; Arc arc = curve as Arc; beamDirection = arc.XDirection; yDir = arc.YDirection; projDir = arc.Normal; center = arc.Center; plane = new Plane(beamDirection, yDir, center); orientTrf.BasisX = beamDirection; orientTrf.BasisY = yDir; orientTrf.BasisZ = projDir; orientTrf.Origin = center; } else { canExportAxis = false; } } using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, element, null, canExportAxis ? orientTrf : null)) { IFCAnyHandle localPlacement = setter.LocalPlacement; SolidMeshGeometryInfo solidMeshInfo = GeometryUtil.GetSplitSolidMeshGeometry(geometryElement); using (IFCExtrusionCreationData extrusionCreationData = new IFCExtrusionCreationData()) { extrusionCreationData.SetLocalPlacement(localPlacement); if (canExportAxis && (orientTrf.BasisX != null)) { extrusionCreationData.CustomAxis = beamDirection; extrusionCreationData.PossibleExtrusionAxes = IFCExtrusionAxes.TryCustom; } else { extrusionCreationData.PossibleExtrusionAxes = IFCExtrusionAxes.TryXY; } IList <Solid> solids = solidMeshInfo.GetSolids(); IList <Mesh> meshes = solidMeshInfo.GetMeshes(); ElementId catId = CategoryUtil.GetSafeCategoryId(element); // The representation handle generated from one of the methods below. IFCAnyHandle repHnd = null; // The list of materials in the solids or meshes. ICollection <ElementId> materialIds = new HashSet <ElementId>(); // There may be an offset to make the local coordinate system // be near the origin. This offset will be used to move the axis to the new LCS. Transform offsetTransform = null; // If we have a beam with a Linear location line that only has one solid geometry, // we will try to use the ExtrusionAnalyzer to generate an extrusion with 0 or more clippings. // This code is currently limited in that it will not process beams with openings, so we // use other methods below if this one fails. if (solids.Count == 1 && meshes.Count == 0 && (canExportAxis && (curve is Line))) { bool completelyClipped; beamDirection = orientTrf.BasisX; Plane beamExtrusionPlane = new Plane(orientTrf.BasisY, orientTrf.BasisZ, orientTrf.Origin); repHnd = ExtrusionExporter.CreateExtrusionWithClipping(exporterIFC, element, catId, solids[0], beamExtrusionPlane, beamDirection, null, out completelyClipped); if (completelyClipped) { return; } if (!IFCAnyHandleUtil.IsNullOrHasNoValue(repHnd)) { // This is used by the BeamSlopeCalculator. This should probably be generated automatically by // CreateExtrusionWithClipping. IFCExtrusionBasis bestAxis = (Math.Abs(beamDirection[0]) > Math.Abs(beamDirection[1])) ? IFCExtrusionBasis.BasisX : IFCExtrusionBasis.BasisY; extrusionCreationData.Slope = GeometryUtil.GetSimpleExtrusionSlope(beamDirection, bestAxis); ElementId materialId = BodyExporter.GetBestMaterialIdFromGeometryOrParameter(solids[0], exporterIFC, element); if (materialId != ElementId.InvalidElementId) { materialIds.Add(materialId); } } } if (IFCAnyHandleUtil.IsNullOrHasNoValue(repHnd)) { BodyData bodyData = null; BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true); if (solids.Count > 0 || meshes.Count > 0) { bodyData = BodyExporter.ExportBody(exporterIFC, element, catId, ElementId.InvalidElementId, solids, meshes, bodyExporterOptions, extrusionCreationData); } else { IList <GeometryObject> geomlist = new List <GeometryObject>(); geomlist.Add(geometryElement); bodyData = BodyExporter.ExportBody(exporterIFC, element, catId, ElementId.InvalidElementId, geomlist, bodyExporterOptions, extrusionCreationData); } repHnd = bodyData.RepresentationHnd; materialIds = bodyData.MaterialIds; offsetTransform = bodyData.OffsetTransform; } if (IFCAnyHandleUtil.IsNullOrHasNoValue(repHnd)) { extrusionCreationData.ClearOpenings(); return; } IList <IFCAnyHandle> representations = new List <IFCAnyHandle>(); if (canExportAxis) { XYZ curveOffset = new XYZ(0, 0, 0); if (offsetTransform != null) { curveOffset = -UnitUtil.UnscaleLength(offsetTransform.Origin); } else { // Note that we do not have to have any scaling adjustment here, since the curve origin is in the // same internal coordinate system as the curve. curveOffset = -plane.Origin; } Plane offsetPlane = new Plane(plane.XVec, plane.YVec, XYZ.Zero); IFCGeometryInfo info = IFCGeometryInfo.CreateCurveGeometryInfo(exporterIFC, offsetPlane, projDir, false); ExporterIFCUtils.CollectGeometryInfo(exporterIFC, info, curve, curveOffset, true); IList <IFCAnyHandle> axis_items = info.GetCurves(); if (axis_items.Count > 0) { string identifierOpt = "Axis"; // this is by IFC2x2 convention, not temporary string representationTypeOpt = "Curve2D"; // this is by IFC2x2 convention, not temporary axisRep = RepresentationUtil.CreateShapeRepresentation(exporterIFC, element, catId, exporterIFC.Get3DContextHandle(identifierOpt), identifierOpt, representationTypeOpt, axis_items); representations.Add(axisRep); } } representations.Add(repHnd); Transform boundingBoxTrf = (offsetTransform == null) ? Transform.Identity : offsetTransform.Inverse; IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geometryElement, boundingBoxTrf); if (boundingBoxRep != null) { representations.Add(boundingBoxRep); } IFCAnyHandle prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations); string instanceGUID = GUIDUtil.CreateGUID(element); string instanceName = NamingUtil.GetNameOverride(element, NamingUtil.GetIFCName(element)); string instanceDescription = NamingUtil.GetDescriptionOverride(element, null); string instanceObjectType = NamingUtil.GetObjectTypeOverride(element, NamingUtil.CreateIFCObjectName(exporterIFC, element)); string instanceTag = NamingUtil.GetTagOverride(element, NamingUtil.CreateIFCElementId(element)); string preDefinedType = "BEAM"; // Default predefined type for Beam preDefinedType = IFCValidateEntry.GetValidIFCType(element, preDefinedType); IFCAnyHandle beam = IFCInstanceExporter.CreateBeam(file, instanceGUID, exporterIFC.GetOwnerHistoryHandle(), instanceName, instanceDescription, instanceObjectType, extrusionCreationData.GetLocalPlacement(), prodRep, instanceTag, preDefinedType); productWrapper.AddElement(element, beam, setter, extrusionCreationData, true); OpeningUtil.CreateOpeningsIfNecessary(beam, element, extrusionCreationData, offsetTransform, exporterIFC, extrusionCreationData.GetLocalPlacement(), setter, productWrapper); FamilyTypeInfo typeInfo = new FamilyTypeInfo(); typeInfo.ScaledDepth = extrusionCreationData.ScaledLength; typeInfo.ScaledArea = extrusionCreationData.ScaledArea; typeInfo.ScaledInnerPerimeter = extrusionCreationData.ScaledInnerPerimeter; typeInfo.ScaledOuterPerimeter = extrusionCreationData.ScaledOuterPerimeter; PropertyUtil.CreateBeamColumnBaseQuantities(exporterIFC, beam, element, typeInfo, null); if (materialIds.Count != 0) { CategoryUtil.CreateMaterialAssociations(exporterIFC, beam, materialIds); } // Register the beam's IFC handle for later use by truss and beam system export. ExporterCacheManager.ElementToHandleCache.Register(element.Id, beam); } } transaction.Commit(); } }
/// <summary> /// Exports a ramp to IfcRamp, without decomposing into separate runs and landings. /// </summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="ifcEnumType">The ramp type.</param> /// <param name="ramp">The ramp element.</param> /// <param name="geometryElement">The geometry element.</param> /// <param name="numFlights">The number of flights for a multistory ramp.</param> /// <param name="productWrapper">The ProductWrapper.</param> public static void ExportRamp(ExporterIFC exporterIFC, string ifcEnumType, Element ramp, GeometryElement geometryElement, int numFlights, ProductWrapper productWrapper) { if (ramp == null || geometryElement == null) { return; } // Check the intended IFC entity or type name is in the exclude list specified in the UI Common.Enums.IFCEntityType elementClassTypeEnum = Common.Enums.IFCEntityType.IfcRamp; if (ExporterCacheManager.ExportOptionsCache.IsElementInExcludeList(elementClassTypeEnum)) { return; } // TESTING foreach (GeometryObject geomObj in geometryElement) { Visibility visibility = geomObj.Visibility; } IFCFile file = exporterIFC.GetFile(); ElementId categoryId = CategoryUtil.GetSafeCategoryId(ramp); using (IFCTransaction tr = new IFCTransaction(file)) { using (PlacementSetter placementSetter = PlacementSetter.Create(exporterIFC, ramp)) { IFCAnyHandle contextOfItemsFootPrint = exporterIFC.Get3DContextHandle("FootPrint"); IFCAnyHandle contextOfItemsAxis = exporterIFC.Get3DContextHandle("Axis"); Transform trf = ExporterIFCUtils.GetUnscaledTransform(exporterIFC, placementSetter.LocalPlacement); IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle; IList <(Solid body, Face largestTopFace)> rampFlights = null; IList <Solid> landings = null; if (IdentifyRampFlightAndLanding(geometryElement, out rampFlights, out landings)) { string rampGUID = GUIDUtil.CreateGUID(ramp); IFCAnyHandle rampLocalPlacement = placementSetter.LocalPlacement; string predefType = "NOTDEFINED"; //Temporary IFCAnyHandle rampContainerHnd = IFCInstanceExporter.CreateRamp(exporterIFC, ramp, rampGUID, ownerHistory, rampLocalPlacement, null, predefType); // Create appropriate type IFCExportInfoPair exportType = new IFCExportInfoPair(); exportType.SetValueWithPair(IFCEntityType.IfcRamp); IFCAnyHandle rampTypeHnd = ExporterUtil.CreateGenericTypeFromElement(ramp, exportType, exporterIFC.GetFile(), ownerHistory, predefType, productWrapper); ExporterCacheManager.TypeRelationsCache.Add(rampTypeHnd, rampContainerHnd); productWrapper.AddElement(ramp, rampContainerHnd, placementSetter.LevelInfo, null, true); //Breakdown the Ramp into its components: RampFlights and Landings int rampFlightIndex = 0; int landingIndex = 0; HashSet <IFCAnyHandle> rampComponents = new HashSet <IFCAnyHandle>(); foreach ((Solid body, Face topFace)rampFlight in rampFlights) { using (IFCExtrusionCreationData ecData = new IFCExtrusionCreationData()) { ecData.AllowVerticalOffsetOfBReps = false; ecData.SetLocalPlacement(ExporterUtil.CreateLocalPlacement(file, placementSetter.LocalPlacement, null)); ecData.ReuseLocalPlacement = true; BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true, ExportOptionsCache.ExportTessellationLevel.ExtraLow); BodyData bodyData = BodyExporter.ExportBody(exporterIFC, ramp, categoryId, ElementId.InvalidElementId, rampFlight.body, bodyExporterOptions, ecData); IFCAnyHandle bodyRep = bodyData.RepresentationHnd; if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep)) { ecData.ClearOpenings(); continue; } IList <IFCAnyHandle> reps = new List <IFCAnyHandle>(); reps.Add(bodyRep); //if (!ExporterCacheManager.ExportOptionsCache.ExportAsCoordinationView2) //{ // CreateWalkingLineAndFootprint(exporterIFC, run, bodyData, categoryId, trf, ref reps); //} Transform boundingBoxTrf = (bodyData.OffsetTransform == null) ? Transform.Identity : bodyData.OffsetTransform.Inverse; IList <GeometryObject> solidList = new List <GeometryObject>(); solidList.Add(rampFlight.body); IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, solidList, boundingBoxTrf); if (boundingBoxRep != null) { reps.Add(boundingBoxRep); } IFCAnyHandle representation = IFCInstanceExporter.CreateProductDefinitionShape(exporterIFC.GetFile(), null, null, reps); rampFlightIndex++; string flightGUID = GUIDUtil.CreateSubElementGUID(ramp, rampFlightIndex); string origFlightName = IFCAnyHandleUtil.GetStringAttribute(rampContainerHnd, "Name") + " " + rampFlightIndex; string flightName = NamingUtil.GetOverrideStringValue(ramp, "IfcRampFlight.Name (" + rampFlightIndex + ")", origFlightName); IFCAnyHandle flightLocalPlacement = ecData.GetLocalPlacement(); string flightPredefType = NamingUtil.GetOverrideStringValue(ramp, "IfcRampFlight.PredefinedType (" + rampFlightIndex + ")", null); IFCAnyHandle rampFlightHnd = IFCInstanceExporter.CreateRampFlight(exporterIFC, null, flightGUID, ownerHistory, flightLocalPlacement, representation, flightPredefType); IFCAnyHandleUtil.OverrideNameAttribute(rampFlightHnd, flightName); rampComponents.Add(rampFlightHnd); // Create type IFCExportInfoPair flightEportType = new IFCExportInfoPair(); flightEportType.SetValueWithPair(IFCEntityType.IfcRampFlight); IFCAnyHandle flightTypeHnd = IFCInstanceExporter.CreateGenericIFCType(flightEportType, null, exporterIFC.GetFile(), null, null, flightPredefType); IFCAnyHandleUtil.OverrideNameAttribute(flightTypeHnd, flightName); ExporterCacheManager.TypeRelationsCache.Add(flightTypeHnd, rampFlightHnd); CategoryUtil.CreateMaterialAssociation(exporterIFC, rampFlightHnd, bodyData.MaterialIds); IFCAnyHandle psetRampFlightCommonHnd = CreatePSetRampFlightCommon(exporterIFC, file, ramp, rampFlightIndex, rampFlight.topFace); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(psetRampFlightCommonHnd)) { HashSet <IFCAnyHandle> relatedObjects = new HashSet <IFCAnyHandle>() { rampFlightHnd }; ExporterUtil.CreateRelDefinesByProperties(file, GUIDUtil.CreateGUID(), ownerHistory, null, null, relatedObjects, psetRampFlightCommonHnd); } } } foreach (Solid landing in landings) { using (IFCExtrusionCreationData ecData = new IFCExtrusionCreationData()) { ecData.AllowVerticalOffsetOfBReps = false; ecData.SetLocalPlacement(ExporterUtil.CreateLocalPlacement(file, placementSetter.LocalPlacement, null)); ecData.ReuseLocalPlacement = true; BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true, ExportOptionsCache.ExportTessellationLevel.ExtraLow); BodyData bodyData = BodyExporter.ExportBody(exporterIFC, ramp, categoryId, ElementId.InvalidElementId, landing, bodyExporterOptions, ecData); IFCAnyHandle bodyRep = bodyData.RepresentationHnd; if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep)) { ecData.ClearOpenings(); continue; } IList <IFCAnyHandle> reps = new List <IFCAnyHandle>(); reps.Add(bodyRep); //if (!ExporterCacheManager.ExportOptionsCache.ExportAsCoordinationView2) //{ // CreateWalkingLineAndFootprint(exporterIFC, run, bodyData, categoryId, trf, ref reps); //} Transform boundingBoxTrf = (bodyData.OffsetTransform == null) ? Transform.Identity : bodyData.OffsetTransform.Inverse; IList <GeometryObject> solidList = new List <GeometryObject>(); solidList.Add(landing); IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, solidList, boundingBoxTrf); if (boundingBoxRep != null) { reps.Add(boundingBoxRep); } IFCAnyHandle representation = IFCInstanceExporter.CreateProductDefinitionShape(exporterIFC.GetFile(), null, null, reps); landingIndex++; string landingGUID = GUIDUtil.CreateSubElementGUID(ramp, landingIndex); string origLandingName = IFCAnyHandleUtil.GetStringAttribute(rampContainerHnd, "Name") + " " + landingIndex; string landingName = NamingUtil.GetOverrideStringValue(ramp, "IfcRampLanding.Name (" + landingIndex + ")", origLandingName); IFCAnyHandle landingLocalPlacement = ecData.GetLocalPlacement(); string landingPredefType = "LANDING"; IFCAnyHandle rampLandingHnd = IFCInstanceExporter.CreateSlab(exporterIFC, ramp, landingGUID, ownerHistory, landingLocalPlacement, representation, landingPredefType); IFCAnyHandleUtil.OverrideNameAttribute(rampLandingHnd, landingName); rampComponents.Add(rampLandingHnd); // Create type IFCExportInfoPair landingEportType = new IFCExportInfoPair(); landingEportType.SetValueWithPair(IFCEntityType.IfcSlab); IFCAnyHandle landingTypeHnd = IFCInstanceExporter.CreateGenericIFCType(landingEportType, null, exporterIFC.GetFile(), null, null, landingPredefType); IFCAnyHandleUtil.OverrideNameAttribute(landingTypeHnd, landingName); ExporterCacheManager.TypeRelationsCache.Add(landingTypeHnd, rampLandingHnd); CategoryUtil.CreateMaterialAssociation(exporterIFC, rampLandingHnd, bodyData.MaterialIds); IFCAnyHandle psetSlabCommonHnd = CreatePSetRampLandingCommon(exporterIFC, file, ramp, landingIndex); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(psetSlabCommonHnd)) { HashSet <IFCAnyHandle> relatedObjects = new HashSet <IFCAnyHandle>() { rampLandingHnd }; ExporterUtil.CreateRelDefinesByProperties(file, GUIDUtil.CreateGUID(), ownerHistory, null, null, relatedObjects, psetSlabCommonHnd); } } } if (rampComponents.Count > 0) { IFCInstanceExporter.CreateRelAggregates(file, GUIDUtil.CreateGUID(), ownerHistory, null, null, rampContainerHnd, rampComponents); } } else { using (IFCExtrusionCreationData ecData = new IFCExtrusionCreationData()) { ecData.SetLocalPlacement(placementSetter.LocalPlacement); ecData.ReuseLocalPlacement = false; GeometryElement rampGeom = GeometryUtil.GetOneLevelGeometryElement(geometryElement, numFlights); BodyData bodyData; BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true, ExportOptionsCache.ExportTessellationLevel.ExtraLow); IFCAnyHandle representation = RepresentationUtil.CreateAppropriateProductDefinitionShape(exporterIFC, ramp, categoryId, rampGeom, bodyExporterOptions, null, ecData, out bodyData); if (IFCAnyHandleUtil.IsNullOrHasNoValue(representation)) { ecData.ClearOpenings(); return; } string containedRampGuid = GUIDUtil.CreateSubElementGUID(ramp, (int)IFCRampSubElements.ContainedRamp); IFCAnyHandle containedRampLocalPlacement = ExporterUtil.CreateLocalPlacement(file, ecData.GetLocalPlacement(), null); string rampType = GetIFCRampType(ifcEnumType); List <IFCAnyHandle> components = new List <IFCAnyHandle>(); IList <IFCExtrusionCreationData> componentExtrusionData = new List <IFCExtrusionCreationData>(); IFCAnyHandle containedRampHnd = IFCInstanceExporter.CreateRamp(exporterIFC, ramp, containedRampGuid, ownerHistory, containedRampLocalPlacement, representation, rampType); components.Add(containedRampHnd); componentExtrusionData.Add(ecData); //productWrapper.AddElement(containedRampHnd, placementSetter.LevelInfo, ecData, false); CategoryUtil.CreateMaterialAssociation(exporterIFC, containedRampHnd, bodyData.MaterialIds); string guid = GUIDUtil.CreateGUID(ramp); IFCAnyHandle localPlacement = ecData.GetLocalPlacement(); IFCAnyHandle rampHnd = IFCInstanceExporter.CreateRamp(exporterIFC, ramp, guid, ownerHistory, localPlacement, null, rampType); productWrapper.AddElement(ramp, rampHnd, placementSetter.LevelInfo, ecData, true); StairRampContainerInfo stairRampInfo = new StairRampContainerInfo(rampHnd, components, localPlacement); ExporterCacheManager.StairRampContainerInfoCache.AddStairRampContainerInfo(ramp.Id, stairRampInfo); ExportMultistoryRamp(exporterIFC, ramp, numFlights, rampHnd, components, componentExtrusionData, placementSetter, productWrapper); } } } tr.Commit(); } }
/// <summary> /// Exports a Rebar Coupler, /// </summary> /// <param name="exporterIFC">The exporter.</param> /// <param name="coupler">The RebarCoupler element.</param> /// <param name="productWrapper">The product wrapper.</param> public static void ExportCoupler(ExporterIFC exporterIFC, RebarCoupler coupler, ProductWrapper productWrapper) { if (coupler == null) { return; } FamilySymbol familySymbol = ExporterCacheManager.Document.GetElement(coupler.GetTypeId()) as FamilySymbol; if (familySymbol == null) { return; } // Check the intended IFC entity or type name is in the exclude list specified in the UI Common.Enums.IFCEntityType elementClassTypeEnum; if (Enum.TryParse <Common.Enums.IFCEntityType>("IfcMechanicalFastener", out elementClassTypeEnum)) { if (ExporterCacheManager.ExportOptionsCache.IsElementInExcludeList(elementClassTypeEnum)) { return; } } ElementId categoryId = CategoryUtil.GetSafeCategoryId(coupler); IFCFile file = exporterIFC.GetFile(); IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle; Options options = GeometryUtil.GetIFCExportGeometryOptions();; string ifcEnumType; IFCExportInfoPair exportType = ExporterUtil.GetExportType(exporterIFC, coupler, out ifcEnumType); using (IFCTransaction tr = new IFCTransaction(file)) { FamilyTypeInfo currentTypeInfo = ExporterCacheManager.FamilySymbolToTypeInfoCache.Find(coupler.GetTypeId(), false, exportType.ExportType); bool found = currentTypeInfo.IsValid(); if (!found) { string typeObjectType = NamingUtil.CreateIFCObjectName(exporterIFC, familySymbol); HashSet <IFCAnyHandle> propertySetsOpt = new HashSet <IFCAnyHandle>(); GeometryElement exportGeometry = familySymbol.get_Geometry(options); BodyData bodyData = null; BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true, ExportOptionsCache.ExportTessellationLevel.ExtraLow); bodyData = BodyExporter.ExportBody(exporterIFC, coupler, categoryId, ElementId.InvalidElementId, exportGeometry, bodyExporterOptions, null); List <IFCAnyHandle> repMap = new List <IFCAnyHandle>(); IFCAnyHandle origin = ExporterUtil.CreateAxis2Placement3D(file);; repMap.Add(IFCInstanceExporter.CreateRepresentationMap(file, origin, bodyData.RepresentationHnd)); IFCAnyHandle styleHandle = FamilyExporterUtil.ExportGenericType(exporterIFC, exportType, ifcEnumType, propertySetsOpt, repMap, coupler, familySymbol); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(styleHandle)) { string applicableOccurrence = NamingUtil.GetObjectTypeOverride(familySymbol, typeObjectType); if (!string.IsNullOrEmpty(applicableOccurrence)) { IFCAnyHandleUtil.SetAttribute(styleHandle, "ApplicableOccurrence", applicableOccurrence); } currentTypeInfo.Style = styleHandle; ExporterCacheManager.FamilySymbolToTypeInfoCache.Register(coupler.GetTypeId(), false, exportType.ExportType, currentTypeInfo); } } int nCouplerQuantity = coupler.GetCouplerQuantity(); if (nCouplerQuantity <= 0) { return; } ISet <IFCAnyHandle> createdRebarCouplerHandles = new HashSet <IFCAnyHandle>(); string origInstanceName = NamingUtil.GetNameOverride(coupler, NamingUtil.GetIFCName(coupler)); for (int idx = 0; idx < nCouplerQuantity; idx++) { string instanceGUID = GUIDUtil.CreateSubElementGUID(coupler, idx); IFCAnyHandle style = currentTypeInfo.Style; if (IFCAnyHandleUtil.IsNullOrHasNoValue(style)) { return; } IList <IFCAnyHandle> repMapList = GeometryUtil.GetRepresentationMaps(style); if (repMapList == null) { return; } if (repMapList.Count == 0) { return; } IList <IFCAnyHandle> shapeReps = new List <IFCAnyHandle>(); IFCAnyHandle contextOfItems3d = exporterIFC.Get3DContextHandle("Body"); ISet <IFCAnyHandle> representations = new HashSet <IFCAnyHandle>(); representations.Add(ExporterUtil.CreateDefaultMappedItem(file, repMapList[0], XYZ.Zero)); IFCAnyHandle shapeRep = RepresentationUtil.CreateBodyMappedItemRep(exporterIFC, coupler, categoryId, contextOfItems3d, representations); shapeReps.Add(shapeRep); IFCAnyHandle productRepresentation = IFCInstanceExporter.CreateProductDefinitionShape(exporterIFC.GetFile(), null, null, shapeReps); Transform trf = coupler.GetCouplerPositionTransform(idx); using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, coupler, trf, null)) { IFCAnyHandle instanceHandle = null; IFCExportInfoPair exportMechFastener = new IFCExportInfoPair(); exportMechFastener.SetValueWithPair(IFCEntityType.IfcMechanicalFastener); instanceHandle = IFCInstanceExporter.CreateGenericIFCEntity(exportMechFastener, exporterIFC, coupler, instanceGUID, ownerHistory, setter.LocalPlacement, productRepresentation); string instanceName = NamingUtil.GetNameOverride(instanceHandle, coupler, origInstanceName + ": " + idx); IFCAnyHandleUtil.SetAttribute(instanceHandle, "Name", instanceName); if (ExporterCacheManager.ExportOptionsCache.ExportAs4) { // In IFC4 NominalDiameter and NominalLength attributes have been deprecated. PredefinedType attribute was added. IFCAnyHandleUtil.SetAttribute(instanceHandle, "PredefinedType", Revit.IFC.Export.Toolkit.IFC4.IFCMechanicalFastenerType.USERDEFINED); } else { IFCAnyHandleUtil.SetAttribute(instanceHandle, "NominalDiameter", familySymbol.get_Parameter(BuiltInParameter.COUPLER_WIDTH).AsDouble()); IFCAnyHandleUtil.SetAttribute(instanceHandle, "NominalLength", familySymbol.get_Parameter(BuiltInParameter.COUPLER_LENGTH).AsDouble()); } createdRebarCouplerHandles.Add(instanceHandle); productWrapper.AddElement(coupler, instanceHandle, setter, null, true); } } string couplerGUID = GUIDUtil.CreateGUID(coupler); if (nCouplerQuantity > 1) { // Create a group to hold all of the created IFC entities, if the coupler aren't already in an assembly. // We want to avoid nested groups of groups of couplers. if (coupler.AssemblyInstanceId == ElementId.InvalidElementId) { string revitObjectType = exporterIFC.GetFamilyName(); string name = NamingUtil.GetNameOverride(coupler, revitObjectType); string description = NamingUtil.GetDescriptionOverride(coupler, null); string objectType = NamingUtil.GetObjectTypeOverride(coupler, revitObjectType); IFCAnyHandle rebarGroup = IFCInstanceExporter.CreateGroup(file, couplerGUID, ownerHistory, name, description, objectType); productWrapper.AddElement(coupler, rebarGroup); IFCInstanceExporter.CreateRelAssignsToGroup(file, GUIDUtil.CreateGUID(), ownerHistory, null, null, createdRebarCouplerHandles, null, rebarGroup); } } else { // We will update the GUID of the one created element to be the element GUID. // This will allow the IfcGUID parameter to be use/set if appropriate. ExporterUtil.SetGlobalId(createdRebarCouplerHandles.ElementAt(0), couplerGUID); } tr.Commit(); } }
/// <summary> /// Exports a beam to IFC beam if it has an axis representation and only one Solid as its geometry, ideally as an extrusion, potentially with clippings and openings. /// </summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="element">The element to be exported.</param> /// <param name="geometryElement">The geometry element.</param> /// <param name="productWrapper">The ProductWrapper.</param> /// <param name="dontExport">An output value that says that the element shouldn't be exported at all.</param> /// <returns>The created handle.</returns> /// <remarks>In the original implementation, the ExportBeam function would export each beam as its own individual geometry (that is, not use representation maps). /// For non-standard beams, this could result in massive IFC files. Now, we use the ExportBeamAsStandardElement function and limit its scope, and instead /// resort to the standard FamilyInstanceExporter.ExportFamilyInstanceAsMappedItem for more complicated objects categorized as beams. This has the following pros and cons: /// Pro: possiblity for massively reduced file sizes for files containing repeated complex beam families /// Con: some beams that may have had an "Axis" representation before will no longer have them, although this possibility is minimized. /// Con: some beams that have 1 Solid and an axis, but that Solid will be heavily faceted, won't be helped by this improvement. /// It is intended that we phase out this routine entirely and instead teach ExportFamilyInstanceAsMappedItem how to sometimes export the Axis representation for beams.</remarks> public static IFCAnyHandle ExportBeamAsStandardElement(ExporterIFC exporterIFC, Element element, IFCExportInfoPair exportType, GeometryElement geometryElement, ProductWrapper productWrapper, out bool dontExport) { dontExport = true; IList <GeometryObject> geomObjects = BeamGeometryToExport(exporterIFC, element, geometryElement, out dontExport); if (dontExport) { return(null); } IFCAnyHandle beam = null; IFCFile file = exporterIFC.GetFile(); MaterialAndProfile materialAndProfile = null; IFCAnyHandle materialProfileSet = null; using (IFCTransaction transaction = new IFCTransaction(file)) { BeamAxisInfo axisInfo = GetBeamAxisTransform(element); bool canExportAxis = (axisInfo != null); Curve curve = canExportAxis ? axisInfo.Axis : null; XYZ beamDirection = canExportAxis ? axisInfo.AxisDirection : null; Transform orientTrf = canExportAxis ? axisInfo.LCSAsTransform : null; // Check for containment override IFCAnyHandle overrideContainerHnd = null; ElementId overrideContainerId = ParameterUtil.OverrideContainmentParameter(exporterIFC, element, out overrideContainerHnd); using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, element, null, orientTrf, overrideContainerId, overrideContainerHnd)) { IFCAnyHandle localPlacement = setter.LocalPlacement; using (IFCExtrusionCreationData extrusionCreationData = new IFCExtrusionCreationData()) { extrusionCreationData.SetLocalPlacement(localPlacement); if (canExportAxis && (orientTrf.BasisX != null)) { extrusionCreationData.CustomAxis = beamDirection; extrusionCreationData.PossibleExtrusionAxes = IFCExtrusionAxes.TryCustom; } else { extrusionCreationData.PossibleExtrusionAxes = IFCExtrusionAxes.TryXY; } ElementId catId = CategoryUtil.GetSafeCategoryId(element); // There may be an offset to make the local coordinate system // be near the origin. This offset will be used to move the axis to the new LCS. Transform offsetTransform = null; // The list of materials in the solids or meshes. ICollection <ElementId> materialIds = null; // If the beam is a FamilyInstance, and it uses transformed FamilySymbol geometry only, then // let's only try to CreateBeamGeometryAsExtrusion unsuccesfully once. Otherwise, we can spend a lot of time trying // unsuccessfully to do so. bool tryToCreateBeamGeometryAsExtrusion = true; //bool useFamilySymbolGeometry = (element is FamilyInstance) ? !ExporterIFCUtils.UsesInstanceGeometry(element as FamilyInstance) : false; bool useFamilySymbolGeometry = (element is FamilyInstance) ? !GeometryUtil.UsesInstanceGeometry(element as FamilyInstance) : false; ElementId beamTypeId = element.GetTypeId(); if (useFamilySymbolGeometry) { tryToCreateBeamGeometryAsExtrusion = !ExporterCacheManager.CanExportBeamGeometryAsExtrusionCache.ContainsKey(beamTypeId) || ExporterCacheManager.CanExportBeamGeometryAsExtrusionCache[beamTypeId]; } // The representation handle generated from one of the methods below. BeamBodyAsExtrusionInfo extrusionInfo = null; if (tryToCreateBeamGeometryAsExtrusion) { extrusionInfo = CreateBeamGeometryAsExtrusion(exporterIFC, element, catId, geomObjects, axisInfo); if (useFamilySymbolGeometry) { ExporterCacheManager.CanExportBeamGeometryAsExtrusionCache[beamTypeId] = (extrusionInfo != null); } } if (extrusionInfo != null && extrusionInfo.DontExport) { dontExport = true; return(null); } IFCAnyHandle repHnd = (extrusionInfo != null) ? extrusionInfo.RepresentationHandle : null; if (!IFCAnyHandleUtil.IsNullOrHasNoValue(repHnd)) { materialIds = extrusionInfo.Materials; extrusionCreationData.Slope = extrusionInfo.Slope; } else { // Here is where we limit the scope of how complex a case we will still try to export as a standard element. // This is explicitly added so that many curved beams that can be represented by a reasonable facetation because of the // SweptSolidExporter can still have an Axis representation. BodyData bodyData = null; BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true, ExportOptionsCache.ExportTessellationLevel.ExtraLow); if (ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView) { bodyExporterOptions.CollectMaterialAndProfile = false; } else { bodyExporterOptions.CollectMaterialAndProfile = true; } if (geomObjects != null && geomObjects.Count == 1 && geomObjects[0] is Solid) { bodyData = BodyExporter.ExportBody(exporterIFC, element, catId, ElementId.InvalidElementId, geomObjects[0], bodyExporterOptions, extrusionCreationData); repHnd = bodyData.RepresentationHnd; materialIds = bodyData.MaterialIds; if (!bodyData.OffsetTransform.IsIdentity) { offsetTransform = bodyData.OffsetTransform; } materialAndProfile = bodyData.MaterialAndProfile; } } if (IFCAnyHandleUtil.IsNullOrHasNoValue(repHnd)) { extrusionCreationData.ClearOpenings(); return(null); } IList <IFCAnyHandle> representations = new List <IFCAnyHandle>(); IFCAnyHandle axisRep = CreateBeamAxis(exporterIFC, element, catId, axisInfo, offsetTransform); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(axisRep)) { representations.Add(axisRep); } representations.Add(repHnd); Transform boundingBoxTrf = (offsetTransform == null) ? Transform.Identity : offsetTransform.Inverse; IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geometryElement, boundingBoxTrf); if (boundingBoxRep != null) { representations.Add(boundingBoxRep); } IFCAnyHandle prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations); string instanceGUID = GUIDUtil.CreateGUID(element); beam = IFCInstanceExporter.CreateBeam(exporterIFC, element, instanceGUID, ExporterCacheManager.OwnerHistoryHandle, extrusionCreationData.GetLocalPlacement(), prodRep, exportType.ValidatedPredefinedType); IFCAnyHandle mpSetUsage; if (materialProfileSet != null) { mpSetUsage = IFCInstanceExporter.CreateMaterialProfileSetUsage(file, materialProfileSet, null, null); } productWrapper.AddElement(element, beam, setter, extrusionCreationData, true, exportType); ExportBeamType(exporterIFC, productWrapper, beam, element, exportType.ValidatedPredefinedType); OpeningUtil.CreateOpeningsIfNecessary(beam, element, extrusionCreationData, offsetTransform, exporterIFC, extrusionCreationData.GetLocalPlacement(), setter, productWrapper); FamilyTypeInfo typeInfo = new FamilyTypeInfo(); typeInfo.ScaledDepth = extrusionCreationData.ScaledLength; typeInfo.ScaledArea = extrusionCreationData.ScaledArea; typeInfo.ScaledInnerPerimeter = extrusionCreationData.ScaledInnerPerimeter; typeInfo.ScaledOuterPerimeter = extrusionCreationData.ScaledOuterPerimeter; PropertyUtil.CreateBeamColumnBaseQuantities(exporterIFC, beam, element, typeInfo, null); if (materialIds.Count != 0) { CategoryUtil.CreateMaterialAssociation(exporterIFC, beam, materialIds); } // Register the beam's IFC handle for later use by truss and beam system export. ExporterCacheManager.ElementToHandleCache.Register(element.Id, beam, exportType); } } transaction.Commit(); return(beam); } }
/// <summary> /// Export the individual part (IfcBuildingElementPart). /// </summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="partElement">The part element to export.</param> /// <param name="geometryElement">The geometry of part.</param> /// <param name="productWrapper">The ProductWrapper object.</param> public static void ExportPart(ExporterIFC exporterIFC, Element partElement, ProductWrapper productWrapper, PlacementSetter placementSetter, IFCAnyHandle originalPlacement, IFCRange range, IFCExtrusionAxes ifcExtrusionAxes, Element hostElement, ElementId overrideLevelId, bool asBuildingElement) { if (!ElementFilteringUtil.IsElementVisible(partElement)) { return; } Part part = partElement as Part; if (part == null) { return; } if (!asBuildingElement) { // Check the intended IFC entity or type name is in the exclude list specified in the UI Common.Enums.IFCEntityType elementClassTypeEnum; if (Enum.TryParse <Common.Enums.IFCEntityType>("IfcBuildingElementPart", out elementClassTypeEnum)) { if (ExporterCacheManager.ExportOptionsCache.IsElementInExcludeList(elementClassTypeEnum)) { return; } } } else { string ifcEnumType = null; IFCExportType exportType = ExporterUtil.GetExportType(exporterIFC, hostElement, out ifcEnumType); // Check the intended IFC entity or type name is in the exclude list specified in the UI Common.Enums.IFCEntityType elementClassTypeEnum; if (Enum.TryParse <Common.Enums.IFCEntityType>(exportType.ToString(), out elementClassTypeEnum)) { if (ExporterCacheManager.ExportOptionsCache.IsElementInExcludeList(elementClassTypeEnum)) { return; } } } PlacementSetter standalonePlacementSetter = null; bool standaloneExport = hostElement == null && !asBuildingElement; ElementId partExportLevel = null; if (standaloneExport || asBuildingElement) { partExportLevel = partElement.LevelId; } else { if (part.OriginalCategoryId != hostElement.Category.Id) { return; } partExportLevel = hostElement.LevelId; } if (overrideLevelId != null) { partExportLevel = overrideLevelId; } if (ExporterCacheManager.PartExportedCache.HasExported(partElement.Id, partExportLevel)) { return; } Options options = GeometryUtil.GetIFCExportGeometryOptions(); View ownerView = partElement.Document.GetElement(partElement.OwnerViewId) as View; if (ownerView != null) { options.View = ownerView; } GeometryElement geometryElement = partElement.get_Geometry(options); if (geometryElement == null) { return; } try { IFCFile file = exporterIFC.GetFile(); using (IFCTransaction transaction = new IFCTransaction(file)) { IFCAnyHandle partPlacement = null; if (standaloneExport || asBuildingElement) { Transform orientationTrf = Transform.Identity; standalonePlacementSetter = PlacementSetter.Create(exporterIFC, partElement, null, orientationTrf, partExportLevel); partPlacement = standalonePlacementSetter.LocalPlacement; } else { partPlacement = ExporterUtil.CreateLocalPlacement(file, originalPlacement, null); } bool validRange = (range != null && !MathUtil.IsAlmostZero(range.Start - range.End)); SolidMeshGeometryInfo solidMeshInfo; if (validRange) { solidMeshInfo = GeometryUtil.GetSplitClippedSolidMeshGeometry(geometryElement, range); if (solidMeshInfo.GetSolids().Count == 0 && solidMeshInfo.GetMeshes().Count == 0) { return; } } else { solidMeshInfo = GeometryUtil.GetSplitSolidMeshGeometry(geometryElement); } using (IFCExtrusionCreationData extrusionCreationData = new IFCExtrusionCreationData()) { extrusionCreationData.SetLocalPlacement(partPlacement); extrusionCreationData.ReuseLocalPlacement = false; extrusionCreationData.PossibleExtrusionAxes = ifcExtrusionAxes; IList <Solid> solids = solidMeshInfo.GetSolids(); IList <Mesh> meshes = solidMeshInfo.GetMeshes(); ElementId catId = CategoryUtil.GetSafeCategoryId(partElement); ElementId hostCatId = CategoryUtil.GetSafeCategoryId(hostElement); BodyData bodyData = null; BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true, ExportOptionsCache.ExportTessellationLevel.ExtraLow); if (solids.Count > 0 || meshes.Count > 0) { bodyData = BodyExporter.ExportBody(exporterIFC, partElement, catId, ElementId.InvalidElementId, solids, meshes, bodyExporterOptions, extrusionCreationData); } else { IList <GeometryObject> geomlist = new List <GeometryObject>(); geomlist.Add(geometryElement); bodyData = BodyExporter.ExportBody(exporterIFC, partElement, catId, ElementId.InvalidElementId, geomlist, bodyExporterOptions, extrusionCreationData); } IFCAnyHandle bodyRep = bodyData.RepresentationHnd; if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep)) { extrusionCreationData.ClearOpenings(); return; } IList <IFCAnyHandle> representations = new List <IFCAnyHandle>(); representations.Add(bodyRep); IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geometryElement, Transform.Identity); if (boundingBoxRep != null) { representations.Add(boundingBoxRep); } IFCAnyHandle prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations); IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle; string partGUID = GUIDUtil.CreateGUID(partElement); string partName = NamingUtil.GetNameOverride(partElement, NamingUtil.GetIFCName(partElement)); string partDescription = NamingUtil.GetDescriptionOverride(partElement, null); string partObjectType = NamingUtil.GetObjectTypeOverride(partElement, NamingUtil.CreateIFCObjectName(exporterIFC, partElement)); string partTag = NamingUtil.GetTagOverride(partElement, NamingUtil.CreateIFCElementId(partElement)); IFCAnyHandle ifcPart = null; if (!asBuildingElement) { ifcPart = IFCInstanceExporter.CreateBuildingElementPart(file, partGUID, ownerHistory, partName, partDescription, partObjectType, extrusionCreationData.GetLocalPlacement(), prodRep, partTag); } else { string ifcEnumType = null; IFCExportType exportType = ExporterUtil.GetExportType(exporterIFC, hostElement, out ifcEnumType); string defaultValue = null; // This replicates old functionality before IFC4 addition, where the default for slab was "FLOOR". // Really the export layer table should be fixed for this case. if (string.IsNullOrWhiteSpace(ifcEnumType) && hostCatId == new ElementId(BuiltInCategory.OST_Floors)) { ifcEnumType = "FLOOR"; } ifcEnumType = IFCValidateEntry.GetValidIFCType(hostElement, ifcEnumType, defaultValue); switch (exportType) { case IFCExportType.IfcColumnType: ifcPart = IFCInstanceExporter.CreateColumn(file, partGUID, ownerHistory, partName, partDescription, partObjectType, extrusionCreationData.GetLocalPlacement(), prodRep, partTag, ifcEnumType); break; case IFCExportType.IfcCovering: ifcPart = IFCInstanceExporter.CreateCovering(file, partGUID, ownerHistory, partName, partDescription, partObjectType, extrusionCreationData.GetLocalPlacement(), prodRep, partTag, ifcEnumType); break; case IFCExportType.IfcFooting: ifcPart = IFCInstanceExporter.CreateFooting(file, partGUID, ownerHistory, partName, partDescription, partObjectType, extrusionCreationData.GetLocalPlacement(), prodRep, partTag, ifcEnumType); break; case IFCExportType.IfcPile: ifcPart = IFCInstanceExporter.CreatePile(file, partGUID, ownerHistory, partName, partDescription, partObjectType, extrusionCreationData.GetLocalPlacement(), prodRep, partTag, ifcEnumType, null); break; case IFCExportType.IfcRoof: ifcPart = IFCInstanceExporter.CreateRoof(file, partGUID, ownerHistory, partName, partDescription, partObjectType, extrusionCreationData.GetLocalPlacement(), prodRep, partTag, ifcEnumType); break; case IFCExportType.IfcSlab: ifcPart = IFCInstanceExporter.CreateSlab(file, partGUID, ownerHistory, partName, partDescription, partObjectType, extrusionCreationData.GetLocalPlacement(), prodRep, partTag, ifcEnumType); break; case IFCExportType.IfcWall: ifcPart = IFCInstanceExporter.CreateWall(file, partGUID, ownerHistory, partName, partDescription, partObjectType, extrusionCreationData.GetLocalPlacement(), prodRep, partTag, ifcEnumType); break; default: ifcPart = IFCInstanceExporter.CreateBuildingElementProxy(file, partGUID, ownerHistory, partName, partDescription, partObjectType, extrusionCreationData.GetLocalPlacement(), prodRep, partTag, null); break; } } bool containedInLevel = (standaloneExport || asBuildingElement); PlacementSetter whichPlacementSetter = containedInLevel ? standalonePlacementSetter : placementSetter; productWrapper.AddElement(partElement, ifcPart, whichPlacementSetter, extrusionCreationData, containedInLevel); OpeningUtil.CreateOpeningsIfNecessary(ifcPart, partElement, extrusionCreationData, bodyData.OffsetTransform, exporterIFC, extrusionCreationData.GetLocalPlacement(), whichPlacementSetter, productWrapper); //Add the exported part to exported cache. TraceExportedParts(partElement, partExportLevel, standaloneExport || asBuildingElement ? ElementId.InvalidElementId : hostElement.Id); CategoryUtil.CreateMaterialAssociation(exporterIFC, ifcPart, bodyData.MaterialIds); transaction.Commit(); } } } finally { if (standalonePlacementSetter != null) { standalonePlacementSetter.Dispose(); } } }
/// <summary> /// Exports an element as IFC railing. /// </summary> /// <param name="exporterIFC"> /// The ExporterIFC object. /// </param> /// <param name="element"> /// The element to be exported. /// </param> /// <param name="geometryElement"> /// The geometry element. /// </param> /// <param name="productWrapper"> /// The ProductWrapper. /// </param> public static void ExportRailing(ExporterIFC exporterIFC, Element element, GeometryElement geomElem, string ifcEnumType, ProductWrapper productWrapper) { // Check the intended IFC entity or type name is in the exclude list specified in the UI Common.Enums.IFCEntityType elementClassTypeEnum = Common.Enums.IFCEntityType.IfcRailing; if (ExporterCacheManager.ExportOptionsCache.IsElementInExcludeList(elementClassTypeEnum)) { return; } ElementType elemType = element.Document.GetElement(element.GetTypeId()) as ElementType; IFCFile file = exporterIFC.GetFile(); Options geomOptions = GeometryUtil.GetIFCExportGeometryOptions(); using (IFCTransaction transaction = new IFCTransaction(file)) { // Check for containment override IFCAnyHandle overrideContainerHnd = null; ElementId overrideContainerId = ParameterUtil.OverrideContainmentParameter(exporterIFC, element, out overrideContainerHnd); using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, element, null, null, overrideContainerId, overrideContainerHnd)) { using (IFCExtrusionCreationData ecData = new IFCExtrusionCreationData()) { IFCAnyHandle localPlacement = setter.LocalPlacement; StairRampContainerInfo stairRampInfo = null; ElementId hostId = GetStairOrRampHostId(exporterIFC, element as Railing); Transform inverseTrf = Transform.Identity; if (hostId != ElementId.InvalidElementId) { stairRampInfo = ExporterCacheManager.StairRampContainerInfoCache.GetStairRampContainerInfo(hostId); IFCAnyHandle stairRampLocalPlacement = stairRampInfo.LocalPlacements[0]; Transform relTrf = ExporterIFCUtils.GetRelativeLocalPlacementOffsetTransform(stairRampLocalPlacement, localPlacement); inverseTrf = relTrf.Inverse; IFCAnyHandle railingLocalPlacement = ExporterUtil.CreateLocalPlacement(file, stairRampLocalPlacement, inverseTrf.Origin, inverseTrf.BasisZ, inverseTrf.BasisX); localPlacement = railingLocalPlacement; } ecData.SetLocalPlacement(localPlacement); SolidMeshGeometryInfo solidMeshInfo = GeometryUtil.GetSplitSolidMeshGeometry(geomElem); IList <Solid> solids = solidMeshInfo.GetSolids(); IList <Mesh> meshes = solidMeshInfo.GetMeshes(); IList <GeometryObject> gObjs = FamilyExporterUtil.RemoveInvisibleSolidsAndMeshes(element.Document, exporterIFC, ref solids, ref meshes); Railing railingElem = element as Railing; IList <ElementId> subElementIds = CollectSubElements(railingElem); foreach (ElementId subElementId in subElementIds) { Element subElement = railingElem.Document.GetElement(subElementId); if (subElement != null) { GeometryElement allLevelsGeometry = subElement.get_Geometry(geomOptions); var oneLevelGeom = GeometryUtil.GetOneLevelGeometryElement(allLevelsGeometry, 0); GeometryElement subElementGeom = oneLevelGeom.element; // Get rail terminations geometry List <GeometryElement> overallGeometry = GeometryUtil.GetAdditionalOneLevelGeometry(allLevelsGeometry, oneLevelGeom.symbolId); overallGeometry.Add(subElementGeom); foreach (GeometryElement subGeomentry in overallGeometry) { SolidMeshGeometryInfo subElementSolidMeshInfo = GeometryUtil.GetSplitSolidMeshGeometry(subGeomentry); IList <Solid> subElemSolids = subElementSolidMeshInfo.GetSolids(); IList <Mesh> subElemMeshes = subElementSolidMeshInfo.GetMeshes(); IList <GeometryObject> partGObjs = FamilyExporterUtil.RemoveInvisibleSolidsAndMeshes(element.Document, exporterIFC, ref subElemSolids, ref subElemMeshes); foreach (Solid subElSolid in subElemSolids) { solids.Add(subElSolid); } foreach (Mesh subElMesh in subElemMeshes) { meshes.Add(subElMesh); } } } } ElementId catId = CategoryUtil.GetSafeCategoryId(element); BodyData bodyData = null; BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true, ExportOptionsCache.ExportTessellationLevel.Medium); if (solids.Count > 0 || meshes.Count > 0) { bodyData = BodyExporter.ExportBody(exporterIFC, element, catId, ElementId.InvalidElementId, solids, meshes, bodyExporterOptions, ecData); } else { IList <GeometryObject> geomlist = new List <GeometryObject>(); geomlist.Add(geomElem); bodyData = BodyExporter.ExportBody(exporterIFC, element, catId, ElementId.InvalidElementId, geomlist, bodyExporterOptions, ecData); } IFCAnyHandle bodyRep = bodyData.RepresentationHnd; if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep)) { if (ecData != null) { ecData.ClearOpenings(); } return; } IList <IFCAnyHandle> representations = new List <IFCAnyHandle>(); representations.Add(bodyRep); IList <GeometryObject> geomObjects = new List <GeometryObject>(solids); foreach (Mesh mesh in meshes) { geomObjects.Add(mesh); } Transform boundingBoxTrf = (bodyData.OffsetTransform != null) ? bodyData.OffsetTransform.Inverse : Transform.Identity; boundingBoxTrf = inverseTrf.Multiply(boundingBoxTrf); IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geomObjects, boundingBoxTrf); if (boundingBoxRep != null) { representations.Add(boundingBoxRep); } IFCAnyHandle prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations); IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle; string instanceGUID = GUIDUtil.CreateGUID(element); IFCExportInfoPair exportInfo = ExporterUtil.GetProductExportType(exporterIFC, element, out ifcEnumType); IFCAnyHandle railing = IFCInstanceExporter.CreateGenericIFCEntity(exportInfo, exporterIFC, element, instanceGUID, ownerHistory, ecData.GetLocalPlacement(), prodRep); bool associateToLevel = (hostId == ElementId.InvalidElementId); productWrapper.AddElement(element, railing, setter, ecData, associateToLevel, exportInfo); OpeningUtil.CreateOpeningsIfNecessary(railing, element, ecData, bodyData.OffsetTransform, exporterIFC, ecData.GetLocalPlacement(), setter, productWrapper); IFCAnyHandle singleMaterialOverrideHnd = null; IList <ElementId> matIds = null; ElementId defaultMatId = ElementId.InvalidElementId; ElementId matId = CategoryUtil.GetBaseMaterialIdForElement(element); // Get IfcSingleMaterialOverride to work for railing singleMaterialOverrideHnd = ExporterUtil.GetSingleMaterial(exporterIFC, element, matId); if (singleMaterialOverrideHnd != null) { matIds = new List <ElementId> { matId }; } else { matIds = bodyData.MaterialIds; defaultMatId = matIds[0]; // Check if all the items are the same, then get the first material id if (matIds.All(x => x == defaultMatId)) { matIds = new List <ElementId> { defaultMatId }; } } CategoryUtil.CreateMaterialAssociationWithShapeAspect(exporterIFC, element, railing, bodyData.RepresentationItemInfo); // Create multi-story duplicates of this railing. if (stairRampInfo != null) { stairRampInfo.AddComponent(0, railing); List <IFCAnyHandle> stairHandles = stairRampInfo.StairOrRampHandles; int levelCount = stairHandles.Count; if (levelCount > 0 && railingElem != null) { Stairs stairs = railingElem.Document.GetElement(railingElem.HostId) as Stairs; if ((stairs?.MultistoryStairsId ?? ElementId.InvalidElementId) != ElementId.InvalidElementId) { // If the railing is hosted by stairs, don't use stairHandles.Count, // use ids (count) of levels the railing is placed on. ISet <ElementId> multistoryStairsPlacementLevels = railingElem.GetMultistoryStairsPlacementLevels(); if (multistoryStairsPlacementLevels != null) { levelCount = multistoryStairsPlacementLevels.Count; } } } for (int ii = 1; ii < levelCount; ii++) { IFCAnyHandle railingLocalPlacement = stairRampInfo.LocalPlacements[ii]; if (!IFCAnyHandleUtil.IsNullOrHasNoValue(railingLocalPlacement)) { IFCAnyHandle railingHndCopy = CopyRailingHandle(exporterIFC, element, catId, railingLocalPlacement, railing, ii); stairRampInfo.AddComponent(ii, railingHndCopy); productWrapper.AddElement(element, railingHndCopy, (IFCLevelInfo)null, ecData, false, exportInfo); CategoryUtil.CreateMaterialAssociationWithShapeAspect(exporterIFC, element, railingHndCopy, bodyData.RepresentationItemInfo); } } ExporterCacheManager.StairRampContainerInfoCache.AddStairRampContainerInfo(hostId, stairRampInfo); } } transaction.Commit(); } } }