/// <summary> /// Finds the spatial element to its associated level. /// </summary> /// <param name="exporterIFC"> /// The ExporterIFC object. /// </param> /// <param name="element"> /// The element. /// </param> /// <returns> /// The handle. /// </returns> public override IFCAnyHandle RedirectDescription(ExporterIFC exporterIFC, Element element) { SpatialElement spatialElem = element as SpatialElement; if (spatialElem != null) { ElementId levelId = spatialElem.LevelId; IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(levelId); if (levelInfo != null) return levelInfo.GetBuildingStorey(); } return null; }
/// <summary> /// Finds the spatial element to its associated level. /// </summary> /// <param name="exporterIFC"> /// The ExporterIFC object. /// </param> /// <param name="element"> /// The element. /// </param> /// <returns> /// The handle. /// </returns> public override IFCAnyHandle RedirectDescription(ExporterIFC exporterIFC, Element element) { SpatialElement spatialElem = element as SpatialElement; if (spatialElem != null) { ElementId levelId = spatialElem.LevelId; IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(levelId); if (levelInfo != null) { return(levelInfo.GetBuildingStorey()); } } return(null); }
/// <summary> /// Exports a family instance as a mapped item. /// </summary> /// <param name="exporterIFC"> /// The ExporterIFC object. /// </param> /// <param name="familyInstance"> /// The family instance to be exported. /// </param> /// <param name="exportType"> /// The export type. /// </param> /// <param name="ifcEnumType"> /// The string value represents the IFC type. /// </param> /// <param name="wrapper"> /// The ProductWrapper. /// </param> /// <param name="overrideLevelId"> /// The level id. /// </param> /// <param name="range"> /// The range of this family instance to be exported. /// </param> public static void ExportFamilyInstanceAsMappedItem(ExporterIFC exporterIFC, FamilyInstance familyInstance, IFCExportType exportType, string ifcEnumType, ProductWrapper wrapper, ElementId overrideLevelId, IFCRange range, IFCAnyHandle parentLocalPlacement) { bool exportParts = PartExporter.CanExportParts(familyInstance); bool isSplit = range != null; if (exportParts && !PartExporter.CanExportElementInPartExport(familyInstance, isSplit ? overrideLevelId : familyInstance.Level.Id, isSplit)) return; Document doc = familyInstance.Document; IFCFile file = exporterIFC.GetFile(); FamilySymbol familySymbol = ExporterIFCUtils.GetOriginalSymbol(familyInstance); if (familySymbol == null) return; ProductWrapper familyProductWrapper = ProductWrapper.Create(wrapper); double scale = exporterIFC.LinearScale; Options options = GeometryUtil.GetIFCExportGeometryOptions(); IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle(); HostObject hostElement = familyInstance.Host as HostObject; //hostElement could be null ElementId categoryId = CategoryUtil.GetSafeCategoryId(familySymbol); //string emptyString = ""; string familyName = familySymbol.Name; string objectType = familyName; // A Family Instance can have its own copy of geometry, or use the symbol's copy with a transform. // The routine below tells us whether to use the Instance's copy or the Symbol's copy. bool useInstanceGeometry = ExporterIFCUtils.UsesInstanceGeometry(familyInstance); IList<IFCExtrusionData> cutPairOpeningsForColumns = new List<IFCExtrusionData>(); using (IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData()) { Transform trf = familyInstance.GetTransform(); // Extra information if we are exporting a door or a window. IFCDoorWindowInfo doorWindowInfo = null; if (exportType == IFCExportType.ExportDoorType) doorWindowInfo = IFCDoorWindowInfo.CreateDoorInfo(exporterIFC, familyInstance, familySymbol, hostElement, overrideLevelId, trf); else if (exportType == IFCExportType.ExportWindowType) doorWindowInfo = IFCDoorWindowInfo.CreateWindowInfo(exporterIFC, familyInstance, familySymbol, hostElement, overrideLevelId, trf); FamilyTypeInfo typeInfo = new FamilyTypeInfo(); XYZ extraOffset = XYZ.Zero; bool flipped = doorWindowInfo != null ? doorWindowInfo.IsSymbolFlipped : false; FamilyTypeInfo currentTypeInfo = ExporterCacheManager.TypeObjectsCache.Find(familySymbol.Id, flipped); bool found = currentTypeInfo.IsValid(); Family family = familySymbol.Family; // TODO: this code to be removed by ExtrusionAnalyzer code. bool trySpecialColumnCreation = ((exportType == IFCExportType.ExportColumnType) && (!family.IsInPlace)); IList<GeometryObject> geomObjects = new List<GeometryObject>(); Transform brepOffsetTransform = null; Transform doorWindowTrf = Transform.Identity; // We will create a new mapped type if: // 1. We are exporting part of a column or in-place wall (range != null), OR // 2. We are using the instance's copy of the geometry (that it, it has unique geometry), OR // 3. We haven't already created the type. bool creatingType = ((range != null) || useInstanceGeometry || !found); if (creatingType) { IFCAnyHandle bodyRepresentation = null; IFCAnyHandle planRepresentation = null; // If we are using the instance geometry, ignore the transformation. if (useInstanceGeometry) trf = Transform.Identity; // TODO: this code to be removed by ExtrusionAnalyzer code. if (trySpecialColumnCreation) { XYZ rangeOffset = trf.Origin; IFCFamilyInstanceExtrusionExportResults results; results = ExporterIFCUtils.ExportFamilyInstanceAsExtrusion(exporterIFC, familyInstance, useInstanceGeometry, range, overrideLevelId, extraParams); bodyRepresentation = results.GetExtrusionHandle(); extraOffset = results.ExtraOffset; cutPairOpeningsForColumns = results.GetCutPairOpenings(); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRepresentation)) { typeInfo.MaterialIds.Add(results.MaterialId); // add in level for real columns, not in-place ones. Element actualLevel = (overrideLevelId == ElementId.InvalidElementId) ? familyInstance.Level : doc.GetElement(overrideLevelId); if (actualLevel != null) { IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(actualLevel.Id); double nonStoryLevelOffset = LevelUtil.GetNonStoryLevelOffsetIfAny(exporterIFC, actualLevel as Level); if (range != null) { rangeOffset = new XYZ(rangeOffset.X, rangeOffset.Y, levelInfo.Elevation + nonStoryLevelOffset); } } } rangeOffset += extraOffset; trf.Origin = rangeOffset; } IFCAnyHandle dummyPlacement = null; if (doorWindowInfo != null) { doorWindowTrf = ExporterIFCUtils.GetTransformForDoorOrWindow(familyInstance, familySymbol, doorWindowInfo); } else { dummyPlacement = IFCInstanceExporter.CreateLocalPlacement(file, null, ExporterUtil.CreateAxis2Placement3D(file)); extraParams.SetLocalPlacement(dummyPlacement); } bool needToCreate2d = ExporterCacheManager.ExportOptionsCache.ExportAnnotations; bool needToCreate3d = IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRepresentation); if (needToCreate2d || needToCreate3d) { using (IFCTransformSetter trfSetter = IFCTransformSetter.Create()) { if (doorWindowInfo != null) { trfSetter.Initialize(exporterIFC, doorWindowTrf); } GeometryElement exportGeometry = useInstanceGeometry ? familyInstance.get_Geometry(options) : familySymbol.get_Geometry(options); if (exportGeometry == null) return; if (needToCreate3d) { SolidMeshGeometryInfo solidMeshCapsule = null; if (range == null) { solidMeshCapsule = GeometryUtil.GetSolidMeshGeometry(exportGeometry, Transform.Identity); } else { solidMeshCapsule = GeometryUtil.GetClippedSolidMeshGeometry(exportGeometry, range); } IList<Solid> solids = solidMeshCapsule.GetSolids(); IList<Mesh> polyMeshes = solidMeshCapsule.GetMeshes(); if (range != null && (solids.Count == 0 && polyMeshes.Count == 0)) return; // no proper split geometry geomObjects = FamilyExporterUtil.RemoveSolidsAndMeshesSetToDontExport(doc, exporterIFC, solids, polyMeshes); if (geomObjects.Count == 0 && (solids.Count > 0 || polyMeshes.Count > 0)) return; bool tryToExportAsExtrusion = (!exporterIFC.ExportAs2x2 || (exportType == IFCExportType.ExportColumnType)); if (exportType == IFCExportType.ExportColumnType) { extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ; if (ExporterCacheManager.ExportOptionsCache.ExportAs2x3CoordinationView2 && solids.Count > 0) { LocationPoint point = familyInstance.Location as LocationPoint; XYZ orig = XYZ.Zero; if (point != null) orig = point.Point; Plane plane = new Plane(XYZ.BasisX, XYZ.BasisY, orig); bool completelyClipped = false; HashSet<ElementId> materialIds = null; bodyRepresentation = ExtrusionExporter.CreateExtrusionWithClipping(exporterIFC, familyInstance, categoryId, solids, plane, XYZ.BasisZ, null, out completelyClipped, out materialIds); typeInfo.MaterialIds = materialIds; } } else { extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryXYZ; } BodyData bodyData = null; if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRepresentation)) { BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(tryToExportAsExtrusion); if (geomObjects.Count > 0) { bodyData = BodyExporter.ExportBody(familyInstance.Document.Application, exporterIFC, familyInstance, categoryId, ElementId.InvalidElementId, geomObjects, bodyExporterOptions, extraParams); typeInfo.MaterialIds = bodyData.MaterialIds; } else { IList<GeometryObject> exportedGeometries = new List<GeometryObject>(); exportedGeometries.Add(exportGeometry); bodyData = BodyExporter.ExportBody(familyInstance.Document.Application, exporterIFC, familyInstance, categoryId, ElementId.InvalidElementId, exportedGeometries, bodyExporterOptions, extraParams); } bodyRepresentation = bodyData.RepresentationHnd; brepOffsetTransform = bodyData.BrepOffsetTransform; } if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRepresentation)) { extraParams.ClearOpenings(); return; } } // By default: if exporting IFC2x3 or later, export 2D plan rep of family, if it exists, unless we are exporting Coordination View V2. // This default can be overridden in the export options. if (needToCreate2d) { XYZ curveOffset = new XYZ(0, 0, 0); if (brepOffsetTransform != null) curveOffset = -brepOffsetTransform.Origin / scale; HashSet<IFCAnyHandle> curveSet = new HashSet<IFCAnyHandle>(); { Transform planeTrf = doorWindowTrf.Inverse; Plane plane = new Plane(planeTrf.get_Basis(0), planeTrf.get_Basis(1), planeTrf.Origin); XYZ projDir = new XYZ(0, 0, 1); IFCGeometryInfo IFCGeometryInfo = IFCGeometryInfo.CreateCurveGeometryInfo(exporterIFC, plane, projDir, true); ExporterIFCUtils.CollectGeometryInfo(exporterIFC, IFCGeometryInfo, exportGeometry, curveOffset, false); IList<IFCAnyHandle> curves = IFCGeometryInfo.GetCurves(); foreach (IFCAnyHandle curve in curves) curveSet.Add(curve); if (curveSet.Count > 0) { IFCAnyHandle contextOfItems2d = exporterIFC.Get2DContextHandle(); IFCAnyHandle curveRepresentationItem = IFCInstanceExporter.CreateGeometricSet(file, curveSet); HashSet<IFCAnyHandle> bodyItems = new HashSet<IFCAnyHandle>(); bodyItems.Add(curveRepresentationItem); planRepresentation = RepresentationUtil.CreateGeometricSetRep(exporterIFC, familyInstance, categoryId, "Annotation", contextOfItems2d, bodyItems); } } } } } if (doorWindowInfo != null) { typeInfo.StyleTransform = doorWindowTrf.Inverse; } else { if (!MathUtil.IsAlmostZero(extraOffset.DotProduct(extraOffset))) { Transform newTransform = typeInfo.StyleTransform; XYZ newOrig = newTransform.Origin + extraOffset; newTransform.Origin = newOrig; typeInfo.StyleTransform = newTransform; } typeInfo.StyleTransform = ExporterIFCUtils.GetUnscaledTransform(exporterIFC, extraParams.GetLocalPlacement()); } IFCAnyHandle origin = ExporterUtil.CreateAxis2Placement3D(file); IFCAnyHandle repMap2dHnd = null; IFCAnyHandle repMap3dHnd = IFCInstanceExporter.CreateRepresentationMap(file, origin, bodyRepresentation); IList<IFCAnyHandle> repMapList = new List<IFCAnyHandle>(); repMapList.Add(repMap3dHnd); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(planRepresentation)) { repMap2dHnd = IFCInstanceExporter.CreateRepresentationMap(file, origin, planRepresentation); repMapList.Add(repMap2dHnd); } // for Door, Window bool paramTakesPrecedence = false; // For Revit, this is currently always false. bool sizeable = false; // for many HashSet<IFCAnyHandle> propertySets = new HashSet<IFCAnyHandle>(); string guid = GUIDUtil.CreateGUID(familySymbol); string symId = NamingUtil.CreateIFCElementId(familySymbol); // This covers many generic types. If we can't find it in the list here, do custom exports. IFCAnyHandle typeStyle = FamilyExporterUtil.ExportGenericType(file, exportType, ifcEnumType, guid, ownerHistory, objectType, null, null, propertySets, repMapList, symId, objectType, familyInstance, familySymbol); // Cover special cases not covered above. if (IFCAnyHandleUtil.IsNullOrHasNoValue(typeStyle)) { switch (exportType) { case IFCExportType.ExportColumnType: { // If we are using the instance GRep, then we have to create a generic GUID for the // column type, as they share the same ElementId. string colGUID = null; string colElemId = null; if (useInstanceGeometry) colGUID = GUIDUtil.CreateGUID(); else colGUID = guid; colElemId = NamingUtil.CreateIFCElementId(familySymbol); string columnType = "Column"; typeStyle = IFCInstanceExporter.CreateColumnType(file, colGUID, ownerHistory, objectType, null, null, propertySets, repMapList, colElemId, objectType, GetColumnType(familyInstance, columnType)); break; } case IFCExportType.ExportDoorType: { string constructionType = string.Empty; ParameterUtil.GetStringValueFromElementOrSymbol(familyInstance, "Construction", out constructionType); IFCAnyHandle doorLining = DoorWindowUtil.CreateDoorLiningProperties(exporterIFC, familyInstance); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(doorLining)) propertySets.Add(doorLining); IList<IFCAnyHandle> doorPanels = DoorWindowUtil.CreateDoorPanelProperties(exporterIFC, doorWindowInfo, familyInstance); propertySets.UnionWith(doorPanels); string doorStyleGUID = GUIDUtil.CreateGUID(); string doorStyleElemId = NamingUtil.CreateIFCElementId(familySymbol); typeStyle = IFCInstanceExporter.CreateDoorStyle(file, doorStyleGUID, ownerHistory, objectType, null, null, propertySets, repMapList, doorStyleElemId, GetDoorStyleOperation(doorWindowInfo.DoorOperationType), GetDoorStyleConstruction(familyInstance, constructionType), paramTakesPrecedence, sizeable); break; } case IFCExportType.ExportSystemFurnitureElementType: { string furnitureId = NamingUtil.CreateIFCElementId(familySymbol); typeStyle = IFCInstanceExporter.CreateSystemFurnitureElementType(file, guid, ownerHistory, objectType, null, null, propertySets, repMapList, furnitureId, objectType); break; } case IFCExportType.ExportWindowType: { Toolkit.IFCWindowStyleOperation operationType = DoorWindowUtil.GetIFCWindowStyleOperation(familySymbol); IFCWindowStyleConstruction constructionType = DoorWindowUtil.GetIFCWindowStyleConstruction(familyInstance, ""); IFCAnyHandle windowLining = DoorWindowUtil.CreateWindowLiningProperties(exporterIFC, familyInstance, null); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(windowLining)) propertySets.Add(windowLining); IList<IFCAnyHandle> windowPanels = DoorWindowUtil.CreateWindowPanelProperties(exporterIFC, familyInstance, null); propertySets.UnionWith(windowPanels); string windowStyleGUID = GUIDUtil.CreateGUID(); string windowStyleElemId = NamingUtil.CreateIFCElementId(familySymbol); typeStyle = IFCInstanceExporter.CreateWindowStyle(file, windowStyleGUID, ownerHistory, objectType, null, null, propertySets, repMapList, windowStyleElemId, constructionType, operationType, paramTakesPrecedence, sizeable); break; } case IFCExportType.ExportBuildingElementProxy: default: { if (!IFCAnyHandleUtil.IsNullOrHasNoValue(repMap2dHnd)) typeInfo.Map2DHandle = repMap2dHnd; if (!IFCAnyHandleUtil.IsNullOrHasNoValue(repMap3dHnd)) typeInfo.Map3DHandle = repMap3dHnd; break; } } } if (!IFCAnyHandleUtil.IsNullOrHasNoValue(typeStyle)) { CategoryUtil.CreateMaterialAssociations(doc, exporterIFC, typeStyle, typeInfo.MaterialIds); typeInfo.Style = typeStyle; if (((exportType == IFCExportType.ExportColumnType) && trySpecialColumnCreation) || (exportType == IFCExportType.ExportMemberType)) { typeInfo.ScaledArea = extraParams.ScaledArea; typeInfo.ScaledDepth = extraParams.ScaledLength; typeInfo.ScaledInnerPerimeter = extraParams.ScaledInnerPerimeter; typeInfo.ScaledOuterPerimeter = extraParams.ScaledOuterPerimeter; } ClassificationUtil.CreateUniformatClassification(exporterIFC, file, familySymbol, typeStyle); } } else if (!creatingType && (trySpecialColumnCreation)) { // still need to modify instance trf for columns. trf.Origin += GetLevelOffsetForExtrudedColumns(exporterIFC, familyInstance, overrideLevelId, extraParams); } if (found && !typeInfo.IsValid()) { typeInfo = currentTypeInfo; } // we'll pretend we succeeded, but we'll do nothing. if (!typeInfo.IsValid()) return; // add to the map, as long as we are not using range, not using instance geometry, and don't have extra openings. if ((range == null) && !useInstanceGeometry && (extraParams.GetOpenings().Count == 0)) ExporterCacheManager.TypeObjectsCache.Register(familySymbol.Id, flipped, typeInfo); Transform oldTrf = new Transform(trf); XYZ scaledMapOrigin = XYZ.Zero; trf = trf.Multiply(typeInfo.StyleTransform); // create instance. IList<IFCAnyHandle> shapeReps = new List<IFCAnyHandle>(); { IFCAnyHandle contextOfItems2d = exporterIFC.Get2DContextHandle(); IFCAnyHandle contextOfItems3d = exporterIFC.Get3DContextHandle("Body"); // for proxies, we store the IfcRepresentationMap directly since there is no style. IFCAnyHandle style = typeInfo.Style; IList<IFCAnyHandle> repMapList = !IFCAnyHandleUtil.IsNullOrHasNoValue(style) ? GeometryUtil.GetRepresentationMaps(style) : null; int numReps = repMapList != null ? repMapList.Count : 0; IFCAnyHandle repMap2dHnd = typeInfo.Map2DHandle; IFCAnyHandle repMap3dHnd = typeInfo.Map3DHandle; if (IFCAnyHandleUtil.IsNullOrHasNoValue(repMap3dHnd) && (numReps > 0)) repMap3dHnd = repMapList[0]; if (IFCAnyHandleUtil.IsNullOrHasNoValue(repMap2dHnd) && (numReps > 1)) repMap2dHnd = repMapList[1]; if (!IFCAnyHandleUtil.IsNullOrHasNoValue(repMap3dHnd)) { IList<IFCAnyHandle> representations = new List<IFCAnyHandle>(); representations.Add(ExporterUtil.CreateDefaultMappedItem(file, repMap3dHnd, scaledMapOrigin)); IFCAnyHandle shapeRep = RepresentationUtil.CreateBodyMappedItemRep(exporterIFC, familyInstance, categoryId, contextOfItems3d, representations); if (IFCAnyHandleUtil.IsNullOrHasNoValue(shapeRep)) return; shapeReps.Add(shapeRep); } if (!IFCAnyHandleUtil.IsNullOrHasNoValue(repMap2dHnd)) { HashSet<IFCAnyHandle> representations = new HashSet<IFCAnyHandle>(); representations.Add(ExporterUtil.CreateDefaultMappedItem(file, repMap2dHnd, scaledMapOrigin)); IFCAnyHandle shapeRep = RepresentationUtil.CreatePlanMappedItemRep(exporterIFC, familyInstance, categoryId, contextOfItems2d, representations); if (IFCAnyHandleUtil.IsNullOrHasNoValue(shapeRep)) return; shapeReps.Add(shapeRep); } } IFCAnyHandle boundingBoxRep = null; Transform boundingBoxTrf = (brepOffsetTransform != null) ? brepOffsetTransform.Inverse : Transform.Identity; if (geomObjects.Count > 0) boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geomObjects, boundingBoxTrf); else { boundingBoxTrf = boundingBoxTrf.Multiply(trf.Inverse); boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, familyInstance.get_Geometry(options), boundingBoxTrf); } if (boundingBoxRep != null) shapeReps.Add(boundingBoxRep); IFCAnyHandle rep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, shapeReps); IFCAnyHandle instanceHandle = null; using (IFCPlacementSetter setter = IFCPlacementSetter.Create(exporterIFC, familyInstance, trf, null, overrideLevelId)) { string instanceGUID = GUIDUtil.CreateGUID(familyInstance); string instanceName = NamingUtil.GetIFCName(familyInstance); string instanceDescription = NamingUtil.GetDescriptionOverride(familyInstance, null); string instanceObjectType = NamingUtil.GetObjectTypeOverride(familyInstance, objectType); string instanceElemId = NamingUtil.CreateIFCElementId(familyInstance); IFCAnyHandle localPlacement = setter.GetPlacement(); IFCAnyHandle overrideLocalPlacement = null; if (parentLocalPlacement != null) { Transform relTrf = ExporterIFCUtils.GetRelativeLocalPlacementOffsetTransform(parentLocalPlacement, localPlacement); Transform inverseTrf = relTrf.Inverse; IFCAnyHandle relativePlacement = ExporterUtil.CreateAxis2Placement3D(file, inverseTrf.Origin, inverseTrf.BasisZ, inverseTrf.BasisX); IFCAnyHandle plateLocalPlacement = IFCInstanceExporter.CreateLocalPlacement(file, parentLocalPlacement, relativePlacement); overrideLocalPlacement = plateLocalPlacement; } instanceHandle = FamilyExporterUtil.ExportGenericInstance(exportType, exporterIFC, familyInstance, wrapper, setter, extraParams, instanceGUID, ownerHistory, instanceName, instanceDescription, instanceObjectType, exportParts ? null : rep, instanceElemId, overrideLocalPlacement); if (exportParts) { PartExporter.ExportHostPart(exporterIFC, familyInstance, instanceHandle, familyProductWrapper, setter, setter.GetPlacement(), overrideLevelId); } if (ElementFilteringUtil.IsMEPType(exportType)) ExporterCacheManager.MEPCache.Register(familyInstance, instanceHandle); switch (exportType) { case IFCExportType.ExportColumnType: { IFCAnyHandle placementToUse = localPlacement; if (!useInstanceGeometry) { bool needToCreateOpenings = (cutPairOpeningsForColumns.Count != 0) || OpeningUtil.NeedToCreateOpenings(instanceHandle, extraParams); if (needToCreateOpenings) { Transform openingTrf = new Transform(oldTrf); Transform extraRot = new Transform(oldTrf); extraRot.Origin = XYZ.Zero; openingTrf = openingTrf.Multiply(extraRot); openingTrf = openingTrf.Multiply(typeInfo.StyleTransform); IFCAnyHandle openingRelativePlacement = ExporterUtil.CreateAxis2Placement3D(file, openingTrf.Origin * scale, openingTrf.get_Basis(2), openingTrf.get_Basis(0)); IFCAnyHandle openingPlacement = ExporterUtil.CopyLocalPlacement(file, localPlacement); GeometryUtil.SetRelativePlacement(openingPlacement, openingRelativePlacement); placementToUse = openingPlacement; } } OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, cutPairOpeningsForColumns, exporterIFC, placementToUse, setter, wrapper); OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, extraParams, exporterIFC, placementToUse, setter, wrapper); //export Base Quantities. PropertyUtil.CreateBeamColumnBaseQuantities(exporterIFC, instanceHandle, familyInstance, typeInfo); PropertyUtil.CreateInternalRevitPropertySets(exporterIFC, familyInstance, wrapper); break; } case IFCExportType.ExportDoorType: case IFCExportType.ExportWindowType: { double doorHeight = doorWindowInfo.OpeningHeight; if (doorHeight < MathUtil.Eps()) doorHeight = GetMinSymbolHeight(familySymbol); double doorWidth = doorWindowInfo.OpeningWidth; if (doorWidth < MathUtil.Eps()) doorWidth = GetMinSymbolWidth(familySymbol); double height = doorHeight * scale; double width = doorWidth * scale; if (IFCAnyHandleUtil.IsNullOrHasNoValue(doorWindowInfo.GetLocalPlacement())) doorWindowInfo.SetLocalPlacement(localPlacement); IFCAnyHandle doorWindowOrigLocalPlacement = doorWindowInfo.GetLocalPlacement(); Transform relTrf = ExporterIFCUtils.GetRelativeLocalPlacementOffsetTransform(localPlacement, doorWindowOrigLocalPlacement); IFCAnyHandle doorWindowRelativePlacement = ExporterUtil.CreateAxis2Placement3D(file, relTrf.Origin, relTrf.BasisZ, relTrf.BasisX); IFCAnyHandle doorWindowLocalPlacement = IFCInstanceExporter.CreateLocalPlacement(file, doorWindowOrigLocalPlacement, doorWindowRelativePlacement); if (exportType == IFCExportType.ExportDoorType) instanceHandle = IFCInstanceExporter.CreateDoor(file, instanceGUID, ownerHistory, instanceName, instanceDescription, instanceObjectType, doorWindowLocalPlacement, rep, instanceElemId, height, width); else if (exportType == IFCExportType.ExportWindowType) instanceHandle = IFCInstanceExporter.CreateWindow(file, instanceGUID, ownerHistory, instanceName, instanceDescription, instanceObjectType, doorWindowLocalPlacement, rep, instanceElemId, height, width); wrapper.AddElement(instanceHandle, setter, extraParams, true); exporterIFC.RegisterSpaceBoundingElementHandle(instanceHandle, familyInstance.Id, setter.LevelId); IFCAnyHandle placementToUse = doorWindowLocalPlacement; if (!useInstanceGeometry) { // correct the placement to the symbol space bool needToCreateOpenings = OpeningUtil.NeedToCreateOpenings(instanceHandle, extraParams); if (needToCreateOpenings) { Transform openingTrf = Transform.Identity; openingTrf.Origin = new XYZ(0, 0, setter.Offset); openingTrf = openingTrf.Multiply(doorWindowTrf); XYZ scaledOrigin = openingTrf.Origin * exporterIFC.LinearScale; IFCAnyHandle openingRelativePlacement = ExporterUtil.CreateAxis2Placement3D(file, scaledOrigin, openingTrf.BasisZ, openingTrf.BasisX); IFCAnyHandle openingLocalPlacement = IFCInstanceExporter.CreateLocalPlacement(file, doorWindowLocalPlacement, openingRelativePlacement); placementToUse = openingLocalPlacement; } } // only necessary when exporting as possible breps. OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, extraParams, exporterIFC, placementToUse, setter, wrapper); if (ExporterCacheManager.ExportOptionsCache.ExportBaseQuantities) ExporterIFCUtils.CreateDoorWindowBaseQuantities(exporterIFC, instanceHandle, (doorHeight * scale), (doorWidth * scale)); PropertyUtil.CreateInternalRevitPropertySets(exporterIFC, familyInstance, wrapper); break; } case IFCExportType.ExportMemberType: { OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, extraParams, exporterIFC, localPlacement, setter, wrapper); //export Base Quantities. PropertyUtil.CreateBeamColumnBaseQuantities(exporterIFC, instanceHandle, familyInstance, typeInfo); // TODO: create PropertySet! //createMemberPropertySet(exporter, pFamInst, pWrapper, extraParams); PropertyUtil.CreateInternalRevitPropertySets(exporterIFC, familyInstance, wrapper); break; } case IFCExportType.ExportPlateType: { OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, extraParams, exporterIFC, localPlacement, setter, wrapper); // TODO: create PropertySet! //createPlatePropertySet(exporter, pFamInst, pWrapper, extraParams); PropertyUtil.CreateInternalRevitPropertySets(exporterIFC, familyInstance, wrapper); break; } case IFCExportType.ExportTransportElementType: { IFCAnyHandle localPlacementToUse; ElementId roomId = setter.UpdateRoomRelativeCoordinates(familyInstance, out localPlacementToUse); instanceHandle = IFCInstanceExporter.CreateTransportElement(file, instanceGUID, ownerHistory, instanceName, instanceDescription, instanceObjectType, localPlacementToUse, rep, instanceElemId, null, null, null); if (roomId == ElementId.InvalidElementId) { wrapper.AddElement(instanceHandle, setter, extraParams, true); } else { exporterIFC.RelateSpatialElement(roomId, instanceHandle); wrapper.AddElement(instanceHandle, setter, extraParams, false); } PropertyUtil.CreateInternalRevitPropertySets(exporterIFC, familyInstance, wrapper); break; } case IFCExportType.ExportBuildingElementProxy: default: { bool isBuildingElementProxy = (exportType == IFCExportType.ExportBuildingElementProxy); IFCAnyHandle localPlacementToUse; ElementId roomId = setter.UpdateRoomRelativeCoordinates(familyInstance, out localPlacementToUse); if (!isBuildingElementProxy) { if (FamilyExporterUtil.IsDistributionControlElementSubType(exportType)) { instanceHandle = IFCInstanceExporter.CreateDistributionControlElement(file, instanceGUID, ownerHistory, instanceName, instanceDescription, instanceObjectType, localPlacementToUse, rep, instanceElemId, null); if (roomId == ElementId.InvalidElementId) { wrapper.AddElement(instanceHandle, setter, extraParams, true); } else { exporterIFC.RelateSpatialElement(roomId, instanceHandle); wrapper.AddElement(instanceHandle, setter, extraParams, false); } } else if (IFCAnyHandleUtil.IsNullOrHasNoValue(instanceHandle)) { isBuildingElementProxy = true; } } if (isBuildingElementProxy) { Toolkit.IFCElementComposition proxyType = Toolkit.IFCElementComposition.Element; instanceHandle = IFCInstanceExporter.CreateBuildingElementProxy(file, instanceGUID, ownerHistory, instanceName, instanceDescription, instanceObjectType, localPlacementToUse, rep, instanceElemId, proxyType); if (roomId == ElementId.InvalidElementId) { wrapper.AddElement(instanceHandle, setter, extraParams, true); } else { exporterIFC.RelateSpatialElement(roomId, instanceHandle); wrapper.AddElement(instanceHandle, setter, extraParams, false); } } IFCAnyHandle placementToUse = localPlacement; if (!useInstanceGeometry) { bool needToCreateOpenings = OpeningUtil.NeedToCreateOpenings(instanceHandle, extraParams); if (needToCreateOpenings) { Transform openingTrf = new Transform(oldTrf); Transform extraRot = new Transform(oldTrf); extraRot.Origin = XYZ.Zero; openingTrf = openingTrf.Multiply(extraRot); openingTrf = openingTrf.Multiply(typeInfo.StyleTransform); IFCAnyHandle openingRelativePlacement = ExporterUtil.CreateAxis2Placement3D(file, openingTrf.Origin * scale, openingTrf.get_Basis(2), openingTrf.get_Basis(0)); IFCAnyHandle openingPlacement = ExporterUtil.CopyLocalPlacement(file, localPlacement); GeometryUtil.SetRelativePlacement(openingPlacement, openingRelativePlacement); placementToUse = openingPlacement; } } OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, extraParams, exporterIFC, placementToUse, setter, wrapper); PropertyUtil.CreateInternalRevitPropertySets(exporterIFC, familyInstance, wrapper); break; } } if (!IFCAnyHandleUtil.IsNullOrHasNoValue(instanceHandle)) { if (doorWindowInfo != null) { if (!IFCAnyHandleUtil.IsNullOrHasNoValue(doorWindowInfo.GetOpening())) { string relGUID = GUIDUtil.CreateGUID(); IFCInstanceExporter.CreateRelFillsElement(file, relGUID, ownerHistory, null, null, doorWindowInfo.GetOpening(), instanceHandle); } else if (doorWindowInfo.NeedsOpening) { bool added = doorWindowInfo.SetDelayedFamilyInstance(instanceHandle, localPlacement, doorWindowInfo.AssignedLevelId); if (added) exporterIFC.RegisterDoorWindowForOpeningUpdate(doorWindowInfo); else { // we need to fill a later opening. exporterIFC.RegisterDoorWindowForUncreatedOpening(familyInstance.Id, instanceHandle); } } } if (!exportParts) CategoryUtil.CreateMaterialAssociations(doc, exporterIFC, instanceHandle, typeInfo.MaterialIds); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(typeInfo.Style)) ExporterCacheManager.TypeRelationsCache.Add(typeInfo.Style, instanceHandle); } } } }
void commonInit(ExporterIFC exporterIFC, Element elem, Transform familyTrf, Transform orientationTrf, ElementId overrideLevelId) { m_ExporterIFC = exporterIFC; overrideLevelId = overrideLevelId != null ? overrideLevelId : ElementId.InvalidElementId; Document doc = elem.Document; Element hostElem = elem; ElementId elemId = elem.Id; ElementId newLevelId = overrideLevelId; bool useOverrideOrigin = false; XYZ overrideOrigin = XYZ.Zero; IDictionary <ElementId, IFCLevelInfo> levelInfos = exporterIFC.GetLevelInfos(); if (overrideLevelId == ElementId.InvalidElementId) { if (familyTrf == null) { // Override for CurveElems -- base level calculation on origin of sketch Plane. if (elem is CurveElement) { SketchPlane sketchPlane = (elem as CurveElement).SketchPlane; if (sketchPlane != null) { useOverrideOrigin = true; overrideOrigin = sketchPlane.GetPlane().Origin; } } else { ElementId hostElemId = ElementId.InvalidElementId; // a bit of a hack. If we have a railing, we want it to have the same level base as its host Stair (because of // the way the stairs place railings and stair flights together). if (elem is Railing) { hostElemId = (elem as Railing).HostId; } else if (elem.Category.Id.IntegerValue == (int)BuiltInCategory.OST_Assemblies) { hostElemId = elem.AssemblyInstanceId; } if (hostElemId != ElementId.InvalidElementId) { hostElem = doc.GetElement(hostElemId); } newLevelId = hostElem != null ? hostElem.LevelId : ElementId.InvalidElementId; if (newLevelId == ElementId.InvalidElementId) { ExporterIFCUtils.GetLevelIdByHeight(exporterIFC, hostElem); } } } // todo: store. double bottomHeight = double.MaxValue; ElementId bottomLevelId = ElementId.InvalidElementId; if ((newLevelId == ElementId.InvalidElementId) || orientationTrf != null) { // if we have a trf, it might geometrically push the instance to a new level. Check that case. // actually, we should ALWAYS check the bbox vs the settings newLevelId = ElementId.InvalidElementId; XYZ originToUse = XYZ.Zero; bool originIsValid = useOverrideOrigin; if (useOverrideOrigin) { originToUse = overrideOrigin; } else { BoundingBoxXYZ bbox = elem.get_BoundingBox(null); if (bbox != null) { originToUse = bbox.Min; originIsValid = true; } else if (hostElem.Id != elemId) { bbox = hostElem.get_BoundingBox(null); if (bbox != null) { originToUse = bbox.Min; originIsValid = true; } } } // The original heuristic here was that the origin determined the level containment based on exact location: // if the Z of the origin was higher than the current level but lower than the next level, it was contained // on that level. // However, in some places (e.g. Germany), the containment is thought to start just below the level, because floors // are placed before the level, not above. So we have made a small modification so that anything within // 10cm of the 'next' level is on that level. double leveExtension = 10.0 / (12.0 * 2.54); foreach (KeyValuePair <ElementId, IFCLevelInfo> levelInfoPair in levelInfos) { // the cache contains levels from all the exported documents // if the export is performed for a linked document, filter the levels that are not from this document if (ExporterCacheManager.ExportOptionsCache.ExportingLink) { Element levelElem = doc.GetElement(levelInfoPair.Key); if (levelElem == null || !(levelElem is Level)) { continue; } } IFCLevelInfo levelInfo = levelInfoPair.Value; double startHeight = levelInfo.Elevation - leveExtension; double height = levelInfo.DistanceToNextLevel; bool useHeight = !MathUtil.IsAlmostZero(height); double endHeight = startHeight + height; if (originIsValid && ((originToUse[2] > (startHeight - MathUtil.Eps())) && (!useHeight || originToUse[2] < (endHeight - MathUtil.Eps())))) { newLevelId = levelInfoPair.Key; } if (startHeight < (bottomHeight + MathUtil.Eps())) { bottomLevelId = levelInfoPair.Key; bottomHeight = startHeight; } } } if (newLevelId == ElementId.InvalidElementId) { newLevelId = bottomLevelId; } } m_LevelInfo = exporterIFC.GetLevelInfo(newLevelId); if (m_LevelInfo == null) { foreach (KeyValuePair <ElementId, IFCLevelInfo> levelInfoPair in levelInfos) { // the cache contains levels from all the exported documents // if the export is performed for a linked document, filter the levels that are not from this document if (ExporterCacheManager.ExportOptionsCache.ExportingLink) { Element levelElem = doc.GetElement(levelInfoPair.Key); if (levelElem == null || !(levelElem is Level)) { continue; } } m_LevelInfo = levelInfoPair.Value; break; } //m_LevelInfo = levelInfos.Values.First<IFCLevelInfo>(); } double elevation = m_LevelInfo.Elevation; IFCAnyHandle levelPlacement = m_LevelInfo.GetLocalPlacement(); IFCFile file = exporterIFC.GetFile(); Transform trf = Transform.Identity; if (familyTrf != null) { XYZ origin, xDir, yDir, zDir; xDir = familyTrf.BasisX; yDir = familyTrf.BasisY; zDir = familyTrf.BasisZ; Transform origOffsetTrf = Transform.Identity; XYZ negLevelOrigin = new XYZ(0, 0, -elevation); origOffsetTrf.Origin = negLevelOrigin; Transform newTrf = origOffsetTrf * familyTrf; origin = newTrf.Origin; trf.BasisX = xDir; trf.BasisY = yDir; trf.BasisZ = zDir; trf = trf.Inverse; origin = UnitUtil.ScaleLength(origin); m_LocalPlacement = ExporterUtil.CreateLocalPlacement(file, levelPlacement, origin, zDir, xDir); } else if (orientationTrf != null) { XYZ origin, xDir, yDir, zDir; xDir = orientationTrf.BasisX; yDir = orientationTrf.BasisY; zDir = orientationTrf.BasisZ; origin = orientationTrf.Origin; XYZ levelOrigin = new XYZ(0, 0, elevation); origin = origin - levelOrigin; trf.BasisX = xDir; trf.BasisY = yDir; trf.BasisZ = zDir; trf.Origin = origin; trf = trf.Inverse; origin = UnitUtil.ScaleLength(origin); m_LocalPlacement = ExporterUtil.CreateLocalPlacement(file, levelPlacement, origin, zDir, xDir); } else { m_LocalPlacement = ExporterUtil.CreateLocalPlacement(file, levelPlacement, null, null, null); } Transform origOffsetTrf2 = Transform.Identity; XYZ negLevelOrigin2 = new XYZ(0, 0, -elevation); origOffsetTrf2.Origin = negLevelOrigin2; Transform newTrf2 = trf * origOffsetTrf2; m_ExporterIFC.PushTransform(newTrf2); m_Offset = elevation; m_LevelId = newLevelId; }
/// <summary> /// Exports spatial elements, including rooms, areas and spaces. 1st level space boundaries. /// </summary> /// <param name="exporterIFC"> /// The ExporterIFC object. /// </param> /// <param name="spatialElement"> /// The spatial element. /// </param> /// <param name="productWrapper"> /// The ProductWrapper. /// </param> public static void ExportSpatialElement(ExporterIFC exporterIFC, SpatialElement spatialElement, ProductWrapper productWrapper) { IFCFile file = exporterIFC.GetFile(); using (IFCTransaction transaction = new IFCTransaction(file)) { using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, spatialElement, null, null)) { SpatialElementGeometryResults spatialElemGeomResult = null; if (!CreateIFCSpace(exporterIFC, spatialElement, productWrapper, setter, out spatialElemGeomResult)) return; bool isArea = (spatialElement is Area); // Do not create boundary information for areas. if (!isArea && (ExporterCacheManager.ExportOptionsCache.SpaceBoundaryLevel == 1)) { Document document = spatialElement.Document; ElementId levelId = spatialElement.LevelId; IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(levelId); double baseHeightNonScaled = (levelInfo != null) ? levelInfo.Elevation : 0.0; try { // This can throw an exception. If it does, continue to export element without boundary information. // We will re-use the previously generated value, if we have it. // TODO: warn user. if (spatialElemGeomResult == null) spatialElemGeomResult = s_SpatialElementGeometryCalculator.CalculateSpatialElementGeometry(spatialElement); Solid spatialElemGeomSolid = spatialElemGeomResult.GetGeometry(); FaceArray faces = spatialElemGeomSolid.Faces; foreach (Face face in faces) { IList<SpatialElementBoundarySubface> spatialElemBoundarySubfaces = spatialElemGeomResult.GetBoundaryFaceInfo(face); foreach (SpatialElementBoundarySubface spatialElemBSubface in spatialElemBoundarySubfaces) { if (spatialElemBSubface.SubfaceType == SubfaceType.Side) continue; if (spatialElemBSubface.GetSubface() == null) continue; ElementId elemId = spatialElemBSubface.SpatialBoundaryElement.LinkInstanceId; if (elemId == ElementId.InvalidElementId) { elemId = spatialElemBSubface.SpatialBoundaryElement.HostElementId; } Element boundingElement = document.GetElement(elemId); if (boundingElement == null) continue; bool isObjectExt = CategoryUtil.IsElementExternal(boundingElement); IFCGeometryInfo info = IFCGeometryInfo.CreateSurfaceGeometryInfo(spatialElement.Document.Application.VertexTolerance); Face subFace = spatialElemBSubface.GetSubface(); ExporterIFCUtils.CollectGeometryInfo(exporterIFC, info, subFace, XYZ.Zero, false); foreach (IFCAnyHandle surfaceHnd in info.GetSurfaces()) { IFCAnyHandle connectionGeometry = IFCInstanceExporter.CreateConnectionSurfaceGeometry(file, surfaceHnd, null); SpaceBoundary spaceBoundary = new SpaceBoundary(spatialElement.Id, boundingElement.Id, setter.LevelId, connectionGeometry, IFCPhysicalOrVirtual.Physical, isObjectExt ? IFCInternalOrExternal.External : IFCInternalOrExternal.Internal); if (!ProcessIFCSpaceBoundary(exporterIFC, spaceBoundary, file)) ExporterCacheManager.SpaceBoundaryCache.Add(spaceBoundary); } } } } catch { } IList<IList<BoundarySegment>> roomBoundaries = spatialElement.GetBoundarySegments(GetSpatialElementBoundaryOptions(spatialElement)); double scaledRoomHeight = GetScaledHeight(spatialElement, levelId, levelInfo); double unscaledHeight = UnitUtil.UnscaleLength(scaledRoomHeight); Plane xyPlane = new Plane(XYZ.BasisZ, XYZ.Zero); foreach (IList<BoundarySegment> roomBoundaryList in roomBoundaries) { foreach (BoundarySegment roomBoundary in roomBoundaryList) { Element boundingElement = roomBoundary.Element; if (boundingElement == null) continue; ElementId buildingElemId = boundingElement.Id; Curve trimmedCurve = roomBoundary.Curve; if (trimmedCurve == null) continue; //trimmedCurve.Visibility = Visibility.Visible; readonly IFCAnyHandle connectionGeometry = ExtrusionExporter.CreateConnectionSurfaceGeometry( exporterIFC, trimmedCurve, xyPlane, scaledRoomHeight, baseHeightNonScaled); IFCPhysicalOrVirtual physOrVirt = IFCPhysicalOrVirtual.Physical; if (boundingElement is CurveElement) physOrVirt = IFCPhysicalOrVirtual.Virtual; else if (boundingElement is Autodesk.Revit.DB.Architecture.Room) physOrVirt = IFCPhysicalOrVirtual.NotDefined; bool isObjectExt = CategoryUtil.IsElementExternal(boundingElement); bool isObjectPhys = (physOrVirt == IFCPhysicalOrVirtual.Physical); ElementId actualBuildingElemId = isObjectPhys ? buildingElemId : ElementId.InvalidElementId; SpaceBoundary spaceBoundary = new SpaceBoundary(spatialElement.Id, actualBuildingElemId, setter.LevelId, !IFCAnyHandleUtil.IsNullOrHasNoValue(connectionGeometry) ? connectionGeometry : null, physOrVirt, isObjectExt ? IFCInternalOrExternal.External : IFCInternalOrExternal.Internal); if (!ProcessIFCSpaceBoundary(exporterIFC, spaceBoundary, file)) ExporterCacheManager.SpaceBoundaryCache.Add(spaceBoundary); // try to add doors and windows for host objects if appropriate. if (isObjectPhys && boundingElement is HostObject) { HostObject hostObj = boundingElement as HostObject; HashSet<ElementId> elemIds = new HashSet<ElementId>(); elemIds.UnionWith(hostObj.FindInserts(false, false, false, false)); if (elemIds.Count == 0) { CurtainGridSet curtainGridSet = CurtainSystemExporter.GetCurtainGridSet(hostObj); if (curtainGridSet != null) { foreach (CurtainGrid curtainGrid in curtainGridSet) elemIds.UnionWith(CurtainSystemExporter.GetVisiblePanelsForGrid(curtainGrid)); } } foreach (ElementId elemId in elemIds) { // we are going to do a simple bbox export, not complicated geometry. Element instElem = document.GetElement(elemId); if (instElem == null) continue; BoundingBoxXYZ instBBox = instElem.get_BoundingBox(null); if (instBBox == null) continue; // make copy of original trimmed curve. Curve instCurve = trimmedCurve.Clone(); XYZ instOrig = instCurve.GetEndPoint(0); // make sure that the insert is on this level. if (instBBox.Max.Z < instOrig.Z) continue; if (instBBox.Min.Z > instOrig.Z + unscaledHeight) continue; double insHeight = Math.Min(instBBox.Max.Z, instOrig.Z + unscaledHeight) - Math.Max(instOrig.Z, instBBox.Min.Z); if (insHeight < (1.0 / (12.0 * 16.0))) continue; // move base curve to bottom of bbox. XYZ moveDir = new XYZ(0.0, 0.0, instBBox.Min.Z - instOrig.Z); Transform moveTrf = Transform.CreateTranslation(moveDir); instCurve = instCurve.CreateTransformed(moveTrf); bool isHorizOrVert = false; if (instCurve is Line) { Line instLine = instCurve as Line; XYZ lineDir = instLine.Direction; if (MathUtil.IsAlmostEqual(Math.Abs(lineDir.X), 1.0) || (MathUtil.IsAlmostEqual(Math.Abs(lineDir.Y), 1.0))) isHorizOrVert = true; } double[] parameters = new double[2]; double[] origEndParams = new double[2]; bool paramsSet = false; if (!isHorizOrVert) { FamilyInstance famInst = instElem as FamilyInstance; if (famInst == null) continue; ElementType elementType = document.GetElement(famInst.GetTypeId()) as ElementType; if (elementType == null) continue; BoundingBoxXYZ symBBox = elementType.get_BoundingBox(null); if (symBBox != null) { Curve symCurve = trimmedCurve.Clone(); Transform trf = famInst.GetTransform(); Transform invTrf = trf.Inverse; Curve trfCurve = symCurve.CreateTransformed(invTrf); parameters[0] = trfCurve.Project(symBBox.Min).Parameter; parameters[1] = trfCurve.Project(symBBox.Max).Parameter; paramsSet = true; } } if (!paramsSet) { parameters[0] = instCurve.Project(instBBox.Min).Parameter; parameters[1] = instCurve.Project(instBBox.Max).Parameter; } // ignore if less than 1/16". if (Math.Abs(parameters[1] - parameters[0]) < 1.0 / (12.0 * 16.0)) continue; if (parameters[0] > parameters[1]) { //swap double tempParam = parameters[0]; parameters[0] = parameters[1]; parameters[1] = tempParam; } origEndParams[0] = instCurve.GetEndParameter(0); origEndParams[1] = instCurve.GetEndParameter(1); if (origEndParams[0] > parameters[1] - (1.0 / (12.0 * 16.0))) continue; if (origEndParams[1] < parameters[0] + (1.0 / (12.0 * 16.0))) continue; instCurve.MakeBound(parameters[0] > origEndParams[0] ? parameters[0] : origEndParams[0], parameters[1] < origEndParams[1] ? parameters[1] : origEndParams[1]); double insHeightScaled = UnitUtil.ScaleLength(insHeight); IFCAnyHandle insConnectionGeom = ExtrusionExporter.CreateConnectionSurfaceGeometry(exporterIFC, instCurve, xyPlane, insHeightScaled, baseHeightNonScaled); SpaceBoundary instBoundary = new SpaceBoundary(spatialElement.Id, elemId, setter.LevelId, !IFCAnyHandleUtil.IsNullOrHasNoValue(insConnectionGeom) ? insConnectionGeom : null, physOrVirt, isObjectExt ? IFCInternalOrExternal.External : IFCInternalOrExternal.Internal); if (!ProcessIFCSpaceBoundary(exporterIFC, instBoundary, file)) ExporterCacheManager.SpaceBoundaryCache.Add(instBoundary); } } } } } CreateZoneInfos(exporterIFC, file, spatialElement, productWrapper); CreateSpaceOccupantInfo(exporterIFC, file, spatialElement, productWrapper); } transaction.Commit(); } }
/// <summary> /// Creates IFC room/space/area item, not include boundaries. /// </summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="spatialElement">The spatial element.</param> /// <param name="productWrapper">The ProductWrapper.</param> /// <param name="setter">The PlacementSetter.</param> /// <returns>True if created successfully, false otherwise.</returns> static bool CreateIFCSpace(ExporterIFC exporterIFC, SpatialElement spatialElement, ProductWrapper productWrapper, PlacementSetter setter, out SpatialElementGeometryResults results) { results = null; IList<CurveLoop> curveLoops = null; try { // Avoid throwing for a spatial element with no location. if (spatialElement.Location == null) return false; SpatialElementBoundaryOptions options = GetSpatialElementBoundaryOptions(spatialElement); curveLoops = ExporterIFCUtils.GetRoomBoundaryAsCurveLoopArray(spatialElement, options, true); } catch (Autodesk.Revit.Exceptions.InvalidOperationException) { //Some spatial elements are not placed that have no boundary loops. Don't export them. return false; } Autodesk.Revit.DB.Document document = spatialElement.Document; ElementId levelId = spatialElement.LevelId; ElementId catId = spatialElement.Category != null ? spatialElement.Category.Id : ElementId.InvalidElementId; double dArea = 0.0; if (ParameterUtil.GetDoubleValueFromElement(spatialElement, BuiltInParameter.ROOM_AREA, out dArea) != null) dArea = UnitUtil.ScaleArea(dArea); IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(levelId); string strSpaceNumber = null; string strSpaceName = null; string strSpaceDesc = null; if (ParameterUtil.GetStringValueFromElement(spatialElement, BuiltInParameter.ROOM_NUMBER, out strSpaceNumber) == null) strSpaceNumber = null; if (ParameterUtil.GetStringValueFromElement(spatialElement, BuiltInParameter.ROOM_NAME, out strSpaceName) == null) strSpaceName = null; if (ParameterUtil.GetStringValueFromElement(spatialElement, BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS, out strSpaceDesc) == null) strSpaceDesc = null; string name = strSpaceNumber; string longName = strSpaceName; string desc = strSpaceDesc; IFCFile file = exporterIFC.GetFile(); IFCAnyHandle localPlacement = setter.LocalPlacement; ElementType elemType = document.GetElement(spatialElement.GetTypeId()) as ElementType; IFCInternalOrExternal internalOrExternal = CategoryUtil.IsElementExternal(spatialElement) ? IFCInternalOrExternal.External : IFCInternalOrExternal.Internal; double scaledRoomHeight = GetScaledHeight(spatialElement, levelId, levelInfo); if (scaledRoomHeight <= 0.0) return false; double bottomOffset; ParameterUtil.GetDoubleValueFromElement(spatialElement, BuiltInParameter.ROOM_LOWER_OFFSET, out bottomOffset); double elevation = (levelInfo != null) ? levelInfo.Elevation : 0.0; XYZ zDir = new XYZ(0, 0, 1); XYZ orig = new XYZ(0, 0, elevation + bottomOffset); Plane plane = new Plane(zDir, orig); // room calculated as level offset. GeometryElement geomElem = null; bool isArea = (spatialElement is Area); Area spatialElementAsArea = isArea ? (spatialElement as Area) : null; if (spatialElement is Autodesk.Revit.DB.Architecture.Room) { Autodesk.Revit.DB.Architecture.Room room = spatialElement as Autodesk.Revit.DB.Architecture.Room; geomElem = room.ClosedShell; } else if (spatialElement is Autodesk.Revit.DB.Mechanical.Space) { Autodesk.Revit.DB.Mechanical.Space space = spatialElement as Autodesk.Revit.DB.Mechanical.Space; geomElem = space.ClosedShell; } else if (isArea) { Options geomOptions = GeometryUtil.GetIFCExportGeometryOptions(); geomElem = spatialElementAsArea.get_Geometry(geomOptions); } IFCAnyHandle spaceHnd = null; string spatialElementName = null; using (IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData()) { extraParams.SetLocalPlacement(localPlacement); extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ; using (IFCTransaction transaction2 = new IFCTransaction(file)) { IFCAnyHandle repHnd = null; if (!ExporterCacheManager.ExportOptionsCache.Use2DRoomBoundaryForRoomVolumeCreation && geomElem != null) { BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true); bodyExporterOptions.TessellationLevel = BodyExporter.GetTessellationLevel(); repHnd = RepresentationUtil.CreateAppropriateProductDefinitionShape(exporterIFC, spatialElement, catId, geomElem, bodyExporterOptions, null, extraParams, false); if (IFCAnyHandleUtil.IsNullOrHasNoValue(repHnd)) extraParams.ClearOpenings(); } else { IFCAnyHandle shapeRep = ExtrusionExporter.CreateExtrudedSolidFromCurveLoop(exporterIFC, null, curveLoops, plane, zDir, scaledRoomHeight); if (IFCAnyHandleUtil.IsNullOrHasNoValue(shapeRep)) return false; IFCAnyHandle styledItemHnd = BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, document, shapeRep, ElementId.InvalidElementId); HashSet<IFCAnyHandle> bodyItems = new HashSet<IFCAnyHandle>(); bodyItems.Add(shapeRep); shapeRep = RepresentationUtil.CreateSweptSolidRep(exporterIFC, spatialElement, catId, exporterIFC.Get3DContextHandle("Body"), bodyItems, null); IList<IFCAnyHandle> shapeReps = new List<IFCAnyHandle>(); shapeReps.Add(shapeRep); IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geomElem, Transform.Identity); if (boundingBoxRep != null) shapeReps.Add(boundingBoxRep); repHnd = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, shapeReps); } extraParams.ScaledHeight = scaledRoomHeight; extraParams.ScaledArea = dArea; spatialElementName = NamingUtil.GetNameOverride(spatialElement, name); string spatialElementDescription = NamingUtil.GetDescriptionOverride(spatialElement, desc); string spatialElementObjectType = NamingUtil.GetObjectTypeOverride(spatialElement, null); string spatialElementLongName = NamingUtil.GetLongNameOverride(spatialElement, longName); double? spaceElevationWithFlooring = null; double elevationWithFlooring = 0.0; if (ParameterUtil.GetDoubleValueFromElement(spatialElement, null, "IfcElevationWithFlooring", out elevationWithFlooring) != null) spaceElevationWithFlooring = UnitUtil.ScaleLength(elevationWithFlooring); spaceHnd = IFCInstanceExporter.CreateSpace(file, GUIDUtil.CreateGUID(spatialElement), ExporterCacheManager.OwnerHistoryHandle, spatialElementName, spatialElementDescription, spatialElementObjectType, extraParams.GetLocalPlacement(), repHnd, spatialElementLongName, Toolkit.IFCElementComposition.Element, internalOrExternal, spaceElevationWithFlooring); transaction2.Commit(); } if (spaceHnd != null) { productWrapper.AddSpace(spatialElement, spaceHnd, levelInfo, extraParams, true); if (isArea) { Element areaScheme = spatialElementAsArea.AreaScheme; if (areaScheme != null) { ElementId areaSchemeId = areaScheme.Id; HashSet<IFCAnyHandle> areas = null; if (!ExporterCacheManager.AreaSchemeCache.TryGetValue(areaSchemeId, out areas)) { areas = new HashSet<IFCAnyHandle>(); ExporterCacheManager.AreaSchemeCache[areaSchemeId] = areas; } areas.Add(spaceHnd); } } } } // Save room handle for later use/relationships ExporterCacheManager.SpaceInfoCache.SetSpaceHandle(spatialElement, spaceHnd); // Find Ceiling as a Space boundary and keep the relationship in a cache for use later bool ret = GetCeilingSpaceBoundary(spatialElement, out results); if (!MathUtil.IsAlmostZero(dArea) && !(ExporterCacheManager.ExportOptionsCache.ExportAsCOBIE) && !ExporterCacheManager.ExportOptionsCache.ExportAs2x3CoordinationView2 && !ExporterCacheManager.ExportOptionsCache.ExportBaseQuantities) { bool isDesignGrossArea = (string.Compare(spatialElementName, "GSA Design Gross Area") > 0); PropertyUtil.CreatePreCOBIEGSAQuantities(exporterIFC, spaceHnd, "GSA Space Areas", (isDesignGrossArea ? "GSA Design Gross Area" : "GSA BIM Area"), dArea); } // Export Classifications for SpatialElement for GSA/COBIE. if (ExporterCacheManager.ExportOptionsCache.ExportAsCOBIE) { ProjectInfo projectInfo = document.ProjectInformation; if (projectInfo != null) CreateCOBIESpaceClassifications(exporterIFC, file, spaceHnd, projectInfo, spatialElement); } return true; }
/// <summary> /// Attempt to determine the local placement of the element based on the element type and initial input. /// </summary> /// <param name="exporterIFC">The ExporterIFC class.</param> /// <param name="elem">The element being exported.</param> /// <param name="familyTrf">The optional family transform.</param> /// <param name="orientationTrf">The optional orientation of the element based on IFC standards or agreements.</param> /// <param name="overrideLevelId">The optional level to place the element, to be used instead of heuristics.</param> private void commonInit(ExporterIFC exporterIFC, Element elem, Transform familyTrf, Transform orientationTrf, ElementId overrideLevelId) { ExporterIFC = exporterIFC; // Convert null value to InvalidElementId. if (overrideLevelId == null) overrideLevelId = ElementId.InvalidElementId; Document doc = elem.Document; Element hostElem = elem; ElementId elemId = elem.Id; ElementId newLevelId = overrideLevelId; bool useOverrideOrigin = false; XYZ overrideOrigin = XYZ.Zero; IDictionary<ElementId, IFCLevelInfo> levelInfos = exporterIFC.GetLevelInfos(); if (overrideLevelId == ElementId.InvalidElementId) { if (familyTrf == null) { // Override for CurveElems -- base level calculation on origin of sketch Plane. if (elem is CurveElement) { SketchPlane sketchPlane = (elem as CurveElement).SketchPlane; if (sketchPlane != null) { useOverrideOrigin = true; overrideOrigin = sketchPlane.GetPlane().Origin; } } else { ElementId hostElemId = ElementId.InvalidElementId; // a bit of a hack. If we have a railing, we want it to have the same level base as its host Stair (because of // the way the stairs place railings and stair flights together). if (elem is Railing) { hostElemId = (elem as Railing).HostId; } else if (elem.Category.Id.IntegerValue == (int)BuiltInCategory.OST_Assemblies) { hostElemId = elem.AssemblyInstanceId; } if (hostElemId != ElementId.InvalidElementId) { hostElem = doc.GetElement(hostElemId); } newLevelId = hostElem != null ? hostElem.LevelId : ElementId.InvalidElementId; if (newLevelId == ElementId.InvalidElementId) { ExporterIFCUtils.GetLevelIdByHeight(exporterIFC, hostElem); } } } // todo: store. double bottomHeight = double.MaxValue; ElementId bottomLevelId = ElementId.InvalidElementId; if ((newLevelId == ElementId.InvalidElementId) || orientationTrf != null) { // if we have a trf, it might geometrically push the instance to a new level. Check that case. // actually, we should ALWAYS check the bbox vs the settings newLevelId = ElementId.InvalidElementId; XYZ originToUse = XYZ.Zero; bool originIsValid = useOverrideOrigin; if (useOverrideOrigin) { originToUse = overrideOrigin; } else { BoundingBoxXYZ bbox = elem.get_BoundingBox(null); if (bbox != null) { originToUse = bbox.Min; originIsValid = true; } else if (hostElem.Id != elemId) { bbox = hostElem.get_BoundingBox(null); if (bbox != null) { originToUse = bbox.Min; originIsValid = true; } } } // The original heuristic here was that the origin determined the level containment based on exact location: // if the Z of the origin was higher than the current level but lower than the next level, it was contained // on that level. // However, in some places (e.g. Germany), the containment is thought to start just below the level, because floors // are placed before the level, not above. So we have made a small modification so that anything within // 10cm of the 'next' level is on that level. double leveExtension = 10.0 / (12.0 * 2.54); foreach (KeyValuePair<ElementId, IFCLevelInfo> levelInfoPair in levelInfos) { // the cache contains levels from all the exported documents // if the export is performed for a linked document, filter the levels that are not from this document if (ExporterCacheManager.ExportOptionsCache.ExportingLink) { Element levelElem = doc.GetElement(levelInfoPair.Key); if (levelElem == null || !(levelElem is Level)) continue; } IFCLevelInfo levelInfo = levelInfoPair.Value; double startHeight = levelInfo.Elevation - leveExtension; double height = levelInfo.DistanceToNextLevel; bool useHeight = !MathUtil.IsAlmostZero(height); double endHeight = startHeight + height; if (originIsValid && ((originToUse[2] > (startHeight - MathUtil.Eps())) && (!useHeight || originToUse[2] < (endHeight - MathUtil.Eps())))) { newLevelId = levelInfoPair.Key; } if (startHeight < (bottomHeight + MathUtil.Eps())) { bottomLevelId = levelInfoPair.Key; bottomHeight = startHeight; } } } if (newLevelId == ElementId.InvalidElementId) newLevelId = bottomLevelId; } LevelInfo = exporterIFC.GetLevelInfo(newLevelId); if (LevelInfo == null) { foreach (KeyValuePair<ElementId, IFCLevelInfo> levelInfoPair in levelInfos) { // the cache contains levels from all the exported documents // if the export is performed for a linked document, filter the levels that are not from this document if (ExporterCacheManager.ExportOptionsCache.ExportingLink) { Element levelElem = doc.GetElement(levelInfoPair.Key); if (levelElem == null || !(levelElem is Level)) continue; } LevelInfo = levelInfoPair.Value; break; } //LevelInfo = levelInfos.Values.First<IFCLevelInfo>(); } double elevation = (LevelInfo != null) ? LevelInfo.Elevation : 0.0; IFCAnyHandle levelPlacement = (LevelInfo != null) ? LevelInfo.GetLocalPlacement() : null; IFCFile file = exporterIFC.GetFile(); Transform trf = Transform.Identity; if (familyTrf != null) { XYZ origin, xDir, yDir, zDir; xDir = familyTrf.BasisX; yDir = familyTrf.BasisY; zDir = familyTrf.BasisZ; Transform origOffsetTrf = Transform.Identity; XYZ negLevelOrigin = new XYZ(0, 0, -elevation); origOffsetTrf.Origin = negLevelOrigin; Transform newTrf = origOffsetTrf * familyTrf; origin = newTrf.Origin; trf.BasisX = xDir; trf.BasisY = yDir; trf.BasisZ = zDir; trf = trf.Inverse; origin = UnitUtil.ScaleLength(origin); LocalPlacement = ExporterUtil.CreateLocalPlacement(file, levelPlacement, origin, zDir, xDir); } else if (orientationTrf != null) { XYZ origin, xDir, yDir, zDir; xDir = orientationTrf.BasisX; yDir = orientationTrf.BasisY; zDir = orientationTrf.BasisZ; origin = orientationTrf.Origin; XYZ levelOrigin = new XYZ(0, 0, elevation); origin = origin - levelOrigin; trf.BasisX = xDir; trf.BasisY = yDir; trf.BasisZ = zDir; trf.Origin = origin; trf = trf.Inverse; origin = UnitUtil.ScaleLength(origin); LocalPlacement = ExporterUtil.CreateLocalPlacement(file, levelPlacement, origin, zDir, xDir); } else { LocalPlacement = ExporterUtil.CreateLocalPlacement(file, levelPlacement, null, null, null); } Transform origOffsetTrf2 = Transform.Identity; XYZ negLevelOrigin2 = new XYZ(0, 0, -elevation); origOffsetTrf2.Origin = negLevelOrigin2; Transform newTrf2 = trf * origOffsetTrf2; ExporterIFC.PushTransform(newTrf2); Offset = elevation; LevelId = newLevelId; }
/// <summary> /// Creates IFC room/space/area item, not include boundaries. /// </summary> /// <param name="exporterIFC"> /// The ExporterIFC object. /// </param> /// <param name="spatialElement"> /// The spatial element. /// </param> /// <param name="productWrapper"> /// The ProductWrapper. /// </param> /// <param name="setter"> /// The IFCPlacementSetter. /// </param> /// <returns> /// True if created successfully, false otherwise. /// </returns> static bool CreateIFCSpace(ExporterIFC exporterIFC, SpatialElement spatialElement, ProductWrapper productWrapper, IFCPlacementSetter setter) { IList<CurveLoop> curveLoops = null; try { SpatialElementBoundaryOptions options = ExporterIFCUtils.GetSpatialElementBoundaryOptions(exporterIFC, spatialElement); curveLoops = ExporterIFCUtils.GetRoomBoundaryAsCurveLoopArray(spatialElement, options, true); } catch (Autodesk.Revit.Exceptions.InvalidOperationException) { //Some spatial elements are not placed that have no boundary loops. Don't export them. return false; } Autodesk.Revit.DB.Document document = spatialElement.Document; ElementId levelId = spatialElement.Level != null ? spatialElement.Level.Id : ElementId.InvalidElementId; double scale = exporterIFC.LinearScale; ElementId catId = spatialElement.Category != null ? spatialElement.Category.Id : ElementId.InvalidElementId; double dArea = 0.0; if (ParameterUtil.GetDoubleValueFromElement(spatialElement, BuiltInParameter.ROOM_AREA, out dArea)) dArea *= (scale * scale); IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(levelId); string strSpaceNumber = null; string strSpaceName = null; string strSpaceDesc = null; bool isArea = spatialElement is Area; if (!isArea) { if (!ParameterUtil.GetStringValueFromElement(spatialElement, BuiltInParameter.ROOM_NUMBER, out strSpaceNumber)) strSpaceNumber = null; if (!ParameterUtil.GetStringValueFromElement(spatialElement, BuiltInParameter.ROOM_NAME, out strSpaceName)) strSpaceName = null; if (!ParameterUtil.GetStringValueFromElement(spatialElement, BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS, out strSpaceDesc)) strSpaceDesc = null; } else { // Default to true to preserve previous behavior. bool? exportGSADesignGrossArea = ExporterCacheManager.ExportOptionsCache.ExportGSAGrossDesignArea; if (!exportGSADesignGrossArea.HasValue || exportGSADesignGrossArea.Value) { Element level = document.GetElement(levelId); if (level != null) { strSpaceNumber = level.Name + " GSA Design Gross Area"; } } } string name = strSpaceNumber; string longName = strSpaceName; string desc = strSpaceDesc; IFCFile file = exporterIFC.GetFile(); IFCAnyHandle localPlacement = setter.GetPlacement(); ElementType elemType = document.GetElement(spatialElement.GetTypeId()) as ElementType; IFCInternalOrExternal internalOrExternal = CategoryUtil.IsElementExternal(spatialElement, true) ? IFCInternalOrExternal.External : IFCInternalOrExternal.Internal; double roomHeight = 0.0; roomHeight = GetHeight(spatialElement, scale, levelId, levelInfo); if (roomHeight <= 0.0) return false; double bottomOffset; ParameterUtil.GetDoubleValueFromElement(spatialElement, BuiltInParameter.ROOM_LOWER_OFFSET, out bottomOffset); XYZ zDir = new XYZ(0, 0, 1); XYZ orig = new XYZ(0, 0, levelInfo.Elevation + bottomOffset); Plane plane = new Plane(zDir, orig); // room calculated as level offset. GeometryElement geomElem = null; if (spatialElement is Autodesk.Revit.DB.Architecture.Room) { Autodesk.Revit.DB.Architecture.Room room = spatialElement as Autodesk.Revit.DB.Architecture.Room; geomElem = room.ClosedShell; } else if (spatialElement is Autodesk.Revit.DB.Mechanical.Space) { Autodesk.Revit.DB.Mechanical.Space space = spatialElement as Autodesk.Revit.DB.Mechanical.Space; geomElem = space.ClosedShell; } IFCAnyHandle spaceHnd = null; using (IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData()) { extraParams.SetLocalPlacement(localPlacement); extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ; using (IFCTransaction transaction2 = new IFCTransaction(file)) { IFCAnyHandle repHnd = null; if (!ExporterCacheManager.ExportOptionsCache.Use2DRoomBoundaryForRoomVolumeCreation && geomElem != null) { BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true); bodyExporterOptions.TessellationLevel = BodyExporterOptions.BodyTessellationLevel.Coarse; repHnd = RepresentationUtil.CreateAppropriateProductDefinitionShape(exporterIFC, spatialElement, catId, geomElem, bodyExporterOptions, null, extraParams); if (IFCAnyHandleUtil.IsNullOrHasNoValue(repHnd)) extraParams.ClearOpenings(); } else { IFCAnyHandle shapeRep = ExtrusionExporter.CreateExtrudedSolidFromCurveLoop(exporterIFC, null, curveLoops, plane, zDir, roomHeight); if (IFCAnyHandleUtil.IsNullOrHasNoValue(shapeRep)) return false; IFCAnyHandle styledItemHnd = BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, document, shapeRep, ElementId.InvalidElementId); HashSet<IFCAnyHandle> bodyItems = new HashSet<IFCAnyHandle>(); bodyItems.Add(shapeRep); shapeRep = RepresentationUtil.CreateSweptSolidRep(exporterIFC, spatialElement, catId, exporterIFC.Get3DContextHandle("Body"), bodyItems, null); IList<IFCAnyHandle> shapeReps = new List<IFCAnyHandle>(); shapeReps.Add(shapeRep); IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geomElem, Transform.Identity); if (boundingBoxRep != null) shapeReps.Add(boundingBoxRep); repHnd = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, shapeReps); } extraParams.ScaledHeight = roomHeight; extraParams.ScaledArea = dArea; string spatialElementName = NamingUtil.GetNameOverride(spatialElement, name); string spatialElementDescription = NamingUtil.GetDescriptionOverride(spatialElement, desc); string spatialElementObjectType = NamingUtil.GetObjectTypeOverride(spatialElement, null); double? spaceElevationWithFlooring = null; double elevationWithFlooring = 0.0; if (ParameterUtil.GetDoubleValueFromElement(spatialElement, "IfcElevationWithFlooring", out elevationWithFlooring) == true) spaceElevationWithFlooring = elevationWithFlooring; spaceHnd = IFCInstanceExporter.CreateSpace(file, GUIDUtil.CreateGUID(spatialElement), exporterIFC.GetOwnerHistoryHandle(), spatialElementName,spatialElementDescription, spatialElementObjectType, extraParams.GetLocalPlacement(), repHnd, longName, Toolkit.IFCElementComposition.Element, internalOrExternal, spaceElevationWithFlooring); transaction2.Commit(); } productWrapper.AddSpace(spaceHnd, levelInfo, extraParams, true); } // Save room handle for later use/relationships ExporterCacheManager.SpatialElementHandleCache.Register(spatialElement.Id, spaceHnd); exporterIFC.RegisterSpatialElementHandle(spatialElement.Id, spaceHnd); // Find Ceiling as a Space boundary and keep the relationship in a cache for use later Boolean ret = getCeilingSpaceBoundary(spatialElement); if (!MathUtil.IsAlmostZero(dArea) && !(ExporterCacheManager.ExportOptionsCache.FileVersion == IFCVersion.IFCCOBIE) && !ExporterCacheManager.ExportOptionsCache.ExportAs2x3CoordinationView2 && !ExporterCacheManager.ExportOptionsCache.ExportBaseQuantities) { ExporterIFCUtils.CreatePreCOBIEGSAQuantities(exporterIFC, spaceHnd, "GSA Space Areas", (isArea ? "GSA Design Gross Area" : "GSA BIM Area"), dArea); } // Export BaseQuantities for SpatialElement if (ExporterCacheManager.ExportOptionsCache.ExportBaseQuantities && !(ExporterCacheManager.ExportOptionsCache.FileVersion == IFCVersion.IFCCOBIE)) { // Skip this step. The "standard" quantities will be exported at the end of export element process in exportElement (Exporter.cs) // ExporterIFCUtils.CreateNonCOBIERoomQuantities(exporterIFC, spaceHnd, spatialElement, dArea, roomHeight); } // Create general classification for Spatial element from ClassificationCode(s). This is not done here but rather at the end of exportElement process // ClassificationUtil.CreateClassification(exporterIFC, file, spatialElement, spaceHnd, ""); // Export Classifications for SpatialElement for GSA/COBIE. if (ExporterCacheManager.ExportOptionsCache.FileVersion == IFCVersion.IFCCOBIE) { CreateCOBIESpaceClassifications(exporterIFC, file, spaceHnd, document.ProjectInformation, spatialElement); } return true; }
/// <summary> /// Create IFC room/space/area item, not include boundaries. /// </summary> /// <param name="exporterIFC"> /// The ExporterIFC object. /// </param> /// <param name="spatialElement"> /// The spatial element. /// </param> /// <param name="productWrapper"> /// The IFCProductWrapper. /// </param> /// <param name="setter"> /// The IFCPlacementSetter. /// </param> /// <returns> /// True if created successfully, false otherwise. /// </returns> static void CreateIFCSpace(ExporterIFC exporterIFC, SpatialElement spatialElement, IFCProductWrapper productWrapper, IFCPlacementSetter setter) { Autodesk.Revit.DB.Document document = spatialElement.Document; ElementId levelId = spatialElement.Level != null ? spatialElement.Level.Id : ElementId.InvalidElementId; double scale = exporterIFC.LinearScale; ElementId catId = spatialElement.Category != null ? spatialElement.Category.Id : ElementId.InvalidElementId; double dArea = 0.0; Parameter param = spatialElement.get_Parameter(BuiltInParameter.ROOM_AREA); if (param != null) { dArea = param.AsDouble(); dArea *= (scale * scale); } SpatialElementBoundaryOptions options = ExporterIFCUtils.GetSpatialElementBoundaryOptions(exporterIFC, spatialElement); IList<CurveLoop> curveLoops = ExporterIFCUtils.GetRoomBoundaryAsCurveLoopArray(spatialElement, options, true); IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(levelId); string strSpaceNumber = null; string strSpaceName = null; string strSpaceDesc = null; bool isArea = spatialElement is Area; if (!isArea) { Parameter paramRoomNum = spatialElement.get_Parameter(BuiltInParameter.ROOM_NUMBER); if (paramRoomNum != null) { strSpaceNumber = paramRoomNum.AsString(); } Parameter paramRoomName = spatialElement.get_Parameter(BuiltInParameter.ROOM_NAME); if (paramRoomName != null) { strSpaceName = paramRoomName.AsString(); } Parameter paramRoomComm = spatialElement.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS); if (paramRoomComm != null) { strSpaceDesc = paramRoomComm.AsString(); } } else { Element level = document.get_Element(levelId); if (level != null) { strSpaceNumber = level.Name + " GSA Design Gross Area"; } } //assign empty string if it is null if (strSpaceNumber == null) strSpaceNumber = ""; if (strSpaceName == null) strSpaceName = ""; if (strSpaceDesc == null) strSpaceDesc = ""; IFCLabel name = IFCLabel.Create(strSpaceNumber); IFCLabel longName = IFCLabel.Create(strSpaceName); IFCLabel desc = IFCLabel.Create(strSpaceDesc); IFCFile file = exporterIFC.GetFile(); IFCAnyHandle localPlacement = setter.GetPlacement(); ElementType elemType = document.get_Element(spatialElement.GetTypeId()) as ElementType; bool isObjectExternal = CategoryUtil.IsElementExternal(spatialElement); IFCMeasureValue elevationWithFlooring = IFCMeasureValue.Create(); double roomHeight = 0.0; roomHeight = GetHeight(spatialElement, scale, levelInfo); double bottomOffset = 0.0; Parameter paramBottomOffset = spatialElement.get_Parameter(BuiltInParameter.ROOM_LOWER_OFFSET); bottomOffset = paramBottomOffset != null ? paramBottomOffset.AsDouble() : 0.0; XYZ zDir = new XYZ(0, 0, 1); XYZ orig = new XYZ(0, 0, levelInfo.Elevation + bottomOffset); Plane plane = new Plane(zDir, orig); // room calculated as level offset. GeometryElement geomElem = null; if (spatialElement is Autodesk.Revit.DB.Architecture.Room) { Autodesk.Revit.DB.Architecture.Room room = spatialElement as Autodesk.Revit.DB.Architecture.Room; geomElem = room.ClosedShell; } else if (spatialElement is Autodesk.Revit.DB.Mechanical.Space) { Autodesk.Revit.DB.Mechanical.Space space = spatialElement as Autodesk.Revit.DB.Mechanical.Space; geomElem = space.ClosedShell; } IFCAnyHandle spaceHnd = null; IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData(); extraParams.SetLocalPlacement(localPlacement); extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ; using (IFCTransaction tr2 = new IFCTransaction(file)) { IFCAnyHandle repHnd = null; if (!(exporterIFC.ExportAs2x2 || Use2DRoomBoundaryForRoomVolumeCalculation()) && geomElem != null) { IFCSolidMeshGeometryInfo solidMeshInfo = ExporterIFCUtils.GetSolidMeshGeometry(exporterIFC, geomElem, Transform.Identity); IList<Solid> solids = solidMeshInfo.GetSolids(); IList<Mesh> polyMeshes = solidMeshInfo.GetMeshes(); bool tryToExportAsExtrusion = true; if (solids.Count != 1 || polyMeshes.Count != 0) tryToExportAsExtrusion = false; IList<GeometryObject> geomObjects = new List<GeometryObject>(); foreach (Solid solid in solids) geomObjects.Add(solid); IFCAnyHandle shapeRep = BodyExporter.ExportBody(spatialElement.Document.Application, exporterIFC, catId, geomObjects, tryToExportAsExtrusion, extraParams); IList<IFCAnyHandle> shapeReps = new List<IFCAnyHandle>(); shapeReps.Add(shapeRep); repHnd = file.CreateProductDefinitionShape(IFCLabel.Create(), IFCLabel.Create(), shapeReps); } else { IFCAnyHandle shapeRep = file.CreateExtrudedSolidFromCurveLoop(exporterIFC, catId, curveLoops, plane, zDir, roomHeight); //pScaledOrig? HashSet<IFCAnyHandle> bodyItems = new HashSet<IFCAnyHandle>(); bodyItems.Add(shapeRep); shapeRep = RepresentationUtil.CreateSweptSolidRep(exporterIFC, catId, exporterIFC.Get3DContextHandle(), bodyItems, IFCAnyHandle.Create()); IList<IFCAnyHandle> shapeReps = new List<IFCAnyHandle>(); shapeReps.Add(shapeRep); repHnd = file.CreateProductDefinitionShape(IFCLabel.Create(), IFCLabel.Create(), shapeReps); } extraParams.ScaledHeight = roomHeight; extraParams.ScaledArea = dArea; spaceHnd = file.CreateSpace(IFCLabel.CreateGUID(spatialElement), exporterIFC.GetOwnerHistoryHandle(), NamingUtil.GetNameOverride(spatialElement, name), NamingUtil.GetDescriptionOverride(spatialElement, desc), NamingUtil.GetObjectTypeOverride(spatialElement, IFCLabel.Create()), extraParams.GetLocalPlacement(), repHnd, longName, IFCElementComposition.Element , isObjectExternal, elevationWithFlooring); tr2.Commit(); } productWrapper.AddSpace(spaceHnd, levelInfo, extraParams, true); // Save room handle for later use/relationships exporterIFC.RegisterSpatialElementHandle(spatialElement.Id, spaceHnd); if (!MathUtil.IsAlmostZero(dArea) && !(exporterIFC.FileVersion == IFCVersion.IFCCOBIE)) { ExporterIFCUtils.CreatePreCOBIEGSAQuantities(exporterIFC, spaceHnd, "GSA Space Areas", (isArea ? "GSA Design Gross Area" : "GSA BIM Area"), dArea); } // Export BaseQuantities for RoomElem if (exporterIFC.ExportBaseQuantities && !(exporterIFC.FileVersion == IFCVersion.IFCCOBIE)) { ExporterIFCUtils.CreateNonCOBIERoomQuantities(exporterIFC, spaceHnd, spatialElement, dArea, roomHeight); } }
/// <summary> /// Export spatial elements, including rooms, areas and spaces. 1st level space boundaries. /// </summary> /// <param name="exporterIFC"> /// The ExporterIFC object. /// </param> /// <param name="spatialElement"> /// The spatial element. /// </param> /// <param name="productWrapper"> /// The IFCProductWrapper. /// </param> public static void ExportSpatialElement(ExporterIFC exporterIFC, SpatialElement spatialElement, IFCProductWrapper productWrapper) { //quick reject bool isArea = spatialElement is Area; if (isArea) { if (!IsAreaGrossInterior(exporterIFC, spatialElement)) return; } IFCFile file = exporterIFC.GetFile(); using (IFCTransaction tr = new IFCTransaction(file)) { ElementId levelId = spatialElement.Level != null ? spatialElement.Level.Id : ElementId.InvalidElementId; using (IFCPlacementSetter setter = IFCPlacementSetter.Create(exporterIFC, spatialElement, null, null, levelId)) { CreateIFCSpace(exporterIFC, spatialElement, productWrapper, setter); // Do not create boundary information, or extra property sets. if (spatialElement is Area) { tr.Commit(); return; } if (exporterIFC.SpaceBoundaryLevel == 1) { Document document = spatialElement.Document; IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(levelId); double baseHeightNonScaled = levelInfo.Elevation; SpatialElementGeometryResults spatialElemGeomResult = s_SpatialElemGeometryCalculator.CalculateSpatialElementGeometry(spatialElement); Solid spatialElemGeomSolid = spatialElemGeomResult.GetGeometry(); FaceArray faces = spatialElemGeomSolid.Faces; foreach (Face face in faces) { IList<SpatialElementBoundarySubface> spatialElemBoundarySubfaces = spatialElemGeomResult.GetBoundaryFaceInfo(face); foreach (SpatialElementBoundarySubface spatialElemBSubface in spatialElemBoundarySubfaces) { if (spatialElemBSubface.SubfaceType == SubfaceType.Side) continue; if (spatialElemBSubface.GetSubface() == null) continue; ElementId elemId = spatialElemBSubface.SpatialBoundaryElement.LinkInstanceId; if (elemId == ElementId.InvalidElementId) { elemId = spatialElemBSubface.SpatialBoundaryElement.HostElementId; } Element boundingElement = document.get_Element(elemId); if (boundingElement == null) continue; bool isObjectExt = CategoryUtil.IsElementExternal(boundingElement); IFCGeometryInfo info = IFCGeometryInfo.CreateSurfaceGeometryInfo(spatialElement.Document.Application.VertexTolerance); Face subFace = spatialElemBSubface.GetSubface(); ExporterIFCUtils.CollectGeometryInfo(exporterIFC, info, subFace, XYZ.Zero, false); IFCAnyHandle ifcOptionalHnd = IFCAnyHandle.Create(); foreach (IFCAnyHandle surfaceHnd in info.GetSurfaces()) { IFCAnyHandle connectionGeometry = file.CreateConnectionSurfaceGeometry(surfaceHnd, ifcOptionalHnd); IFCSpaceBoundary spaceBoundary = IFCSpaceBoundary.Create(spatialElement.Id, boundingElement.Id, connectionGeometry, IFCSpaceBoundaryType.Physical, isObjectExt); if (!ProcessIFCSpaceBoundary(exporterIFC, spaceBoundary, file)) exporterIFC.RegisterIFCSpaceBoundary(spaceBoundary); } } } IList<IList<BoundarySegment>> roomBoundaries = spatialElement.GetBoundarySegments(ExporterIFCUtils.GetSpatialElementBoundaryOptions(exporterIFC, spatialElement)); double roomHeight = GetHeight(spatialElement, exporterIFC.LinearScale, levelInfo); XYZ zDir = new XYZ(0, 0, 1); foreach (IList<BoundarySegment> roomBoundaryList in roomBoundaries) { foreach (BoundarySegment roomBoundary in roomBoundaryList) { Element boundingElement = roomBoundary.Element; if (boundingElement == null) continue; ElementId buildingElemId = boundingElement.Id; Curve trimmedCurve = roomBoundary.Curve; if (trimmedCurve == null) continue; //trimmedCurve.Visibility = Visibility.Visible; readonly IFCAnyHandle connectionGeometry = ExporterIFCUtils.CreateExtrudedSurfaceFromCurve( exporterIFC, trimmedCurve, zDir, roomHeight, baseHeightNonScaled); IFCSpaceBoundaryType physOrVirt = IFCSpaceBoundaryType.Physical; if (boundingElement is CurveElement) physOrVirt = IFCSpaceBoundaryType.Virtual; else if (boundingElement is Autodesk.Revit.DB.Architecture.Room) physOrVirt = IFCSpaceBoundaryType.Undefined; bool isObjectExt = CategoryUtil.IsElementExternal(boundingElement); bool isObjectPhys = (physOrVirt == IFCSpaceBoundaryType.Physical); ElementId actualBuildingElemId = isObjectPhys ? buildingElemId : ElementId.InvalidElementId; IFCSpaceBoundary boundary = IFCSpaceBoundary.Create(spatialElement.Id, actualBuildingElemId, connectionGeometry, physOrVirt, isObjectExt); if (!ProcessIFCSpaceBoundary(exporterIFC, boundary, file)) exporterIFC.RegisterIFCSpaceBoundary(boundary); // try to add doors and windows for host objects if appropriate. if (isObjectPhys && boundingElement is HostObject) { HostObject hostObj = boundingElement as HostObject; IList<ElementId> elemIds = hostObj.FindInserts(false, false, false, false); foreach (ElementId elemId in elemIds) { // we are going to do a simple bbox export, not complicated geometry. Element instElem = document.get_Element(elemId); if (instElem == null) continue; BoundingBoxXYZ instBBox = instElem.get_BoundingBox(null); // make copy of original trimmed curve. Curve instCurve = trimmedCurve.Clone(); XYZ instOrig = instCurve.get_EndPoint(0); // make sure that the insert is on this level. if (instBBox.Max.Z < instOrig.Z) continue; if (instBBox.Min.Z > instOrig.Z + roomHeight) continue; double insHeight = Math.Min(instBBox.Max.Z, instOrig.Z + roomHeight) - Math.Max(instOrig.Z, instBBox.Min.Z); if (insHeight < (1.0 / (12.0 * 16.0))) continue; // move base curve to bottom of bbox. XYZ moveDir = new XYZ(0.0, 0.0, instBBox.Min.Z - instOrig.Z); Transform moveTrf = Transform.get_Translation(moveDir); instCurve = instCurve.get_Transformed(moveTrf); bool isHorizOrVert = false; if (instCurve is Line) { Line instLine = instCurve as Line; XYZ lineDir = instLine.Direction; if (MathUtil.IsAlmostEqual(Math.Abs(lineDir.X), 1.0) || (MathUtil.IsAlmostEqual(Math.Abs(lineDir.Y), 1.0))) isHorizOrVert = true; } double[] parameters = new double[2]; double[] origEndParams = new double[2]; if (isHorizOrVert) { parameters[0] = instCurve.Project(instBBox.Min).Parameter; parameters[1] = instCurve.Project(instBBox.Max).Parameter; } else { FamilyInstance famInst = instElem as FamilyInstance; if (famInst == null) continue; ElementType elementType = document.get_Element(famInst.GetTypeId()) as ElementType; if (elementType == null) continue; BoundingBoxXYZ symBBox = elementType.get_BoundingBox(null); Curve symCurve = trimmedCurve.Clone(); Transform trf = famInst.GetTransform(); Transform invTrf = trf.Inverse; Curve trfCurve = symCurve.get_Transformed(invTrf); parameters[0] = trfCurve.Project(symBBox.Min).Parameter; parameters[1] = trfCurve.Project(symBBox.Max).Parameter; } // ignore if less than 1/16". if (Math.Abs(parameters[1] - parameters[0]) < 1.0 / (12.0 * 16.0)) continue; if (parameters[0] > parameters[1]) { //swap double tempParam = parameters[0]; parameters[0] = parameters[1]; parameters[1] = tempParam; } origEndParams[0] = instCurve.get_EndParameter(0); origEndParams[1] = instCurve.get_EndParameter(1); if (origEndParams[0] > parameters[1] - (1.0 / (12.0 * 16.0))) continue; if (origEndParams[1] < parameters[0] + (1.0 / (12.0 * 16.0))) continue; if (parameters[0] > origEndParams[0]) instCurve.set_EndParameter(0, parameters[0]); if (parameters[1] < origEndParams[1]) instCurve.set_EndParameter(1, parameters[1]); IFCAnyHandle insConnectionGeom = ExporterIFCUtils.CreateExtrudedSurfaceFromCurve(exporterIFC, instCurve, zDir, insHeight, baseHeightNonScaled); IFCSpaceBoundary instBoundary = IFCSpaceBoundary.Create(spatialElement.Id, elemId, insConnectionGeom, physOrVirt, isObjectExt); if (!ProcessIFCSpaceBoundary(exporterIFC, instBoundary, file)) exporterIFC.RegisterIFCSpaceBoundary(instBoundary); } } } } } ExporterIFCUtils.CreateSpatialElementPropertySet(exporterIFC, spatialElement, productWrapper); } tr.Commit(); } }
/// <summary> /// Exports a family instance as a mapped item. /// </summary> /// <param name="exporterIFC"> /// The ExporterIFC object. /// </param> /// <param name="familyInstance"> /// The family instance to be exported. /// </param> /// <param name="exportType"> /// The export type. /// </param> /// <param name="ifcEnumType"> /// The string value represents the IFC type. /// </param> /// <param name="wrapper"> /// The IFCProductWrapper. /// </param> /// <param name="overrideLevelId"> /// The level id. /// </param> /// <param name="range"> /// The range of this family instance to be exported. /// </param> public static void ExportFamilyInstanceAsMappedItem(ExporterIFC exporterIFC, FamilyInstance familyInstance, IFCExportType exportType, string ifcEnumType, IFCProductWrapper wrapper, ElementId overrideLevelId, UV range) { Document doc = familyInstance.Document; IFCFile file = exporterIFC.GetFile(); FamilySymbol familySymbol = ExporterIFCUtils.GetOriginalSymbol(familyInstance); if (familySymbol == null) return; IFCProductWrapper familyProductWrapper = IFCProductWrapper.Create(wrapper); double scale = exporterIFC.LinearScale; IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle(); HostObject hostElement = familyInstance.Host as HostObject; //hostElement could be null ElementId categoryId = CategoryUtil.GetSafeCategoryId(familySymbol); //string emptyString = ""; string familyName = familySymbol.Name; IFCLabel objectType = IFCLabel.Create(familyName); // A Family Instance can have its own copy of geometry, or use the symbol's copy with a transform. // The routine below tells us whether to use the Instance's copy or the Symbol's copy. bool useInstanceGeometry = ExporterIFCUtils.UsesInstanceGeometry(familyInstance); IList<IFCExtrusionData> cutPairOpeningsForColumns = new List<IFCExtrusionData>(); IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData(); Transform trf = familyInstance.GetTransform(); // Extra information if we are exporting a door or a window. IFCDoorWindowInfo doorWindowInfo = null; if (exportType == IFCExportType.ExportDoorType) doorWindowInfo = IFCDoorWindowInfo.CreateDoorInfo(exporterIFC, familyInstance, familySymbol, hostElement, overrideLevelId, trf); else if (exportType == IFCExportType.ExportWindowType) doorWindowInfo = IFCDoorWindowInfo.CreateWindowInfo(exporterIFC, familyInstance, familySymbol, hostElement, overrideLevelId, trf); IFCTypeInfo typeInfo = new IFCTypeInfo(); XYZ extraOffset = XYZ.Zero; bool flipped = doorWindowInfo != null ? doorWindowInfo.IsSymbolFlipped : false; IFCTypeInfo currentTypeInfo = exporterIFC.FindType(familySymbol.Id, flipped); bool found = currentTypeInfo.IsValid(); Family family = familySymbol.Family; // TODO: this code to be removed by ExtrusionAnalyzer code. bool trySpecialColumnCreation = ((exportType == IFCExportType.ExportColumnType) && (!family.IsInPlace)); // We will create a new mapped type if: // 1. We are exporting part of a column or in-place wall (range != null), OR // 2. We are using the instance's copy of the geometry (that it, it has unique geometry), OR // 3. We haven't already created the type. bool creatingType = ((range != null) || useInstanceGeometry || !found); if (creatingType) { IFCAnyHandle bodyRepresentation = IFCAnyHandle.Create(); IFCAnyHandle planRepresentation = IFCAnyHandle.Create(); // If we are using the instance geometry, ignore the transformation. if (useInstanceGeometry) trf = Transform.Identity; // TODO: this code to be removed by ExtrusionAnalyzer code. if (trySpecialColumnCreation) { XYZ rangeOffset = trf.Origin; IFCFamilyInstanceExtrusionExportResults results; if (range != null) { results = ExporterIFCUtils.ExportFamilyInstanceAsExtrusion(exporterIFC, familyInstance, useInstanceGeometry, range, overrideLevelId, extraParams); } else { results = ExporterIFCUtils.ExportFamilyInstanceAsExtrusion(exporterIFC, familyInstance, useInstanceGeometry, overrideLevelId, extraParams); } bodyRepresentation = results.GetExtrusionHandle(); extraOffset = results.ExtraOffset; cutPairOpeningsForColumns = results.GetCutPairOpenings(); if (bodyRepresentation.HasValue) { typeInfo.MaterialId = results.MaterialId; // add in level for real columns, not in-place ones. Element actualLevel = (overrideLevelId == ElementId.InvalidElementId) ? familyInstance.Level : doc.get_Element(overrideLevelId); if (actualLevel != null) { IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(actualLevel.Id); double nonStoryLevelOffset = LevelUtil.GetNonStoryLevelOffsetIfAny(exporterIFC, actualLevel as Level); if (range != null) { rangeOffset = new XYZ(rangeOffset.X, rangeOffset.Y, levelInfo.Elevation + nonStoryLevelOffset); } } } rangeOffset += extraOffset; trf.Origin = rangeOffset; } Transform doorWindowTrf = Transform.Identity; IFCAnyHandle dummyPlacement = IFCAnyHandle.Create(); if (doorWindowInfo != null) { doorWindowTrf = ExporterIFCUtils.GetTransformForDoorOrWindow(familyInstance, familySymbol, doorWindowInfo); } else { dummyPlacement = file.CreateLocalPlacement(IFCAnyHandle.Create(), file.CreateAxis2Placement3D()); extraParams.SetLocalPlacement(dummyPlacement); } bool needToCreate2d = (!exporterIFC.ExportAs2x2); bool needToCreate3d = (!bodyRepresentation.HasValue); if (needToCreate2d || needToCreate3d) { using (IFCTransformSetter trfSetter = IFCTransformSetter.Create()) { if (doorWindowInfo != null) { trfSetter.Initialize(exporterIFC, doorWindowTrf); } Options options = new Options(); GeometryElement exportGeometry = useInstanceGeometry ? familyInstance.get_Geometry(options) : familySymbol.get_Geometry(options); if (exportGeometry == null) return; if (needToCreate3d) { IFCSolidMeshGeometryInfo solidMeshInfo; if (range == null) solidMeshInfo = ExporterIFCUtils.GetSolidMeshGeometry(exporterIFC, exportGeometry, Transform.Identity); else solidMeshInfo = ExporterIFCUtils.GetClippedSolidMeshGeometry(exporterIFC, range, exportGeometry); IList<Solid> solids = solidMeshInfo.GetSolids(); IList<Mesh> polyMeshes = solidMeshInfo.GetMeshes(); bool tryToExportAsExtrusion = (!exporterIFC.ExportAs2x2 || (exportType == IFCExportType.ExportColumnType)); if (exportType == IFCExportType.ExportColumnType) { extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ; } else { extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryXYZ; } if (solids.Count > 0 || polyMeshes.Count > 0) { bodyRepresentation = BodyExporter.ExportBody(familyInstance.Document.Application, exporterIFC, categoryId, solids, polyMeshes, tryToExportAsExtrusion, extraParams); typeInfo.MaterialId = BodyExporter.GetBestMaterialIdForGeometry(solids, polyMeshes); } else { IList<GeometryObject> exportedGeometries = new List<GeometryObject>(); exportedGeometries.Add(exportGeometry); bodyRepresentation = BodyExporter.ExportBody(familyInstance.Document.Application, exporterIFC, categoryId, exportedGeometries, tryToExportAsExtrusion, extraParams); } if (!bodyRepresentation.HasValue) { extraParams.ClearOpenings(); return; } } // if exporting IFC2x3 (or later), export 2D plan rep of family (if it exists). if (needToCreate2d) { HashSet<IFCAnyHandle> curveSet = new HashSet<IFCAnyHandle>(); { Transform planeTrf = doorWindowTrf.Inverse; Plane plane = new Plane(planeTrf.get_Basis(0), planeTrf.get_Basis(1), planeTrf.Origin); XYZ projDir = new XYZ(0, 0, 1); IFCGeometryInfo IFCGeometryInfo = IFCGeometryInfo.CreateCurveGeometryInfo(exporterIFC, plane, projDir, true); ExporterIFCUtils.CollectGeometryInfo(exporterIFC, IFCGeometryInfo, exportGeometry, planeTrf.Origin, false); IList<IFCAnyHandle> curves = IFCGeometryInfo.GetCurves(); foreach (IFCAnyHandle curve in curves) curveSet.Add(curve); if (curveSet.Count > 0) { IFCAnyHandle contextOfItems2d = exporterIFC.Get2DContextHandle(); IFCAnyHandle curveRepresentationItem = file.CreateGeometricSet(curveSet); HashSet<IFCAnyHandle> bodyItems = new HashSet<IFCAnyHandle>(); bodyItems.Add(curveRepresentationItem); planRepresentation = RepresentationUtil.CreateGeometricSetRep(exporterIFC, categoryId, "Annotation", contextOfItems2d, bodyItems); } } } } } if (doorWindowInfo != null) { typeInfo.SetStyleTransform(doorWindowTrf.Inverse); } else { if (!MathUtil.IsAlmostZero(extraOffset.DotProduct(extraOffset))) { Transform newTransform = typeInfo.GetStyleTransform(); XYZ newOrig = newTransform.Origin + extraOffset; newTransform.Origin = newOrig; typeInfo.SetStyleTransform(newTransform); } typeInfo.SetStyleTransform(ExporterIFCUtils.GetUnscaledTransform(exporterIFC, extraParams.GetLocalPlacement())); } IFCLabel descriptionOpt = IFCLabel.Create(); IFCLabel applicableOccurrenceOpt = IFCLabel.Create(); IFCAnyHandle origin = file.CreateAxis2Placement3D(); IFCAnyHandle repMap2dHnd = IFCAnyHandle.Create(); IFCAnyHandle repMap3dHnd = file.CreateRepresentationMap(origin, bodyRepresentation); IList<IFCAnyHandle> repMapList = new List<IFCAnyHandle>(); repMapList.Add(repMap3dHnd); if (planRepresentation.HasValue) { repMap2dHnd = file.CreateRepresentationMap(origin, planRepresentation); repMapList.Add(repMap2dHnd); } // for Door, Window bool paramTakesPrecedence = false; // For Revit, this is currently always false. bool sizeable = false; // for many HashSet<IFCAnyHandle> propertySets = new HashSet<IFCAnyHandle>(); IFCLabel guid = IFCLabel.CreateGUID(familySymbol); IFCLabel symIdAsLabel = NamingUtil.CreateIFCElementId(familySymbol); // This covers many generic types. If we can't find it in the list here, do custom exports. IFCAnyHandle typeStyle = FamilyExporterUtil.ExportGenericType(file, exportType, ifcEnumType, guid, ownerHistory, objectType, descriptionOpt, applicableOccurrenceOpt, propertySets, repMapList, symIdAsLabel, objectType, familyInstance, familySymbol); // Cover special cases not covered above. if (!typeStyle.HasValue) { switch (exportType) { case IFCExportType.ExportColumnType: { // If we are using the instance GRep, then we have to create a generic GUID for the // column type, as they share the same ElementId. IFCLabel colGUID = IFCLabel.Create(); IFCLabel colElemId = IFCLabel.Create(); if (useInstanceGeometry) { colGUID = IFCLabel.CreateGUID(); colElemId = NamingUtil.CreateIFCElementId(familyInstance); } else { colGUID = guid; colElemId = NamingUtil.CreateIFCElementId(familySymbol); } string columnType = "Column"; typeStyle = file.CreateColumnType(columnType, colGUID, ownerHistory, objectType, descriptionOpt, applicableOccurrenceOpt, propertySets, repMapList, colElemId, objectType, familyInstance, familySymbol); break; } case IFCExportType.ExportDoorType: { string constructionType = string.Empty; ParameterUtil.GetStringValueFromElementOrSymbol(familyInstance, "Construction", out constructionType); IFCAnyHandle doorLining = DoorWindowUtil.CreateDoorLiningProperties(exporterIFC, familyInstance); if (doorLining.HasValue) propertySets.Add(doorLining); IList<IFCAnyHandle> doorPanels = DoorWindowUtil.CreateDoorPanelProperties(exporterIFC, doorWindowInfo, familyInstance); propertySets.UnionWith(doorPanels); IFCLabel doorStyleGUID = IFCLabel.CreateGUID(); IFCLabel doorStyleElemId = NamingUtil.CreateIFCElementId(familyInstance); typeStyle = file.CreateDoorStyle(doorStyleGUID, ownerHistory, objectType, descriptionOpt, applicableOccurrenceOpt, propertySets, repMapList, doorStyleElemId, doorWindowInfo.DoorOperationType, constructionType, paramTakesPrecedence, sizeable); break; } case IFCExportType.ExportSystemFurnitureElementType: { IFCLabel furnitureId = NamingUtil.CreateIFCElementId(familyInstance); typeStyle = file.CreateSystemFurnitureElementType(guid, ownerHistory, objectType, descriptionOpt, applicableOccurrenceOpt, propertySets, repMapList, furnitureId, objectType); break; } case IFCExportType.ExportWindowType: { IFCWindowStyleOperation operationType = DoorWindowUtil.GetIFCWindowStyleOperation(familySymbol); string constructionType = DoorWindowUtil.GetIFCWindowStyleConstruction(familyInstance, ""); IFCAnyHandle windowLining = DoorWindowUtil.CreateWindowLiningProperties(exporterIFC, familyInstance, descriptionOpt); if (windowLining.HasValue) propertySets.Add(windowLining); IList<IFCAnyHandle> windowPanels = DoorWindowUtil.CreateWindowPanelProperties(exporterIFC, familyInstance, descriptionOpt); propertySets.UnionWith(windowPanels); IFCLabel windowStyleGUID = IFCLabel.CreateGUID(); IFCLabel windowStyleElemId = NamingUtil.CreateIFCElementId(familyInstance); typeStyle = file.CreateWindowStyle(windowStyleGUID, ownerHistory, objectType, descriptionOpt, applicableOccurrenceOpt, propertySets, repMapList, windowStyleElemId, operationType, constructionType, paramTakesPrecedence, sizeable); break; } case IFCExportType.ExportBuildingElementProxy: default: { typeInfo.Set2DMapHandle(repMap2dHnd); typeInfo.Set3DMapHandle(repMap3dHnd); break; } } } typeInfo.SetStyle(typeStyle); // Transfer extraParams information for certain types. if (typeStyle.HasValue) { if (((exportType == IFCExportType.ExportColumnType) && trySpecialColumnCreation) || (exportType == IFCExportType.ExportMemberType)) { typeInfo.ScaledArea = extraParams.ScaledArea; typeInfo.ScaledDepth = extraParams.ScaledLength; typeInfo.ScaledInnerPerimeter = extraParams.ScaledInnerPerimeter; typeInfo.ScaledOuterPerimeter = extraParams.ScaledOuterPerimeter; } } } else if (!creatingType && (trySpecialColumnCreation)) { // still need to modify instance trf for columns. trf.Origin += GetLevelOffsetForExtrudedColumns(exporterIFC, familyInstance, overrideLevelId, extraParams); } if (found && !typeInfo.GetStyle().HasValue) { typeInfo = currentTypeInfo; } // we'll pretend we succeeded, but we'll do nothing. if (!typeInfo.GetStyle().HasValue && !typeInfo.Get2DMapHandle().HasValue && !typeInfo.Get3DMapHandle().HasValue) return; // add to the map, as long as we are not using range, not using instance geometry, and don't have extra openings. if ((range == null) && !useInstanceGeometry && (extraParams.GetOpenings().Count == 0)) exporterIFC.AddType(familySymbol.Id, flipped, typeInfo); Transform oldTrf = new Transform(trf); XYZ scaledMapOrigin = XYZ.Zero; trf = trf.Multiply(typeInfo.GetStyleTransform()); // create instance. IList<IFCAnyHandle> shapeReps = new List<IFCAnyHandle>(); { IFCAnyHandle contextOfItems2d = exporterIFC.Get2DContextHandle(); IFCAnyHandle contextOfItems3d = exporterIFC.Get3DContextHandle(); // for proxies, we store the IfcRepresentationMap directly since there is no style. IList<IFCAnyHandle> repMapList = IFCGeometryUtils.GetRepresentationMaps(typeInfo.GetStyle()); int numReps = repMapList.Count; IFCAnyHandle repMap2dHnd = typeInfo.Get2DMapHandle(); IFCAnyHandle repMap3dHnd = typeInfo.Get3DMapHandle(); if (!repMap3dHnd.HasValue && (numReps > 0)) repMap3dHnd = repMapList[0]; if (!repMap2dHnd.HasValue && (numReps > 1)) repMap2dHnd = repMapList[1]; if (repMap3dHnd.HasValue) { HashSet<IFCAnyHandle> representations = new HashSet<IFCAnyHandle>(); representations.Add(ExporterUtil.CreateDefaultMappedItem(file, repMap3dHnd, scaledMapOrigin)); IFCAnyHandle shapeRep = RepresentationUtil.CreateBodyMappedItemRep(exporterIFC, categoryId, contextOfItems3d, representations); if (!shapeRep.HasValue) return; shapeReps.Add(shapeRep); } if (repMap2dHnd.HasValue) { HashSet<IFCAnyHandle> representations = new HashSet<IFCAnyHandle>(); representations.Add(ExporterUtil.CreateDefaultMappedItem(file, repMap2dHnd, scaledMapOrigin)); IFCAnyHandle shapeRep = RepresentationUtil.CreatePlanMappedItemRep(exporterIFC, categoryId, contextOfItems2d, representations); if (!shapeRep.HasValue) return; shapeReps.Add(shapeRep); } } IFCLabel noDescriptionOpt = IFCLabel.Create(); IFCLabel noNameOpt = IFCLabel.Create(); IFCAnyHandle rep = file.CreateProductDefinitionShape(noNameOpt, noDescriptionOpt, shapeReps); IFCAnyHandle instanceHandle = IFCAnyHandle.Create(); using (IFCPlacementSetter setter = IFCPlacementSetter.Create(exporterIFC, familyInstance, trf, null, overrideLevelId)) { IFCLabel instanceGUID = IFCLabel.CreateGUID(familyInstance); IFCLabel origInstanceName = NamingUtil.CreateIFCName(exporterIFC, -1); IFCLabel instanceName = NamingUtil.GetNameOverride(familyInstance, origInstanceName); IFCLabel instanceDescription = NamingUtil.GetDescriptionOverride(familyInstance, noDescriptionOpt); IFCLabel instanceObjectType = NamingUtil.GetObjectTypeOverride(familyInstance, objectType); IFCLabel instanceElemId = NamingUtil.CreateIFCElementId(familyInstance); IFCAnyHandle localPlacement = setter.GetPlacement(); instanceHandle = FamilyExporterUtil.ExportGenericInstance(exportType, exporterIFC, familyInstance, wrapper, setter, extraParams, instanceGUID, ownerHistory, instanceName, instanceDescription, instanceObjectType, rep, instanceElemId); switch (exportType) { case IFCExportType.ExportColumnType: { IFCAnyHandle placementToUse = localPlacement; if (!useInstanceGeometry) { Transform openingTrf = new Transform(oldTrf); Transform extraRot = new Transform(oldTrf); extraRot.Origin = XYZ.Zero; openingTrf = openingTrf.Multiply(extraRot); openingTrf = openingTrf.Multiply(typeInfo.GetStyleTransform()); IFCAnyHandle openingRelativePlacement = file.CreateAxis2Placement3D(openingTrf.Origin * scale, openingTrf.get_Basis(2), openingTrf.get_Basis(0)); IFCAnyHandle openingPlacement = ExporterUtil.CopyLocalPlacement(file, localPlacement); IFCGeometryUtils.SetRelativePlacement(openingPlacement, openingRelativePlacement); placementToUse = openingPlacement; } OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, cutPairOpeningsForColumns, exporterIFC, placementToUse, setter, wrapper); OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, extraParams, exporterIFC, placementToUse, setter, wrapper); //export Base Quantities. ExporterIFCUtils.CreateBeamColumnBaseQuantities(exporterIFC, instanceHandle, familyInstance, typeInfo); CategoryUtil.CreateMaterialAssociation(doc, exporterIFC, instanceHandle, typeInfo.MaterialId); ExporterIFCUtils.CreateColumnPropertySet(exporterIFC, familyInstance, extraParams, wrapper); break; } case IFCExportType.ExportDoorType: case IFCExportType.ExportWindowType: { double doorHeight = doorWindowInfo.OpeningHeight; if (doorHeight < MathUtil.Eps()) doorHeight = GetMinSymbolHeight(familySymbol); double doorWidth = doorWindowInfo.OpeningWidth; if (doorWidth < MathUtil.Eps()) doorWidth = GetMinSymbolWidth(familySymbol); IFCMeasureValue height = IFCMeasureValue.Create(doorHeight * scale); IFCMeasureValue width = IFCMeasureValue.Create(doorWidth * scale); if (!doorWindowInfo.GetLocalPlacement().HasValue) doorWindowInfo.SetLocalPlacement(localPlacement); IFCAnyHandle doorWindowOrigLocalPlacement = doorWindowInfo.GetLocalPlacement(); Transform relTrf = ExporterIFCUtils.GetRelativeLocalPlacementOffsetTransform(localPlacement, doorWindowOrigLocalPlacement); IFCAnyHandle doorWindowRelativePlacement = file.CreateAxis2Placement3D(relTrf); IFCAnyHandle doorWindowLocalPlacement = file.CreateLocalPlacement(doorWindowOrigLocalPlacement, doorWindowRelativePlacement); if (exportType == IFCExportType.ExportDoorType) instanceHandle = file.CreateDoor(instanceGUID, ownerHistory, instanceName, instanceDescription, instanceObjectType, doorWindowLocalPlacement, rep, instanceElemId, height, width); else if (exportType == IFCExportType.ExportWindowType) instanceHandle = file.CreateWindow(instanceGUID, ownerHistory, instanceName, instanceDescription, instanceObjectType, doorWindowLocalPlacement, rep, instanceElemId, height, width); wrapper.AddElement(instanceHandle, setter, extraParams, true); exporterIFC.RegisterSpaceBoundingElementHandle(instanceHandle, familyInstance.Id, setter.LevelId); // only necessary when exporting as possible breps. OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, extraParams, exporterIFC, doorWindowLocalPlacement, setter, wrapper); if (exporterIFC.ExportBaseQuantities) ExporterIFCUtils.CreateDoorWindowBaseQuantities(exporterIFC, instanceHandle, (doorHeight * scale), (doorWidth * scale)); if (exportType == IFCExportType.ExportDoorType) ExporterIFCUtils.CreateDoorPropertySet(exporterIFC, familyInstance, wrapper); else ExporterIFCUtils.CreateWindowPropertySet(exporterIFC, familyInstance, wrapper); break; } case IFCExportType.ExportMemberType: { OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, extraParams, exporterIFC, localPlacement, setter, wrapper); CategoryUtil.CreateMaterialAssociation(doc, exporterIFC, instanceHandle, typeInfo.MaterialId); //export Base Quantities. ExporterIFCUtils.CreateBeamColumnBaseQuantities(exporterIFC, instanceHandle, familyInstance, typeInfo); // TODO: create PropertySet! //createMemberPropertySet(exporter, pFamInst, pWrapper, extraParams); ExporterIFCUtils.CreateGenericElementPropertySet(exporterIFC, familyInstance, wrapper); break; } case IFCExportType.ExportPlateType: { OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, extraParams, exporterIFC, localPlacement, setter, wrapper); CategoryUtil.CreateMaterialAssociation(doc, exporterIFC, instanceHandle, typeInfo.MaterialId); // TODO: create PropertySet! //createPlatePropertySet(exporter, pFamInst, pWrapper, extraParams); ExporterIFCUtils.CreateGenericElementPropertySet(exporterIFC, familyInstance, wrapper); break; } case IFCExportType.ExportTransportElementType: { string operationTypeOpt = ""; IFCMeasureValue capByWeightOpt = IFCMeasureValue.Create(); IFCMeasureValue capByNumOpt = IFCMeasureValue.Create(); IFCAnyHandle localPlacementToUse; ElementId roomId = setter.UpdateRoomRelativeCoordinates(familyInstance, out localPlacementToUse); instanceHandle = file.CreateTransportElement(instanceGUID, ownerHistory, instanceName, instanceDescription, instanceObjectType, localPlacementToUse, rep, instanceElemId, operationTypeOpt, capByWeightOpt, capByNumOpt, familyInstance, familySymbol); if (roomId == ElementId.InvalidElementId) { wrapper.AddElement(instanceHandle, setter, extraParams, true); } else { exporterIFC.RelateSpatialElement(roomId, instanceHandle); wrapper.AddElement(instanceHandle, setter, extraParams, false); } ExporterIFCUtils.CreateGenericElementPropertySet(exporterIFC, familyInstance, wrapper); break; } case IFCExportType.ExportBuildingElementProxy: default: { bool isBuildingElementProxy = (exportType == IFCExportType.ExportBuildingElementProxy); if (!isBuildingElementProxy) { if (FamilyExporterUtil.IsDistributionControlElementSubType(exportType)) { IFCLabel controlElementId = IFCLabel.Create(); IFCAnyHandle localPlacementToUse; ElementId roomId = setter.UpdateRoomRelativeCoordinates(familyInstance, out localPlacementToUse); instanceHandle = file.CreateDistributionControlElement(instanceGUID, ownerHistory, instanceName, instanceDescription, instanceObjectType, localPlacement, rep, instanceElemId, controlElementId); if (roomId == ElementId.InvalidElementId) { wrapper.AddElement(instanceHandle, setter, extraParams, true); } else { exporterIFC.RelateSpatialElement(roomId, instanceHandle); wrapper.AddElement(instanceHandle, setter, extraParams, false); } OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, extraParams, exporterIFC, localPlacement, setter, wrapper); } else if (!instanceHandle.HasValue) { isBuildingElementProxy = true; } } if (isBuildingElementProxy) { IFCElementComposition proxyType = IFCElementComposition.Element; IFCAnyHandle localPlacementToUse; ElementId roomId = setter.UpdateRoomRelativeCoordinates(familyInstance, out localPlacementToUse); instanceHandle = file.CreateBuildingElementProxy(instanceGUID, ownerHistory, instanceName, instanceDescription, instanceObjectType, localPlacementToUse, rep, instanceElemId, proxyType); if (roomId == ElementId.InvalidElementId) { wrapper.AddElement(instanceHandle, setter, extraParams, true); } else { exporterIFC.RelateSpatialElement(roomId, instanceHandle); wrapper.AddElement(instanceHandle, setter, extraParams, false); } OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, extraParams, exporterIFC, localPlacement, setter, wrapper); } ExporterIFCUtils.CreateGenericElementPropertySet(exporterIFC, familyInstance, wrapper); break; } } if (instanceHandle.HasValue) { if (doorWindowInfo != null) { if (doorWindowInfo.GetOpening().HasValue) { IFCLabel relGUID = IFCLabel.CreateGUID(); file.CreateRelFillsElement(relGUID, ownerHistory, IFCLabel.Create(), IFCLabel.Create(), doorWindowInfo.GetOpening(), instanceHandle); } else if (doorWindowInfo.NeedsOpening) { bool added = doorWindowInfo.SetDelayedFamilyInstance(instanceHandle, localPlacement, doorWindowInfo.AssignedLevelId); if (added) exporterIFC.RegisterDoorWindowForOpeningUpdate(doorWindowInfo); else { // we need to fill a later opening. exporterIFC.RegisterDoorWindowForUncreatedOpening(familyInstance.Id, instanceHandle); } } } if (typeInfo.GetStyle().HasValue) exporterIFC.AddTypeRelation(typeInfo.GetStyle(), instanceHandle); } } }
/// <summary> /// Creates IFC room/space/area item, not include boundaries. /// </summary> /// <param name="exporterIFC"> /// The ExporterIFC object. /// </param> /// <param name="spatialElement"> /// The spatial element. /// </param> /// <param name="productWrapper"> /// The IFCProductWrapper. /// </param> /// <param name="setter"> /// The IFCPlacementSetter. /// </param> /// <returns> /// True if created successfully, false otherwise. /// </returns> static bool CreateIFCSpace(ExporterIFC exporterIFC, SpatialElement spatialElement, IFCProductWrapper productWrapper, IFCPlacementSetter setter) { IList<CurveLoop> curveLoops = null; try { SpatialElementBoundaryOptions options = ExporterIFCUtils.GetSpatialElementBoundaryOptions(exporterIFC, spatialElement); curveLoops = ExporterIFCUtils.GetRoomBoundaryAsCurveLoopArray(spatialElement, options, true); } catch (Autodesk.Revit.Exceptions.InvalidOperationException) { //Some spatial elements are not placed that have no boundary loops. Don't export them. return false; } Autodesk.Revit.DB.Document document = spatialElement.Document; ElementId levelId = spatialElement.Level != null ? spatialElement.Level.Id : ElementId.InvalidElementId; double scale = exporterIFC.LinearScale; ElementId catId = spatialElement.Category != null ? spatialElement.Category.Id : ElementId.InvalidElementId; double dArea = 0.0; Parameter param = spatialElement.get_Parameter(BuiltInParameter.ROOM_AREA); if (param != null) { dArea = param.AsDouble(); dArea *= (scale * scale); } IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(levelId); string strSpaceNumber = null; string strSpaceName = null; string strSpaceDesc = null; bool isArea = spatialElement is Area; if (!isArea) { Parameter paramRoomNum = spatialElement.get_Parameter(BuiltInParameter.ROOM_NUMBER); if (paramRoomNum != null) { strSpaceNumber = paramRoomNum.AsString(); } Parameter paramRoomName = spatialElement.get_Parameter(BuiltInParameter.ROOM_NAME); if (paramRoomName != null) { strSpaceName = paramRoomName.AsString(); } Parameter paramRoomComm = spatialElement.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS); if (paramRoomComm != null) { strSpaceDesc = paramRoomComm.AsString(); } } else { Element level = document.GetElement(levelId); if (level != null) { strSpaceNumber = level.Name + " GSA Design Gross Area"; } } string name = strSpaceNumber; string longName = strSpaceName; string desc = strSpaceDesc; IFCFile file = exporterIFC.GetFile(); IFCAnyHandle localPlacement = setter.GetPlacement(); ElementType elemType = document.GetElement(spatialElement.GetTypeId()) as ElementType; IFCInternalOrExternal internalOrExternal = CategoryUtil.IsElementExternal(spatialElement) ? IFCInternalOrExternal.External : IFCInternalOrExternal.Internal; double roomHeight = 0.0; roomHeight = GetHeight(spatialElement, scale, levelId, levelInfo); double bottomOffset = 0.0; Parameter paramBottomOffset = spatialElement.get_Parameter(BuiltInParameter.ROOM_LOWER_OFFSET); bottomOffset = paramBottomOffset != null ? paramBottomOffset.AsDouble() : 0.0; XYZ zDir = new XYZ(0, 0, 1); XYZ orig = new XYZ(0, 0, levelInfo.Elevation + bottomOffset); Plane plane = new Plane(zDir, orig); // room calculated as level offset. GeometryElement geomElem = null; if (spatialElement is Autodesk.Revit.DB.Architecture.Room) { Autodesk.Revit.DB.Architecture.Room room = spatialElement as Autodesk.Revit.DB.Architecture.Room; geomElem = room.ClosedShell; } else if (spatialElement is Autodesk.Revit.DB.Mechanical.Space) { Autodesk.Revit.DB.Mechanical.Space space = spatialElement as Autodesk.Revit.DB.Mechanical.Space; geomElem = space.ClosedShell; } IFCAnyHandle spaceHnd = null; using (IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData()) { extraParams.SetLocalPlacement(localPlacement); extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ; using (IFCTransaction transaction2 = new IFCTransaction(file)) { IFCAnyHandle repHnd = null; if (!ExporterCacheManager.ExportOptionsCache.Use2DRoomBoundaryForRoomVolumeCreation && geomElem != null) { BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true); bodyExporterOptions.TessellationLevel = BodyExporterOptions.BodyTessellationLevel.Coarse; repHnd = RepresentationUtil.CreateBRepProductDefinitionShape(spatialElement.Document.Application, exporterIFC, spatialElement, catId, geomElem, bodyExporterOptions, null, extraParams); if (IFCAnyHandleUtil.IsNullOrHasNoValue(repHnd)) extraParams.ClearOpenings(); } else { IFCAnyHandle shapeRep = ExtrusionExporter.CreateExtrudedSolidFromCurveLoop(exporterIFC, null, curveLoops, plane, zDir, roomHeight); if (IFCAnyHandleUtil.IsNullOrHasNoValue(shapeRep)) return false; IFCAnyHandle styledItemHnd = BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, document, shapeRep, ElementId.InvalidElementId); HashSet<IFCAnyHandle> bodyItems = new HashSet<IFCAnyHandle>(); bodyItems.Add(shapeRep); shapeRep = RepresentationUtil.CreateSweptSolidRep(exporterIFC, spatialElement, catId, exporterIFC.Get3DContextHandle("Body"), bodyItems, null); IList<IFCAnyHandle> shapeReps = new List<IFCAnyHandle>(); shapeReps.Add(shapeRep); repHnd = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, shapeReps); } extraParams.ScaledHeight = roomHeight; extraParams.ScaledArea = dArea; spaceHnd = IFCInstanceExporter.CreateSpace(file, ExporterIFCUtils.CreateGUID(spatialElement), exporterIFC.GetOwnerHistoryHandle(), NamingUtil.GetNameOverride(spatialElement, name), NamingUtil.GetDescriptionOverride(spatialElement, desc), NamingUtil.GetObjectTypeOverride(spatialElement, null), extraParams.GetLocalPlacement(), repHnd, longName, Toolkit.IFCElementComposition.Element , internalOrExternal, null); transaction2.Commit(); } productWrapper.AddSpace(spaceHnd, levelInfo, extraParams, true); } // Save room handle for later use/relationships ExporterCacheManager.SpatialElementHandleCache.Register(spatialElement.Id, spaceHnd); exporterIFC.RegisterSpatialElementHandle(spatialElement.Id, spaceHnd); if (!MathUtil.IsAlmostZero(dArea) && !(ExporterCacheManager.ExportOptionsCache.FileVersion == IFCVersion.IFCCOBIE)) { ExporterIFCUtils.CreatePreCOBIEGSAQuantities(exporterIFC, spaceHnd, "GSA Space Areas", (isArea ? "GSA Design Gross Area" : "GSA BIM Area"), dArea); } // Export BaseQuantities for SpatialElement if (ExporterCacheManager.ExportOptionsCache.ExportBaseQuantities && !(ExporterCacheManager.ExportOptionsCache.FileVersion == IFCVersion.IFCCOBIE)) { ExporterIFCUtils.CreateNonCOBIERoomQuantities(exporterIFC, spaceHnd, spatialElement, dArea, roomHeight); } // Export Classifications for SpatialElement for GSA/COBIE. if (ExporterCacheManager.ExportOptionsCache.FileVersion == IFCVersion.IFCCOBIE) { CreateCOBIESpaceClassifications(exporterIFC, file, spaceHnd, document.ProjectInformation, spatialElement); } return true; }