/// <summary> /// Exports a CeilingAndFloor element to IFC. /// </summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="floor">The floor element.</param> /// <param name="geometryElement">The geometry element.</param> /// <param name="productWrapper">The ProductWrapper.</param> public static void ExportCeilingAndFloorElement(ExporterIFC exporterIFC, CeilingAndFloor floorElement, GeometryElement geometryElement, ProductWrapper productWrapper) { if (geometryElement == null) { return; } // export parts or not bool exportParts = PartExporter.CanExportParts(floorElement); if (exportParts && !PartExporter.CanExportElementInPartExport(floorElement, floorElement.LevelId, false)) { return; } IFCFile file = exporterIFC.GetFile(); string ifcEnumType; IFCExportInfoPair exportType = ExporterUtil.GetExportType(exporterIFC, floorElement, out ifcEnumType); IFCAnyHandle type = null; MaterialLayerSetInfo layersetInfo = null; if (!ElementFilteringUtil.IsElementVisible(floorElement)) { return; } // Check the intended IFC entity or type name is in the exclude list specified in the UI Common.Enums.IFCEntityType elementClassTypeEnum; if (Enum.TryParse <Common.Enums.IFCEntityType>(exportType.ExportInstance.ToString(), out elementClassTypeEnum) || Enum.TryParse <Common.Enums.IFCEntityType>(exportType.ExportType.ToString(), out elementClassTypeEnum)) { if (ExporterCacheManager.ExportOptionsCache.IsElementInExcludeList(elementClassTypeEnum)) { return; } } Document doc = floorElement.Document; using (SubTransaction tempPartTransaction = new SubTransaction(doc)) { // For IFC4RV export, Floor will be split into its parts(temporarily) in order to export the floor by its parts bool exportByComponents = ExporterUtil.ShouldExportByComponents(floorElement, exportParts); using (IFCTransaction tr = new IFCTransaction(file)) { bool canExportAsContainerOrWithExtrusionAnalyzer = (!exportParts && (floorElement is Floor)); if (canExportAsContainerOrWithExtrusionAnalyzer) { // Try to export the Floor slab as a container. If that succeeds, we are done. // If we do export the floor as a container, it will take care of the local placement and transform there, so we need to leave // this out of the IFCTransformSetter and PlacementSetter scopes below, or else we'll get double transforms. IFCAnyHandle floorHnd = RoofExporter.ExportRoofOrFloorAsContainer(exporterIFC, floorElement, geometryElement, productWrapper); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(floorHnd)) { tr.Commit(); return; } } IList <IFCAnyHandle> slabHnds = new List <IFCAnyHandle>(); IList <IFCAnyHandle> brepSlabHnds = new List <IFCAnyHandle>(); IList <IFCAnyHandle> nonBrepSlabHnds = new List <IFCAnyHandle>(); IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle; using (IFCTransformSetter transformSetter = IFCTransformSetter.Create()) { // Check for containment override IFCAnyHandle overrideContainerHnd = null; ElementId overrideContainerId = ParameterUtil.OverrideContainmentParameter(exporterIFC, floorElement, out overrideContainerHnd); using (PlacementSetter placementSetter = PlacementSetter.Create(exporterIFC, floorElement, null, null, overrideContainerId, overrideContainerHnd)) { IFCAnyHandle localPlacement = placementSetter.LocalPlacement; // The routine ExportExtrudedSlabOpenings is called if exportedAsInternalExtrusion is true, and it requires having a valid level association. // Disable calling ExportSlabAsExtrusion if we can't handle potential openings. bool canExportAsInternalExtrusion = placementSetter.LevelInfo != null; bool exportedAsInternalExtrusion = false; ElementId catId = CategoryUtil.GetSafeCategoryId(floorElement); IList <IFCAnyHandle> prodReps = new List <IFCAnyHandle>(); IList <ShapeRepresentationType> repTypes = new List <ShapeRepresentationType>(); IList <IList <CurveLoop> > extrusionLoops = new List <IList <CurveLoop> >(); IList <IFCExtrusionCreationData> loopExtraParams = new List <IFCExtrusionCreationData>(); Plane floorPlane = GeometryUtil.CreateDefaultPlane(); IList <IFCAnyHandle> localPlacements = new List <IFCAnyHandle>(); if (canExportAsContainerOrWithExtrusionAnalyzer) { Floor floor = floorElement as Floor; // Next, try to use the ExtrusionAnalyzer for the limited cases it handles - 1 solid, no openings, end clippings only. // Also limited to cases with line and arc boundaries. // SolidMeshGeometryInfo solidMeshInfo = GeometryUtil.GetSplitSolidMeshGeometry(geometryElement); IList <Solid> solids = solidMeshInfo.GetSolids(); IList <Mesh> meshes = solidMeshInfo.GetMeshes(); IList <GeometryObject> gObjs = FamilyExporterUtil.RemoveInvisibleSolidsAndMeshes(floorElement.Document, exporterIFC, ref solids, ref meshes); if (solids.Count == 1 && meshes.Count == 0) { bool completelyClipped; // floorExtrusionDirection is set to (0, 0, -1) because extrusionAnalyzerFloorPlane is computed from the top face of the floor XYZ floorExtrusionDirection = new XYZ(0, 0, -1); XYZ modelOrigin = XYZ.Zero; XYZ floorOrigin = floor.GetVerticalProjectionPoint(modelOrigin, FloorFace.Top); if (floorOrigin == null) { // GetVerticalProjectionPoint may return null if FloorFace.Top is an edited face that doesn't // go through the Revit model origin. We'll try the midpoint of the bounding box instead. BoundingBoxXYZ boundingBox = floorElement.get_BoundingBox(null); modelOrigin = (boundingBox.Min + boundingBox.Max) / 2.0; floorOrigin = floor.GetVerticalProjectionPoint(modelOrigin, FloorFace.Top); } if (floorOrigin != null) { XYZ floorDir = floor.GetNormalAtVerticalProjectionPoint(floorOrigin, FloorFace.Top); Plane extrusionAnalyzerFloorBasePlane = GeometryUtil.CreatePlaneByNormalAtOrigin(floorDir); GenerateAdditionalInfo additionalInfo = GenerateAdditionalInfo.GenerateBody; additionalInfo |= ExporterCacheManager.ExportOptionsCache.ExportAs4 ? GenerateAdditionalInfo.GenerateFootprint : GenerateAdditionalInfo.None; // Skip generate body item for IFC4RV. It will be handled later in PartExporter.ExportHostPartAsShapeAspects() if (exportByComponents) { additionalInfo &= ~GenerateAdditionalInfo.GenerateBody; } HandleAndData floorAndProperties = ExtrusionExporter.CreateExtrusionWithClippingAndProperties(exporterIFC, floorElement, catId, solids[0], extrusionAnalyzerFloorBasePlane, floorOrigin, floorExtrusionDirection, null, out completelyClipped, addInfo: additionalInfo); if (completelyClipped) { return; } IList <IFCAnyHandle> representations = new List <IFCAnyHandle>(); if (floorAndProperties.Handle != null) { representations.Add(floorAndProperties.Handle); repTypes.Add(ShapeRepresentationType.SweptSolid); } // Footprint representation will only be exported in export to IFC4 if (((additionalInfo & GenerateAdditionalInfo.GenerateFootprint) != 0) && (floorAndProperties.FootprintInfo != null)) { IFCAnyHandle footprintShapeRep = floorAndProperties.FootprintInfo.CreateFootprintShapeRepresentation(exporterIFC); representations.Add(footprintShapeRep); } if (exportByComponents) { IFCAnyHandle prodRep = RepresentationUtil.CreateProductDefinitionShapeWithoutBodyRep(exporterIFC, floorElement, catId, geometryElement, representations); prodReps.Add(prodRep); } else if (representations.Count > 0 && floorAndProperties.Handle != null) // Only when at least the body rep exists will come here { IFCAnyHandle prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations); prodReps.Add(prodRep); } if (floorAndProperties.Data != null) { loopExtraParams.Add(floorAndProperties.Data); } } } } // Use internal routine as backup that handles openings. if (prodReps.Count == 0 && canExportAsInternalExtrusion && !exportByComponents) { exportedAsInternalExtrusion = ExporterIFCUtils.ExportSlabAsExtrusion(exporterIFC, floorElement, geometryElement, transformSetter, localPlacement, out localPlacements, out prodReps, out extrusionLoops, out loopExtraParams, floorPlane); PotentiallyFixPresentationLayerAssignment(floorElement, prodReps); for (int ii = 0; ii < prodReps.Count; ii++) { // all are extrusions repTypes.Add(ShapeRepresentationType.SweptSolid); // Footprint representation will only be exported in export to IFC4 if (ExporterCacheManager.ExportOptionsCache.ExportAs4) { if (extrusionLoops.Count > ii) { if (extrusionLoops[ii].Count > 0) { // Get the extrusion footprint using the first Curveloop. Transform needs to be obtained from the returned local placement Transform lcs = ExporterIFCUtils.GetUnscaledTransform(exporterIFC, localPlacements[ii]); IFCAnyHandle footprintGeomRepItem = GeometryUtil.CreateIFCCurveFromCurveLoop(exporterIFC, extrusionLoops[ii][0], lcs, floorPlane.Normal); IFCAnyHandle contextOfItemsFootprint = exporterIFC.Get3DContextHandle("FootPrint"); ISet <IFCAnyHandle> repItem = new HashSet <IFCAnyHandle>(); repItem.Add(footprintGeomRepItem); IFCAnyHandle footprintShapeRepresentation = RepresentationUtil.CreateBaseShapeRepresentation(exporterIFC, contextOfItemsFootprint, "FootPrint", "Curve2D", repItem); IList <IFCAnyHandle> reps = new List <IFCAnyHandle>(); reps.Add(footprintShapeRepresentation); IFCAnyHandleUtil.AddRepresentations(prodReps[ii], reps); } } } } } IFCAnyHandle prodDefHnd; if (prodReps.Count == 0) { if (exportByComponents) { prodDefHnd = RepresentationUtil.CreateProductDefinitionShapeWithoutBodyRep(exporterIFC, floorElement, catId, geometryElement, null); prodReps.Add(prodDefHnd); } else { using (IFCExtrusionCreationData ecData = new IFCExtrusionCreationData()) { // Brep representation using tesellation after ExportSlabAsExtrusion does not return prodReps BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true, ExportOptionsCache.ExportTessellationLevel.Medium); BodyData bodyData; prodDefHnd = RepresentationUtil.CreateAppropriateProductDefinitionShape(exporterIFC, floorElement, catId, geometryElement, bodyExporterOptions, null, ecData, out bodyData); if (IFCAnyHandleUtil.IsNullOrHasNoValue(prodDefHnd)) { ecData.ClearOpenings(); return; } prodReps.Add(prodDefHnd); repTypes.Add(bodyData.ShapeRepresentationType); } } } // Create the slab from either the extrusion or the BRep information. string ifcGUID = GUIDUtil.CreateGUID(floorElement); int numReps = exportParts ? 1 : prodReps.Count; // Deal with a couple of cases that have non-standard defaults. switch (exportType.ExportInstance) { case IFCEntityType.IfcCovering: exportType.ValidatedPredefinedType = IFCValidateEntry.GetValidIFCType <IFCCoveringType>(floorElement, ifcEnumType, "FLOORING"); break; case IFCEntityType.IfcSlab: bool isBaseSlab = false; AnalyticalModel analyticalModel = floorElement.GetAnalyticalModel(); if (analyticalModel != null) { AnalyzeAs slabFoundationType = analyticalModel.GetAnalyzeAs(); isBaseSlab = (slabFoundationType == AnalyzeAs.SlabOnGrade) || (slabFoundationType == AnalyzeAs.Mat); } exportType.ValidatedPredefinedType = IFCValidateEntry.GetValidIFCType <IFCSlabType>(floorElement, ifcEnumType, isBaseSlab ? "BASESLAB" : "FLOOR"); break; } for (int ii = 0; ii < numReps; ii++) { string ifcName = NamingUtil.GetNameOverride(floorElement, NamingUtil.GetIFCNamePlusIndex(floorElement, ii == 0 ? -1 : ii + 1)); string currentGUID = (ii == 0) ? ifcGUID : GUIDUtil.CreateGUID(); IFCAnyHandle localPlacementHnd = exportedAsInternalExtrusion ? localPlacements[ii] : localPlacement; IFCAnyHandle slabHnd = null; slabHnd = IFCInstanceExporter.CreateGenericIFCEntity(exportType, exporterIFC, floorElement, currentGUID, ownerHistory, localPlacementHnd, exportParts ? null : prodReps[ii]); if (IFCAnyHandleUtil.IsNullOrHasNoValue(slabHnd)) { return; } if (!string.IsNullOrEmpty(ifcName)) { IFCAnyHandleUtil.OverrideNameAttribute(slabHnd, ifcName); } // Pre IFC4 Slab does not have PredefinedType if (!string.IsNullOrEmpty(exportType.ValidatedPredefinedType) && !ExporterCacheManager.ExportOptionsCache.ExportAsOlderThanIFC4) { IFCAnyHandleUtil.SetAttribute(slabHnd, "PredefinedType", exportType.ValidatedPredefinedType, true); } if (exportParts && !ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView) { PartExporter.ExportHostPart(exporterIFC, floorElement, slabHnd, productWrapper, placementSetter, localPlacementHnd, null); } else if (exportByComponents) { IFCExtrusionCreationData partECData = new IFCExtrusionCreationData(); IFCAnyHandle hostShapeRepFromParts = PartExporter.ExportHostPartAsShapeAspects(exporterIFC, floorElement, prodReps[ii], productWrapper, placementSetter, localPlacement, ElementId.InvalidElementId, out layersetInfo, partECData); loopExtraParams.Add(partECData); } slabHnds.Add(slabHnd); // For IFC4RV, export of the geometry is already handled in PartExporter.ExportHostPartAsShapeAspects() if (!exportParts && !exportByComponents) { if (repTypes[ii] == ShapeRepresentationType.Brep || repTypes[ii] == ShapeRepresentationType.Tessellation) { brepSlabHnds.Add(slabHnd); } else { nonBrepSlabHnds.Add(slabHnd); } } } for (int ii = 0; ii < numReps; ii++) { IFCExtrusionCreationData loopExtraParam = ii < loopExtraParams.Count ? loopExtraParams[ii] : null; productWrapper.AddElement(floorElement, slabHnds[ii], placementSetter, loopExtraParam, true, exportType); type = ExporterUtil.CreateGenericTypeFromElement(floorElement, exportType, file, ownerHistory, exportType.ValidatedPredefinedType, productWrapper); ExporterCacheManager.TypeRelationsCache.Add(type, slabHnds[ii]); ExporterUtil.AddIntoComplexPropertyCache(slabHnds[ii], layersetInfo); } // This call to the native function appears to create Brep opening also when appropriate. But the creation of the IFC instances is not // controllable from the managed code. Therefore in some cases BRep geometry for Opening will still be exported even in the Reference View if (exportedAsInternalExtrusion) { ISet <IFCAnyHandle> oldCreatedObjects = productWrapper.GetAllObjects(); ExporterIFCUtils.ExportExtrudedSlabOpenings(exporterIFC, floorElement, placementSetter.LevelInfo, localPlacements[0], slabHnds, extrusionLoops, floorPlane, productWrapper.ToNative()); ISet <IFCAnyHandle> newCreatedObjects = productWrapper.GetAllObjects(); newCreatedObjects.ExceptWith(oldCreatedObjects); PotentiallyFixPresentationLayerAssignment(floorElement, newCreatedObjects); } } if (!exportParts) { if (ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView) { HostObjectExporter.ExportHostObjectMaterials(exporterIFC, floorElement, productWrapper.GetAnElement(), geometryElement, productWrapper, ElementId.InvalidElementId, Toolkit.IFCLayerSetDirection.Axis3, false, type); } else { if (nonBrepSlabHnds.Count > 0) { HostObjectExporter.ExportHostObjectMaterials(exporterIFC, floorElement, nonBrepSlabHnds, geometryElement, productWrapper, ElementId.InvalidElementId, Toolkit.IFCLayerSetDirection.Axis3, false, type); } if (brepSlabHnds.Count > 0) { HostObjectExporter.ExportHostObjectMaterials(exporterIFC, floorElement, brepSlabHnds, geometryElement, productWrapper, ElementId.InvalidElementId, Toolkit.IFCLayerSetDirection.Axis3, true, type); } } } } tr.Commit(); return; } } }
/// <summary> /// Exports a CeilingAndFloor element to IFC. /// </summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="floor">The floor element.</param> /// <param name="geometryElement">The geometry element.</param> /// <param name="productWrapper">The ProductWrapper.</param> public static void ExportCeilingAndFloorElement(ExporterIFC exporterIFC, CeilingAndFloor floorElement, GeometryElement geometryElement, ProductWrapper productWrapper) { if (geometryElement == null) { return; } // export parts or not bool exportParts = PartExporter.CanExportParts(floorElement); if (exportParts && !PartExporter.CanExportElementInPartExport(floorElement, floorElement.LevelId, false)) { return; } IFCFile file = exporterIFC.GetFile(); string ifcEnumType; IFCExportType exportType = ExporterUtil.GetExportType(exporterIFC, floorElement, out ifcEnumType); using (IFCTransaction tr = new IFCTransaction(file)) { bool canExportAsContainerOrWithExtrusionAnalyzer = (!exportParts && (floorElement is Floor)); IList <IFCAnyHandle> slabHnds = new List <IFCAnyHandle>(); IList <IFCAnyHandle> brepSlabHnds = new List <IFCAnyHandle>(); IList <IFCAnyHandle> nonBrepSlabHnds = new List <IFCAnyHandle>(); using (IFCTransformSetter transformSetter = IFCTransformSetter.Create()) { using (PlacementSetter placementSetter = PlacementSetter.Create(exporterIFC, floorElement)) { IFCAnyHandle localPlacement = placementSetter.LocalPlacement; IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle; // The routine ExportExtrudedSlabOpenings is called if exportedAsInternalExtrusion is true, and it requires having a valid level association. // Disable calling ExportSlabAsExtrusion if we can't handle potential openings. bool canExportAsInternalExtrusion = placementSetter.LevelInfo != null; bool exportedAsInternalExtrusion = false; ElementId catId = CategoryUtil.GetSafeCategoryId(floorElement); IList <IFCAnyHandle> prodReps = new List <IFCAnyHandle>(); IList <ShapeRepresentationType> repTypes = new List <ShapeRepresentationType>(); IList <IList <CurveLoop> > extrusionLoops = new List <IList <CurveLoop> >(); IList <IFCExtrusionCreationData> loopExtraParams = new List <IFCExtrusionCreationData>(); Plane floorPlane = GeometryUtil.CreateDefaultPlane(); IList <IFCAnyHandle> localPlacements = new List <IFCAnyHandle>(); if (canExportAsContainerOrWithExtrusionAnalyzer) { Floor floor = floorElement as Floor; // First, try to use the ExtrusionAnalyzer for the limited cases it handles - 1 solid, no openings, end clippings only. // Also limited to cases with line and arc boundaries. // SolidMeshGeometryInfo solidMeshInfo = GeometryUtil.GetSplitSolidMeshGeometry(geometryElement); IList <Solid> solids = solidMeshInfo.GetSolids(); IList <Mesh> meshes = solidMeshInfo.GetMeshes(); if (solids.Count == 1 && meshes.Count == 0) { bool completelyClipped; // floorExtrusionDirection is set to (0, 0, -1) because extrusionAnalyzerFloorPlane is computed from the top face of the floor XYZ floorExtrusionDirection = new XYZ(0, 0, -1); XYZ modelOrigin = XYZ.Zero; XYZ floorOrigin = floor.GetVerticalProjectionPoint(modelOrigin, FloorFace.Top); if (floorOrigin == null) { // GetVerticalProjectionPoint may return null if FloorFace.Top is an edited face that doesn't // go thruough te Revit model orgigin. We'll try the midpoint of the bounding box instead. BoundingBoxXYZ boundingBox = floorElement.get_BoundingBox(null); modelOrigin = (boundingBox.Min + boundingBox.Max) / 2.0; floorOrigin = floor.GetVerticalProjectionPoint(modelOrigin, FloorFace.Top); } if (floorOrigin != null) { XYZ floorDir = floor.GetNormalAtVerticalProjectionPoint(floorOrigin, FloorFace.Top); Plane extrusionAnalyzerFloorPlane = new Plane(floorDir, floorOrigin); HandleAndData floorAndProperties = ExtrusionExporter.CreateExtrusionWithClippingAndProperties(exporterIFC, floorElement, catId, solids[0], extrusionAnalyzerFloorPlane, floorExtrusionDirection, null, out completelyClipped); if (completelyClipped) { return; } if (floorAndProperties.Handle != null) { IList <IFCAnyHandle> representations = new List <IFCAnyHandle>(); representations.Add(floorAndProperties.Handle); IFCAnyHandle prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations); prodReps.Add(prodRep); repTypes.Add(ShapeRepresentationType.SweptSolid); if (floorAndProperties.Data != null) { loopExtraParams.Add(floorAndProperties.Data); } } } } } // Use internal routine as backup that handles openings. if (prodReps.Count == 0 && canExportAsInternalExtrusion) { exportedAsInternalExtrusion = ExporterIFCUtils.ExportSlabAsExtrusion(exporterIFC, floorElement, geometryElement, transformSetter, localPlacement, out localPlacements, out prodReps, out extrusionLoops, out loopExtraParams, floorPlane); for (int ii = 0; ii < prodReps.Count; ii++) { // all are extrusions repTypes.Add(ShapeRepresentationType.SweptSolid); } } if (prodReps.Count == 0) { using (IFCExtrusionCreationData ecData = new IFCExtrusionCreationData()) { BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true, ExportOptionsCache.ExportTessellationLevel.Medium); BodyData bodyData; IFCAnyHandle prodDefHnd = RepresentationUtil.CreateAppropriateProductDefinitionShape(exporterIFC, floorElement, catId, geometryElement, bodyExporterOptions, null, ecData, out bodyData); if (IFCAnyHandleUtil.IsNullOrHasNoValue(prodDefHnd)) { ecData.ClearOpenings(); return; } prodReps.Add(prodDefHnd); repTypes.Add(bodyData.ShapeRepresentationType); } } // Create the slab from either the extrusion or the BRep information. string ifcGUID = GUIDUtil.CreateGUID(floorElement); int numReps = exportParts ? 1 : prodReps.Count; string entityType = null; switch (exportType) { case IFCExportType.IfcFooting: if (ExporterCacheManager.ExportOptionsCache.ExportAs4) { entityType = IFCValidateEntry.GetValidIFCType <Revit.IFC.Export.Toolkit.IFC4.IFCFootingType>(floorElement, ifcEnumType, null); } else { entityType = IFCValidateEntry.GetValidIFCType <IFCFootingType>(floorElement, ifcEnumType, null); } break; case IFCExportType.IfcCovering: entityType = IFCValidateEntry.GetValidIFCType <IFCCoveringType>(floorElement, ifcEnumType, "FLOORING"); break; case IFCExportType.IfcRamp: if (ExporterCacheManager.ExportOptionsCache.ExportAs4) { entityType = IFCValidateEntry.GetValidIFCType <Revit.IFC.Export.Toolkit.IFC4.IFCRampType>(floorElement, ifcEnumType, null); } else { entityType = IFCValidateEntry.GetValidIFCType <IFCRampType>(floorElement, ifcEnumType, null); } break; default: bool isBaseSlab = false; AnalyticalModel analyticalModel = floorElement.GetAnalyticalModel(); if (analyticalModel != null) { AnalyzeAs slabFoundationType = analyticalModel.GetAnalyzeAs(); isBaseSlab = (slabFoundationType == AnalyzeAs.SlabOnGrade) || (slabFoundationType == AnalyzeAs.Mat); } entityType = IFCValidateEntry.GetValidIFCType <IFCSlabType>(floorElement, ifcEnumType, isBaseSlab ? "BASESLAB" : "FLOOR"); break; } for (int ii = 0; ii < numReps; ii++) { string ifcName = NamingUtil.GetNameOverride(floorElement, NamingUtil.GetIFCNamePlusIndex(floorElement, ii == 0 ? -1 : ii + 1)); string ifcDescription = NamingUtil.GetDescriptionOverride(floorElement, null); string ifcObjectType = NamingUtil.GetObjectTypeOverride(floorElement, exporterIFC.GetFamilyName()); string ifcTag = NamingUtil.GetTagOverride(floorElement, NamingUtil.CreateIFCElementId(floorElement)); string currentGUID = (ii == 0) ? ifcGUID : GUIDUtil.CreateGUID(); IFCAnyHandle localPlacementHnd = exportedAsInternalExtrusion ? localPlacements[ii] : localPlacement; IFCAnyHandle slabHnd = null; // TODO: replace with CreateGenericBuildingElement. switch (exportType) { case IFCExportType.IfcFooting: slabHnd = IFCInstanceExporter.CreateFooting(file, currentGUID, ownerHistory, ifcName, ifcDescription, ifcObjectType, localPlacementHnd, exportParts ? null : prodReps[ii], ifcTag, entityType); break; case IFCExportType.IfcCovering: slabHnd = IFCInstanceExporter.CreateCovering(file, currentGUID, ownerHistory, ifcName, ifcDescription, ifcObjectType, localPlacementHnd, exportParts ? null : prodReps[ii], ifcTag, entityType); break; case IFCExportType.IfcRamp: slabHnd = IFCInstanceExporter.CreateRamp(file, currentGUID, ownerHistory, ifcName, ifcDescription, ifcObjectType, localPlacementHnd, exportParts ? null : prodReps[ii], ifcTag, entityType); break; default: slabHnd = IFCInstanceExporter.CreateSlab(file, currentGUID, ownerHistory, ifcName, ifcDescription, ifcObjectType, localPlacementHnd, exportParts ? null : prodReps[ii], ifcTag, entityType); break; } if (IFCAnyHandleUtil.IsNullOrHasNoValue(slabHnd)) { return; } if (exportParts) { PartExporter.ExportHostPart(exporterIFC, floorElement, slabHnd, productWrapper, placementSetter, localPlacementHnd, null); } slabHnds.Add(slabHnd); if (!exportParts) { if (repTypes[ii] == ShapeRepresentationType.Brep) { brepSlabHnds.Add(slabHnd); } else { nonBrepSlabHnds.Add(slabHnd); } } } for (int ii = 0; ii < numReps; ii++) { IFCExtrusionCreationData loopExtraParam = ii < loopExtraParams.Count ? loopExtraParams[ii] : null; productWrapper.AddElement(floorElement, slabHnds[ii], placementSetter, loopExtraParam, true); } // This call to the native function appears to create Brep opening also when appropriate. But the creation of the IFC instances is not // controllable from the managed code. Therefore in some cases BRep geometry for Opening will still be exported even in the Reference View if (exportedAsInternalExtrusion) { ExporterIFCUtils.ExportExtrudedSlabOpenings(exporterIFC, floorElement, placementSetter.LevelInfo, localPlacements[0], slabHnds, extrusionLoops, floorPlane, productWrapper.ToNative()); } } if (!exportParts) { if (nonBrepSlabHnds.Count > 0) { HostObjectExporter.ExportHostObjectMaterials(exporterIFC, floorElement, nonBrepSlabHnds, geometryElement, productWrapper, ElementId.InvalidElementId, Toolkit.IFCLayerSetDirection.Axis3, false); } if (brepSlabHnds.Count > 0) { HostObjectExporter.ExportHostObjectMaterials(exporterIFC, floorElement, brepSlabHnds, geometryElement, productWrapper, ElementId.InvalidElementId, Toolkit.IFCLayerSetDirection.Axis3, true); } } } tr.Commit(); return; } }
/// <summary> /// Exports a geometry element to boundary representation. /// </summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="element">The element.</param> /// <param name="geometryElement">The geometry element.</param> /// <param name="exportBoundaryRep">True if to export boundary representation.</param> /// <param name="exportAsFacetation">True if to export the geometry as facetation.</param> /// <param name="bodyRep">Body representation.</param> /// <param name="boundaryRep">Boundary representation.</param> /// <returns>True if success, false if fail.</returns> public static bool ExportSurface(ExporterIFC exporterIFC, Element element, GeometryElement geometryElement, bool exportBoundaryRep, bool exportAsFacetation, ref IFCAnyHandle bodyRep, ref IFCAnyHandle boundaryRep) { if (geometryElement == null) { return(false); } IFCGeometryInfo ifcGeomInfo = null; Plane plane = GeometryUtil.CreateDefaultPlane(); XYZ projDir = new XYZ(0, 0, 1); double eps = element.Document.Application.VertexTolerance * exporterIFC.LinearScale; ifcGeomInfo = IFCGeometryInfo.CreateFaceGeometryInfo(exporterIFC, plane, projDir, eps, exportBoundaryRep); ExporterIFCUtils.CollectGeometryInfo(exporterIFC, ifcGeomInfo, geometryElement, XYZ.Zero, true); IFCFile file = exporterIFC.GetFile(); HashSet <IFCAnyHandle> faceSets = new HashSet <IFCAnyHandle>(); IList <ICollection <IFCAnyHandle> > faceList = ifcGeomInfo.GetFaces(); foreach (ICollection <IFCAnyHandle> faces in faceList) { // no faces, don't complain. if (faces.Count == 0) { continue; } HashSet <IFCAnyHandle> faceSet = new HashSet <IFCAnyHandle>(faces); faceSets.Add(IFCInstanceExporter.CreateConnectedFaceSet(file, faceSet)); } if (faceSets.Count == 0) { return(false); } IFCAnyHandle surface = IFCInstanceExporter.CreateFaceBasedSurfaceModel(file, faceSets); IList <IFCAnyHandle> surfaceItems = new List <IFCAnyHandle>(); surfaceItems.Add(surface); ElementId catId = CategoryUtil.GetSafeCategoryId(element); bodyRep = RepresentationUtil.CreateSurfaceRep(exporterIFC, element, catId, exporterIFC.Get3DContextHandle("Body"), surfaceItems, exportAsFacetation, bodyRep); if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep)) { return(false); } ICollection <IFCAnyHandle> boudaryRepresentations = ifcGeomInfo.GetRepresentations(); if (exportBoundaryRep && boudaryRepresentations.Count > 1) { boundaryRep = RepresentationUtil.CreateBoundaryRep(exporterIFC, element, catId, exporterIFC.Get3DContextHandle("Body"), boudaryRepresentations, boundaryRep); } return(true); }
/// <summary> /// Exports a geometry element to boundary representation. /// </summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="element">The element.</param> /// <param name="geometryElement">The geometry element.</param> /// <param name="exportBoundaryRep">True if to export boundary representation.</param> /// <param name="exportAsFacetation">True if to export the geometry as facetation.</param> /// <param name="bodyRep">Body representation.</param> /// <param name="boundaryRep">Boundary representation.</param> /// <returns>True if success, false if fail.</returns> public static bool ExportSurface(ExporterIFC exporterIFC, Element element, GeometryElement geometryElement, bool exportBoundaryRep, bool exportAsFacetation, ref IFCAnyHandle bodyRep, ref IFCAnyHandle boundaryRep) { if (geometryElement == null) { return(false); } IFCGeometryInfo ifcGeomInfo = null; Document doc = element.Document; Plane plane = GeometryUtil.CreateDefaultPlane(); XYZ projDir = new XYZ(0, 0, 1); double eps = UnitUtil.ScaleLength(doc.Application.VertexTolerance); ifcGeomInfo = IFCGeometryInfo.CreateFaceGeometryInfo(exporterIFC, plane, projDir, eps, exportBoundaryRep); ExporterIFCUtils.CollectGeometryInfo(exporterIFC, ifcGeomInfo, geometryElement, XYZ.Zero, true); IFCFile file = exporterIFC.GetFile(); IFCAnyHandle surface; // Use tessellated geometry for surface in IFC Reference View if (ExporterUtil.IsReferenceView()) { BodyExporterOptions options = new BodyExporterOptions(false); surface = BodyExporter.ExportBodyAsTriangulatedFaceSet(exporterIFC, element, options, geometryElement); } else { HashSet <IFCAnyHandle> faceSets = new HashSet <IFCAnyHandle>(); IList <ICollection <IFCAnyHandle> > faceList = ifcGeomInfo.GetFaces(); foreach (ICollection <IFCAnyHandle> faces in faceList) { // no faces, don't complain. if (faces.Count == 0) { continue; } HashSet <IFCAnyHandle> faceSet = new HashSet <IFCAnyHandle>(faces); faceSets.Add(IFCInstanceExporter.CreateConnectedFaceSet(file, faceSet)); } if (faceSets.Count == 0) { return(false); } surface = IFCInstanceExporter.CreateFaceBasedSurfaceModel(file, faceSets); } if (IFCAnyHandleUtil.IsNullOrHasNoValue(surface)) { return(false); } BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, doc, surface, BodyExporter.GetBestMaterialIdFromGeometryOrParameter(geometryElement, exporterIFC, element)); ISet <IFCAnyHandle> surfaceItems = new HashSet <IFCAnyHandle>(); surfaceItems.Add(surface); ElementId catId = CategoryUtil.GetSafeCategoryId(element); bodyRep = RepresentationUtil.CreateSurfaceRep(exporterIFC, element, catId, exporterIFC.Get3DContextHandle("Body"), surfaceItems, exportAsFacetation, bodyRep); if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep)) { return(false); } ICollection <IFCAnyHandle> boundaryRepresentations = ifcGeomInfo.GetRepresentations(); if (exportBoundaryRep && boundaryRepresentations.Count > 0) { HashSet <IFCAnyHandle> boundaryRepresentationSet = new HashSet <IFCAnyHandle>(); boundaryRepresentationSet.UnionWith(boundaryRepresentations); boundaryRep = RepresentationUtil.CreateBoundaryRep(exporterIFC, element, catId, exporterIFC.Get3DContextHandle("FootPrint"), boundaryRepresentationSet, boundaryRep); } return(true); }
/// <summary> /// Exports a floor to IFC slab. /// </summary> /// <param name="exporterIFC"> /// The ExporterIFC object. /// </param> /// <param name="floor"> /// The floor element. /// </param> /// <param name="geometryElement"> /// The geometry element. /// </param> /// <param name="ifcEnumType"> /// The string value represents the IFC type. /// </param> /// <param name="productWrapper"> /// The ProductWrapper. /// </param> /// <param name="exportParts"> /// Whether to export parts or not. /// </param> /// <returns> /// True if the floor is exported successfully, false otherwise. /// </returns> public static void ExportFloor(ExporterIFC exporterIFC, Element floorElement, GeometryElement geometryElement, string ifcEnumType, ProductWrapper productWrapper, bool exportParts) { if (geometryElement == null) { return; } IFCFile file = exporterIFC.GetFile(); IList <IFCAnyHandle> slabHnds = new List <IFCAnyHandle>(); IList <IFCAnyHandle> brepSlabHnds = new List <IFCAnyHandle>(); IList <IFCAnyHandle> nonBrepSlabHnds = new List <IFCAnyHandle>(); using (IFCTransaction tr = new IFCTransaction(file)) { using (IFCTransformSetter transformSetter = IFCTransformSetter.Create()) { using (IFCPlacementSetter placementSetter = IFCPlacementSetter.Create(exporterIFC, floorElement, null, null, ExporterUtil.GetBaseLevelIdForElement(floorElement))) { IFCAnyHandle localPlacement = placementSetter.GetPlacement(); IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle(); bool exportedAsInternalExtrusion = false; double scale = exporterIFC.LinearScale; ElementId catId = CategoryUtil.GetSafeCategoryId(floorElement); IList <IFCAnyHandle> prodReps = new List <IFCAnyHandle>(); IList <ShapeRepresentationType> repTypes = new List <ShapeRepresentationType>(); IList <IList <CurveLoop> > extrusionLoops = new List <IList <CurveLoop> >(); IList <IFCExtrusionCreationData> loopExtraParams = new List <IFCExtrusionCreationData>(); Plane floorPlane = GeometryUtil.CreateDefaultPlane(); IList <IFCAnyHandle> localPlacements = new List <IFCAnyHandle>(); if (!exportParts) { // First, try to use the ExtrusionAnalyzer for the limited cases it handles - 1 solid, no openings, end clippings only. // Also limited to cases with line and arc boundaries. // if (floorElement is Floor) { Floor floor = floorElement as Floor; SolidMeshGeometryInfo solidMeshInfo = GeometryUtil.GetSplitSolidMeshGeometry(geometryElement); IList <Solid> solids = solidMeshInfo.GetSolids(); IList <Mesh> meshes = solidMeshInfo.GetMeshes(); if (solids.Count == 1 && meshes.Count == 0) { bool completelyClipped; XYZ floorExtrusionDirection = new XYZ(0, 0, -1); XYZ modelOrigin = XYZ.Zero; XYZ floorOrigin = floor.GetVerticalProjectionPoint(modelOrigin, FloorFace.Top); if (floorOrigin == null) { // GetVerticalProjectionPoint may return null if FloorFace.Top is an edited face that doesn't // go thruough te Revit model orgigin. We'll try the midpoint of the bounding box instead. BoundingBoxXYZ boundingBox = floor.get_BoundingBox(null); modelOrigin = (boundingBox.Min + boundingBox.Max) / 2.0; floorOrigin = floor.GetVerticalProjectionPoint(modelOrigin, FloorFace.Top); } if (floorOrigin != null) { XYZ floorDir = floor.GetNormalAtVerticalProjectionPoint(floorOrigin, FloorFace.Top); Plane extrusionAnalyzerFloorPlane = new Plane(floorDir, floorOrigin); HandleAndData floorAndProperties = ExtrusionExporter.CreateExtrusionWithClippingAndProperties(exporterIFC, floor, catId, solids[0], extrusionAnalyzerFloorPlane, floorExtrusionDirection, null, out completelyClipped); if (completelyClipped) { return; } if (floorAndProperties.Handle != null) { IList <IFCAnyHandle> representations = new List <IFCAnyHandle>(); representations.Add(floorAndProperties.Handle); IFCAnyHandle prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations); prodReps.Add(prodRep); repTypes.Add(ShapeRepresentationType.SweptSolid); if (floorAndProperties.Data != null) { loopExtraParams.Add(floorAndProperties.Data); } } } } } // Use internal routine as backup that handles openings. if (prodReps.Count == 0) { exportedAsInternalExtrusion = ExporterIFCUtils.ExportSlabAsExtrusion(exporterIFC, floorElement, geometryElement, transformSetter, localPlacement, out localPlacements, out prodReps, out extrusionLoops, out loopExtraParams, floorPlane); for (int ii = 0; ii < prodReps.Count; ii++) { // all are extrusions repTypes.Add(ShapeRepresentationType.SweptSolid); } } if (prodReps.Count == 0) { using (IFCExtrusionCreationData ecData = new IFCExtrusionCreationData()) { BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true); bodyExporterOptions.TessellationLevel = BodyExporter.GetTessellationLevel(); BodyData bodyData; IFCAnyHandle prodDefHnd = RepresentationUtil.CreateAppropriateProductDefinitionShape(exporterIFC, floorElement, catId, geometryElement, bodyExporterOptions, null, ecData, out bodyData); if (IFCAnyHandleUtil.IsNullOrHasNoValue(prodDefHnd)) { ecData.ClearOpenings(); return; } prodReps.Add(prodDefHnd); repTypes.Add(bodyData.ShapeRepresentationType); } } } // Create the slab from either the extrusion or the BRep information. string ifcGUID = GUIDUtil.CreateGUID(floorElement); int numReps = exportParts ? 1 : prodReps.Count; // Allow export as IfcSlab or IfcFooting. Ignore altIfcEnumType value; use value passed in. string altIfcEnumType; IFCExportType exportAs = ExporterUtil.GetExportType(exporterIFC, floorElement, out altIfcEnumType); bool exportAsFooting = (exportAs == IFCExportType.ExportFooting); IFCFootingType?footingType = null; IFCSlabType? slabType = null; if (exportAsFooting) { footingType = FootingExporter.GetIFCFootingType(ifcEnumType); } else { slabType = GetIFCSlabType(ifcEnumType); } for (int ii = 0; ii < numReps; ii++) { string ifcName = NamingUtil.GetNameOverride(floorElement, NamingUtil.GetIFCNamePlusIndex(floorElement, ii == 0 ? -1 : ii + 1)); string ifcDescription = NamingUtil.GetDescriptionOverride(floorElement, null); string ifcObjectType = NamingUtil.GetObjectTypeOverride(floorElement, exporterIFC.GetFamilyName()); string ifcTag = NamingUtil.GetTagOverride(floorElement, NamingUtil.CreateIFCElementId(floorElement)); string currentGUID = (ii == 0) ? ifcGUID : GUIDUtil.CreateGUID(); IFCAnyHandle localPlacementHnd = exportedAsInternalExtrusion ? localPlacements[ii] : localPlacement; IFCAnyHandle slabHnd = null; if (exportAsFooting) { slabHnd = IFCInstanceExporter.CreateFooting(file, currentGUID, ownerHistory, ifcName, ifcDescription, ifcObjectType, localPlacementHnd, exportParts ? null : prodReps[ii], ifcTag, footingType.Value); } else { slabHnd = IFCInstanceExporter.CreateSlab(file, currentGUID, ownerHistory, ifcName, ifcDescription, ifcObjectType, localPlacementHnd, exportParts ? null : prodReps[ii], ifcTag, slabType.Value); } if (IFCAnyHandleUtil.IsNullOrHasNoValue(slabHnd)) { return; } if (exportParts) { PartExporter.ExportHostPart(exporterIFC, floorElement, slabHnd, productWrapper, placementSetter, localPlacementHnd, null); } slabHnds.Add(slabHnd); if (!exportParts) { if (repTypes[ii] == ShapeRepresentationType.Brep) { brepSlabHnds.Add(slabHnd); } else { nonBrepSlabHnds.Add(slabHnd); } } } for (int ii = 0; ii < numReps; ii++) { IFCExtrusionCreationData loopExtraParam = ii < loopExtraParams.Count ? loopExtraParams[ii] : null; productWrapper.AddElement(floorElement, slabHnds[ii], placementSetter, loopExtraParam, true); } if (exportedAsInternalExtrusion) { ExporterIFCUtils.ExportExtrudedSlabOpenings(exporterIFC, floorElement, placementSetter, localPlacements[0], slabHnds, extrusionLoops, floorPlane, productWrapper.ToNative()); } } if (!exportParts) { if (floorElement is HostObject) { HostObject hostObject = floorElement as HostObject; if (nonBrepSlabHnds.Count > 0) { HostObjectExporter.ExportHostObjectMaterials(exporterIFC, hostObject, nonBrepSlabHnds, geometryElement, productWrapper, ElementId.InvalidElementId, Toolkit.IFCLayerSetDirection.Axis3, false); } if (brepSlabHnds.Count > 0) { HostObjectExporter.ExportHostObjectMaterials(exporterIFC, hostObject, brepSlabHnds, geometryElement, productWrapper, ElementId.InvalidElementId, Toolkit.IFCLayerSetDirection.Axis3, true); } } else if (floorElement is FamilyInstance && slabHnds.Count > 0) { ElementId matId = BodyExporter.GetBestMaterialIdFromGeometryOrParameter(geometryElement, exporterIFC, floorElement); Document doc = floorElement.Document; foreach (IFCAnyHandle slabHnd in slabHnds) { CategoryUtil.CreateMaterialAssociation(exporterIFC, slabHnd, matId); } } } } tr.Commit(); return; } }
/// <summary> /// Exports a floor to IFC slab. /// </summary> /// <param name="exporterIFC"> /// The ExporterIFC object. /// </param> /// <param name="floor"> /// The floor element. /// </param> /// <param name="geometryElement"> /// The geometry element. /// </param> /// <param name="ifcEnumType"> /// The string value represents the IFC type. /// </param> /// <param name="productWrapper"> /// The IFCProductWrapper. /// </param> /// <param name="exportParts"> /// Whether to export parts or not. /// </param> /// <returns> /// True if the floor is exported successfully, false otherwise. /// </returns> public static void ExportFloor(ExporterIFC exporterIFC, Element floorElement, GeometryElement geometryElement, string ifcEnumType, IFCProductWrapper productWrapper, bool exportParts) { if (geometryElement == null) { return; } IFCFile file = exporterIFC.GetFile(); IList <IFCAnyHandle> slabHnds = new List <IFCAnyHandle>(); using (IFCTransaction tr = new IFCTransaction(file)) { using (IFCTransformSetter transformSetter = IFCTransformSetter.Create()) { using (IFCPlacementSetter placementSetter = IFCPlacementSetter.Create(exporterIFC, floorElement)) { IFCAnyHandle localPlacement = placementSetter.GetPlacement(); IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle(); bool exportedAsInternalExtrusion = false; double scale = exporterIFC.LinearScale; ElementId catId = CategoryUtil.GetSafeCategoryId(floorElement); IList <IFCAnyHandle> reps = new List <IFCAnyHandle>(); IList <IList <CurveLoop> > extrusionLoops = new List <IList <CurveLoop> >(); IList <IFCExtrusionCreationData> loopExtraParams = new List <IFCExtrusionCreationData>(); Plane floorPlane = GeometryUtil.CreateDefaultPlane(); IList <IFCAnyHandle> localPlacements = new List <IFCAnyHandle>(); if (!exportParts) { // First, try to use the ExtrusionAnalyzer for the limited cases it handles - 1 solid, no openings, end clippings only. // Also limited to cases with line and arc boundaries. // if (floorElement is Floor) { Floor floor = floorElement as Floor; SolidMeshGeometryInfo solidMeshInfo = GeometryUtil.GetSolidMeshGeometry(geometryElement, Transform.Identity); IList <Solid> solids = solidMeshInfo.GetSolids(); IList <Mesh> meshes = solidMeshInfo.GetMeshes(); if (solids.Count == 1 && meshes.Count == 0) { IList <Solid> splitVolumes = SolidUtils.SplitVolumes(solids[0]); if (splitVolumes.Count == 1) { bool completelyClipped; XYZ floorExtrusionDirection = new XYZ(0, 0, -1); XYZ modelOrigin = XYZ.Zero; XYZ floorOrigin = floor.GetVerticalProjectionPoint(modelOrigin, FloorFace.Top); if (floorOrigin == null) { // GetVerticalProjectionPoint may return null if FloorFace.Top is an edited face that doesn't // go thruough te Revit model orgigin. We'll try the midpoint of the bounding box instead. BoundingBoxXYZ boundingBox = floor.get_BoundingBox(null); modelOrigin = (boundingBox.Min + boundingBox.Max) / 2.0; floorOrigin = floor.GetVerticalProjectionPoint(modelOrigin, FloorFace.Top); } if (floorOrigin != null) { XYZ floorDir = floor.GetNormalAtVerticalProjectionPoint(floorOrigin, FloorFace.Top); Plane extrusionAnalyzerFloorPlane = new Plane(floorDir, floorOrigin); HandleAndData floorAndProperties = ExtrusionExporter.CreateExtrusionWithClippingAndProperties(exporterIFC, floor, catId, solids[0], extrusionAnalyzerFloorPlane, floorExtrusionDirection, null, out completelyClipped); if (completelyClipped) { return; } if (floorAndProperties.Handle != null) { IList <IFCAnyHandle> representations = new List <IFCAnyHandle>(); representations.Add(floorAndProperties.Handle); IFCAnyHandle prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations); reps.Add(prodRep); if (floorAndProperties.Data != null) { loopExtraParams.Add(floorAndProperties.Data); } } } } } } // Use internal routine as backup that handles openings. if (reps.Count == 0) { exportedAsInternalExtrusion = ExporterIFCUtils.ExportSlabAsExtrusion(exporterIFC, floorElement, geometryElement, transformSetter, localPlacement, out localPlacements, out reps, out extrusionLoops, out loopExtraParams, floorPlane); } if (reps.Count == 0) { using (IFCExtrusionCreationData ecData = new IFCExtrusionCreationData()) { BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true); bodyExporterOptions.TessellationLevel = BodyExporterOptions.BodyTessellationLevel.Coarse; IFCAnyHandle prodDefHnd = RepresentationUtil.CreateBRepProductDefinitionShape(floorElement.Document.Application, exporterIFC, floorElement, catId, geometryElement, bodyExporterOptions, null, ecData); if (IFCAnyHandleUtil.IsNullOrHasNoValue(prodDefHnd)) { ecData.ClearOpenings(); return; } reps.Add(prodDefHnd); } } } // Create the slab from either the extrusion or the BRep information. string ifcGUID = ExporterIFCUtils.CreateGUID(floorElement); int numReps = exportParts ? 1 : reps.Count; for (int ii = 0; ii < numReps; ii++) { string ifcName = NamingUtil.GetNameOverride(floorElement, NamingUtil.CreateIFCName(exporterIFC, ii == 0 ? -1 : ii + 1)); string ifcDescription = NamingUtil.GetDescriptionOverride(floorElement, null); string ifcObjectType = NamingUtil.GetObjectTypeOverride(floorElement, exporterIFC.GetFamilyName()); string ifcElemId = NamingUtil.CreateIFCElementId(floorElement); string currentGUID = (ii == 0) ? ifcGUID : ExporterIFCUtils.CreateGUID(); IFCAnyHandle localPlacementHnd = exportedAsInternalExtrusion ? localPlacements[ii] : localPlacement; IFCSlabType slabType = GetIFCSlabType(ifcEnumType); IFCAnyHandle slabHnd = IFCInstanceExporter.CreateSlab(file, currentGUID, ownerHistory, ifcName, ifcDescription, ifcObjectType, localPlacementHnd, exportParts ? null : reps[ii], ifcElemId, slabType); if (IFCAnyHandleUtil.IsNullOrHasNoValue(slabHnd)) { return; } if (exportParts) { PartExporter.ExportHostPart(exporterIFC, floorElement, slabHnd, productWrapper, placementSetter, localPlacementHnd, null); } slabHnds.Add(slabHnd); } bool associateElementToLevel = LevelUtil.AssociateElementToLevel(floorElement); for (int ii = 0; ii < numReps; ii++) { IFCExtrusionCreationData loopExtraParam = ii < loopExtraParams.Count ? loopExtraParams[ii] : null; productWrapper.AddElement(slabHnds[ii], placementSetter, loopExtraParam, associateElementToLevel); } if (exportedAsInternalExtrusion) { ExporterIFCUtils.ExportExtrudedSlabOpenings(exporterIFC, floorElement, placementSetter, localPlacements[0], slabHnds, extrusionLoops, floorPlane, productWrapper); } PropertyUtil.CreateInternalRevitPropertySets(exporterIFC, floorElement, productWrapper); } if (!exportParts) { HostObjectExporter.ExportHostObjectMaterials(exporterIFC, floorElement as HostObject, slabHnds, geometryElement, productWrapper, ElementId.InvalidElementId, Toolkit.IFCLayerSetDirection.Axis3); } } tr.Commit(); return; } }
/// <summary> /// Exports a generic element as an IfcSlab.</summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="floor">The floor element.</param> /// <param name="geometryElement">The geometry element.</param> /// <param name="ifcEnumType">The string value represents the IFC type.</param> /// <param name="productWrapper">The ProductWrapper.</param> /// <returns>True if the floor is exported successfully, false otherwise.</returns> public static void ExportGenericSlab(ExporterIFC exporterIFC, Element slabElement, GeometryElement geometryElement, string ifcEnumType, ProductWrapper productWrapper) { if (geometryElement == null) { return; } bool exportParts = PartExporter.CanExportParts(slabElement); IFCFile file = exporterIFC.GetFile(); IList <IFCAnyHandle> slabHnds = new List <IFCAnyHandle>(); IList <IFCAnyHandle> brepSlabHnds = new List <IFCAnyHandle>(); IList <IFCAnyHandle> nonBrepSlabHnds = new List <IFCAnyHandle>(); using (IFCTransaction tr = new IFCTransaction(file)) { using (IFCTransformSetter transformSetter = IFCTransformSetter.Create()) { using (PlacementSetter placementSetter = PlacementSetter.Create(exporterIFC, slabElement)) { IFCAnyHandle localPlacement = placementSetter.LocalPlacement; IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle(); bool exportedAsInternalExtrusion = false; ElementId catId = CategoryUtil.GetSafeCategoryId(slabElement); IList <IFCAnyHandle> prodReps = new List <IFCAnyHandle>(); IList <ShapeRepresentationType> repTypes = new List <ShapeRepresentationType>(); IList <IList <CurveLoop> > extrusionLoops = new List <IList <CurveLoop> >(); IList <IFCExtrusionCreationData> loopExtraParams = new List <IFCExtrusionCreationData>(); Plane floorPlane = GeometryUtil.CreateDefaultPlane(); IList <IFCAnyHandle> localPlacements = new List <IFCAnyHandle>(); using (IFCExtrusionCreationData ecData = new IFCExtrusionCreationData()) { BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true); bodyExporterOptions.TessellationLevel = BodyExporter.GetTessellationLevel(); BodyData bodyData; IFCAnyHandle prodDefHnd = RepresentationUtil.CreateAppropriateProductDefinitionShape(exporterIFC, slabElement, catId, geometryElement, bodyExporterOptions, null, ecData, out bodyData); if (IFCAnyHandleUtil.IsNullOrHasNoValue(prodDefHnd)) { ecData.ClearOpenings(); return; } prodReps.Add(prodDefHnd); repTypes.Add(bodyData.ShapeRepresentationType); } // Create the slab from either the extrusion or the BRep information. string ifcGUID = GUIDUtil.CreateGUID(slabElement); int numReps = exportParts ? 1 : prodReps.Count; string entityType = IFCValidateEntry.GetValidIFCType <IFCSlabType>(slabElement, ifcEnumType, "FLOOR"); for (int ii = 0; ii < numReps; ii++) { string ifcName = NamingUtil.GetNameOverride(slabElement, NamingUtil.GetIFCNamePlusIndex(slabElement, ii == 0 ? -1 : ii + 1)); string ifcDescription = NamingUtil.GetDescriptionOverride(slabElement, null); string ifcObjectType = NamingUtil.GetObjectTypeOverride(slabElement, exporterIFC.GetFamilyName()); string ifcTag = NamingUtil.GetTagOverride(slabElement, NamingUtil.CreateIFCElementId(slabElement)); string currentGUID = (ii == 0) ? ifcGUID : GUIDUtil.CreateGUID(); IFCAnyHandle localPlacementHnd = exportedAsInternalExtrusion ? localPlacements[ii] : localPlacement; IFCAnyHandle slabHnd = IFCInstanceExporter.CreateSlab(file, currentGUID, ownerHistory, ifcName, ifcDescription, ifcObjectType, localPlacementHnd, exportParts ? null : prodReps[ii], ifcTag, entityType); if (IFCAnyHandleUtil.IsNullOrHasNoValue(slabHnd)) { return; } if (exportParts) { PartExporter.ExportHostPart(exporterIFC, slabElement, slabHnd, productWrapper, placementSetter, localPlacementHnd, null); } slabHnds.Add(slabHnd); if (!exportParts) { if (repTypes[ii] == ShapeRepresentationType.Brep) { brepSlabHnds.Add(slabHnd); } else { nonBrepSlabHnds.Add(slabHnd); } } } for (int ii = 0; ii < numReps; ii++) { IFCExtrusionCreationData loopExtraParam = ii < loopExtraParams.Count ? loopExtraParams[ii] : null; productWrapper.AddElement(slabElement, slabHnds[ii], placementSetter, loopExtraParam, true); } if (exportedAsInternalExtrusion) { ExporterIFCUtils.ExportExtrudedSlabOpenings(exporterIFC, slabElement, placementSetter.LevelInfo, localPlacements[0], slabHnds, extrusionLoops, floorPlane, productWrapper.ToNative()); } } if (!exportParts) { if (slabElement is HostObject) { HostObject hostObject = slabElement as HostObject; if (nonBrepSlabHnds.Count > 0) { HostObjectExporter.ExportHostObjectMaterials(exporterIFC, hostObject, nonBrepSlabHnds, geometryElement, productWrapper, ElementId.InvalidElementId, Toolkit.IFCLayerSetDirection.Axis3, false); } if (brepSlabHnds.Count > 0) { HostObjectExporter.ExportHostObjectMaterials(exporterIFC, hostObject, brepSlabHnds, geometryElement, productWrapper, ElementId.InvalidElementId, Toolkit.IFCLayerSetDirection.Axis3, true); } } else if (slabElement is FamilyInstance && slabHnds.Count > 0) { ElementId matId = BodyExporter.GetBestMaterialIdFromGeometryOrParameter(geometryElement, exporterIFC, slabElement); Document doc = slabElement.Document; foreach (IFCAnyHandle slabHnd in slabHnds) { CategoryUtil.CreateMaterialAssociation(exporterIFC, slabHnd, matId); } } } } tr.Commit(); return; } }
/// <summary> /// Exports a CeilingAndFloor element to IFC. /// </summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="floor">The floor element.</param> /// <param name="geometryElement">The geometry element.</param> /// <param name="productWrapper">The ProductWrapper.</param> public static void ExportCeilingAndFloorElement(ExporterIFC exporterIFC, CeilingAndFloor floorElement, GeometryElement geometryElement, ProductWrapper productWrapper) { if (geometryElement == null) { return; } // export parts or not bool exportParts = PartExporter.CanExportParts(floorElement); if (exportParts && !PartExporter.CanExportElementInPartExport(floorElement, floorElement.LevelId, false)) { return; } IFCFile file = exporterIFC.GetFile(); string ifcEnumType; IFCExportType exportType = ExporterUtil.GetExportType(exporterIFC, floorElement, out ifcEnumType); // Check the intended IFC entity or type name is in the exclude list specified in the UI Common.Enums.IFCEntityType elementClassTypeEnum; if (Enum.TryParse <Common.Enums.IFCEntityType>(exportType.ToString(), out elementClassTypeEnum)) { if (ExporterCacheManager.ExportOptionsCache.IsElementInExcludeList(elementClassTypeEnum)) { return; } } using (IFCTransaction tr = new IFCTransaction(file)) { bool canExportAsContainerOrWithExtrusionAnalyzer = (!exportParts && (floorElement is Floor)); if (canExportAsContainerOrWithExtrusionAnalyzer) { // Try to export the Floor slab as a container. If that succeeds, we are done. // If we do export the floor as a container, it will take care of the local placement and transform there, so we need to leave // this out of the IFCTransformSetter and PlacementSetter scopes below, or else we'll get double transforms. IFCAnyHandle floorHnd = RoofExporter.ExportRoofOrFloorAsContainer(exporterIFC, ifcEnumType, floorElement, geometryElement, productWrapper); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(floorHnd)) { tr.Commit(); return; } } IList <IFCAnyHandle> slabHnds = new List <IFCAnyHandle>(); IList <IFCAnyHandle> brepSlabHnds = new List <IFCAnyHandle>(); IList <IFCAnyHandle> nonBrepSlabHnds = new List <IFCAnyHandle>(); using (IFCTransformSetter transformSetter = IFCTransformSetter.Create()) { using (PlacementSetter placementSetter = PlacementSetter.Create(exporterIFC, floorElement)) { IFCAnyHandle localPlacement = placementSetter.LocalPlacement; IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle; // The routine ExportExtrudedSlabOpenings is called if exportedAsInternalExtrusion is true, and it requires having a valid level association. // Disable calling ExportSlabAsExtrusion if we can't handle potential openings. bool canExportAsInternalExtrusion = placementSetter.LevelInfo != null; bool exportedAsInternalExtrusion = false; ElementId catId = CategoryUtil.GetSafeCategoryId(floorElement); IList <IFCAnyHandle> prodReps = new List <IFCAnyHandle>(); IList <ShapeRepresentationType> repTypes = new List <ShapeRepresentationType>(); IList <IList <CurveLoop> > extrusionLoops = new List <IList <CurveLoop> >(); IList <IFCExtrusionCreationData> loopExtraParams = new List <IFCExtrusionCreationData>(); Plane floorPlane = GeometryUtil.CreateDefaultPlane(); IList <IFCAnyHandle> localPlacements = new List <IFCAnyHandle>(); if (canExportAsContainerOrWithExtrusionAnalyzer) { Floor floor = floorElement as Floor; // Next, try to use the ExtrusionAnalyzer for the limited cases it handles - 1 solid, no openings, end clippings only. // Also limited to cases with line and arc boundaries. // SolidMeshGeometryInfo solidMeshInfo = GeometryUtil.GetSplitSolidMeshGeometry(geometryElement); IList <Solid> solids = solidMeshInfo.GetSolids(); IList <Mesh> meshes = solidMeshInfo.GetMeshes(); if (solids.Count == 1 && meshes.Count == 0) { bool completelyClipped; // floorExtrusionDirection is set to (0, 0, -1) because extrusionAnalyzerFloorPlane is computed from the top face of the floor XYZ floorExtrusionDirection = new XYZ(0, 0, -1); XYZ modelOrigin = XYZ.Zero; XYZ floorOrigin = floor.GetVerticalProjectionPoint(modelOrigin, FloorFace.Top); if (floorOrigin == null) { // GetVerticalProjectionPoint may return null if FloorFace.Top is an edited face that doesn't // go through the Revit model origin. We'll try the midpoint of the bounding box instead. BoundingBoxXYZ boundingBox = floorElement.get_BoundingBox(null); modelOrigin = (boundingBox.Min + boundingBox.Max) / 2.0; floorOrigin = floor.GetVerticalProjectionPoint(modelOrigin, FloorFace.Top); } if (floorOrigin != null) { XYZ floorDir = floor.GetNormalAtVerticalProjectionPoint(floorOrigin, FloorFace.Top); Plane extrusionAnalyzerFloorBasePlane = GeometryUtil.CreatePlaneByNormalAtOrigin(floorDir); GenerateAdditionalInfo additionalInfo = ExporterCacheManager.ExportOptionsCache.ExportAs4 ? GenerateAdditionalInfo.GenerateFootprint : GenerateAdditionalInfo.None; HandleAndData floorAndProperties = ExtrusionExporter.CreateExtrusionWithClippingAndProperties(exporterIFC, floorElement, catId, solids[0], extrusionAnalyzerFloorBasePlane, floorOrigin, floorExtrusionDirection, null, out completelyClipped, addInfo: additionalInfo); if (completelyClipped) { return; } if (floorAndProperties.Handle != null) { IList <IFCAnyHandle> representations = new List <IFCAnyHandle>(); representations.Add(floorAndProperties.Handle); // Footprint representation will only be exported in export to IFC4 if (((additionalInfo & GenerateAdditionalInfo.GenerateFootprint) != 0) && (floorAndProperties.FootprintInfo != null)) { if (!(IFCAnyHandleUtil.IsNullOrHasNoValue(floorAndProperties.FootprintInfo.FootPrintHandle))) { representations.Add(floorAndProperties.FootprintInfo.FootPrintHandle); } } IFCAnyHandle prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations); prodReps.Add(prodRep); repTypes.Add(ShapeRepresentationType.SweptSolid); if (floorAndProperties.Data != null) { loopExtraParams.Add(floorAndProperties.Data); } } } } } // Use internal routine as backup that handles openings. if (prodReps.Count == 0 && canExportAsInternalExtrusion) { //IList<IFCAnyHandle> prodRepsTmp = new List<IFCAnyHandle>(); exportedAsInternalExtrusion = ExporterIFCUtils.ExportSlabAsExtrusion(exporterIFC, floorElement, geometryElement, transformSetter, localPlacement, out localPlacements, out prodReps, out extrusionLoops, out loopExtraParams, floorPlane); for (int ii = 0; ii < prodReps.Count; ii++) { // all are extrusions repTypes.Add(ShapeRepresentationType.SweptSolid); // Footprint representation will only be exported in export to IFC4 if (ExporterCacheManager.ExportOptionsCache.ExportAs4) { // Get back the representations, we need to add the Footprint to it //IList<IFCAnyHandle> representations = IFCAnyHandleUtil.GetRepresentations(prodRepsTmp[ii]); if (extrusionLoops.Count > ii) { if (extrusionLoops[ii].Count > 0) { // Get the extrusion footprint using the first Curveloop. Transform needs to be obtained from the returned local placement Transform lcs = ExporterIFCUtils.GetUnscaledTransform(exporterIFC, localPlacements[ii]); IFCAnyHandle footprintGeomRepItem = GeometryUtil.CreateIFCCurveFromCurveLoop(exporterIFC, extrusionLoops[ii][0], lcs, floorPlane.Normal); IFCAnyHandle contextOfItemsFootprint = exporterIFC.Get3DContextHandle("FootPrint"); ISet <IFCAnyHandle> repItem = new HashSet <IFCAnyHandle>(); repItem.Add(footprintGeomRepItem); IFCAnyHandle footprintShapeRepresentation = RepresentationUtil.CreateBaseShapeRepresentation(exporterIFC, contextOfItemsFootprint, "FootPrint", "Curve2D", repItem); //representations.Add(footprintShapeRepresentation); IList <IFCAnyHandle> reps = new List <IFCAnyHandle>(); reps.Add(footprintShapeRepresentation); IFCAnyHandleUtil.AddRepresentations(prodReps[ii], reps); } } //IFCAnyHandle prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations); //prodReps.Add(prodRep); } else { //prodReps.Add(prodRepsTmp[ii]); } // We do not need the prodRepsTmp anymore, delete the handle: //prodRepsTmp[ii].Delete(); } } if (prodReps.Count == 0) { using (IFCExtrusionCreationData ecData = new IFCExtrusionCreationData()) { // Brep representation using tesellation after ExportSlabAsExtrusion does not return prodReps BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true, ExportOptionsCache.ExportTessellationLevel.Medium); BodyData bodyData; IFCAnyHandle prodDefHnd = RepresentationUtil.CreateAppropriateProductDefinitionShape(exporterIFC, floorElement, catId, geometryElement, bodyExporterOptions, null, ecData, out bodyData); if (IFCAnyHandleUtil.IsNullOrHasNoValue(prodDefHnd)) { ecData.ClearOpenings(); return; } prodReps.Add(prodDefHnd); repTypes.Add(bodyData.ShapeRepresentationType); } } // Create the slab from either the extrusion or the BRep information. string ifcGUID = GUIDUtil.CreateGUID(floorElement); int numReps = exportParts ? 1 : prodReps.Count; string entityType = null; switch (exportType) { case IFCExportType.IfcFooting: if (ExporterCacheManager.ExportOptionsCache.ExportAs4) { entityType = IFCValidateEntry.GetValidIFCType <Revit.IFC.Export.Toolkit.IFC4.IFCFootingType>(floorElement, ifcEnumType, null); } else { entityType = IFCValidateEntry.GetValidIFCType <IFCFootingType>(floorElement, ifcEnumType, null); } break; case IFCExportType.IfcCovering: entityType = IFCValidateEntry.GetValidIFCType <IFCCoveringType>(floorElement, ifcEnumType, "FLOORING"); break; case IFCExportType.IfcRamp: if (ExporterCacheManager.ExportOptionsCache.ExportAs4) { entityType = IFCValidateEntry.GetValidIFCType <Revit.IFC.Export.Toolkit.IFC4.IFCRampType>(floorElement, ifcEnumType, null); } else { entityType = IFCValidateEntry.GetValidIFCType <IFCRampType>(floorElement, ifcEnumType, null); } break; default: bool isBaseSlab = false; AnalyticalModel analyticalModel = floorElement.GetAnalyticalModel(); if (analyticalModel != null) { AnalyzeAs slabFoundationType = analyticalModel.GetAnalyzeAs(); isBaseSlab = (slabFoundationType == AnalyzeAs.SlabOnGrade) || (slabFoundationType == AnalyzeAs.Mat); } entityType = IFCValidateEntry.GetValidIFCType <IFCSlabType>(floorElement, ifcEnumType, isBaseSlab ? "BASESLAB" : "FLOOR"); break; } for (int ii = 0; ii < numReps; ii++) { string ifcName = NamingUtil.GetNameOverride(floorElement, NamingUtil.GetIFCNamePlusIndex(floorElement, ii == 0 ? -1 : ii + 1)); string ifcDescription = NamingUtil.GetDescriptionOverride(floorElement, null); string ifcObjectType = NamingUtil.GetObjectTypeOverride(floorElement, exporterIFC.GetFamilyName()); string ifcTag = NamingUtil.GetTagOverride(floorElement, NamingUtil.CreateIFCElementId(floorElement)); string currentGUID = (ii == 0) ? ifcGUID : GUIDUtil.CreateGUID(); IFCAnyHandle localPlacementHnd = exportedAsInternalExtrusion ? localPlacements[ii] : localPlacement; IFCAnyHandle slabHnd = null; // TODO: replace with CreateGenericBuildingElement. switch (exportType) { case IFCExportType.IfcFooting: slabHnd = IFCInstanceExporter.CreateFooting(file, currentGUID, ownerHistory, ifcName, ifcDescription, ifcObjectType, localPlacementHnd, exportParts ? null : prodReps[ii], ifcTag, entityType); break; case IFCExportType.IfcCovering: slabHnd = IFCInstanceExporter.CreateCovering(file, currentGUID, ownerHistory, ifcName, ifcDescription, ifcObjectType, localPlacementHnd, exportParts ? null : prodReps[ii], ifcTag, entityType); break; case IFCExportType.IfcRamp: slabHnd = IFCInstanceExporter.CreateRamp(file, currentGUID, ownerHistory, ifcName, ifcDescription, ifcObjectType, localPlacementHnd, exportParts ? null : prodReps[ii], ifcTag, entityType); break; default: //if ((canExportAsInternalExtrusion || exportedAsInternalExtrusion) && ExporterCacheManager.ExportOptionsCache.ExportAs4) //{ // slabHnd = IFCInstanceExporter.CreateSlabStandardCase(file, currentGUID, ownerHistory, ifcName, // ifcDescription, ifcObjectType, localPlacementHnd, exportParts ? null : prodReps[ii], // ifcTag, entityType); //} //else slabHnd = IFCInstanceExporter.CreateSlab(file, currentGUID, ownerHistory, ifcName, ifcDescription, ifcObjectType, localPlacementHnd, exportParts ? null : prodReps[ii], ifcTag, entityType); break; } if (IFCAnyHandleUtil.IsNullOrHasNoValue(slabHnd)) { return; } if (exportParts) { PartExporter.ExportHostPart(exporterIFC, floorElement, slabHnd, productWrapper, placementSetter, localPlacementHnd, null); } slabHnds.Add(slabHnd); if (!exportParts) { if (repTypes[ii] == ShapeRepresentationType.Brep) { brepSlabHnds.Add(slabHnd); } else { nonBrepSlabHnds.Add(slabHnd); } } } for (int ii = 0; ii < numReps; ii++) { IFCExtrusionCreationData loopExtraParam = ii < loopExtraParams.Count ? loopExtraParams[ii] : null; productWrapper.AddElement(floorElement, slabHnds[ii], placementSetter, loopExtraParam, true); } // This call to the native function appears to create Brep opening also when appropriate. But the creation of the IFC instances is not // controllable from the managed code. Therefore in some cases BRep geometry for Opening will still be exported even in the Reference View if (exportedAsInternalExtrusion) { ExporterIFCUtils.ExportExtrudedSlabOpenings(exporterIFC, floorElement, placementSetter.LevelInfo, localPlacements[0], slabHnds, extrusionLoops, floorPlane, productWrapper.ToNative()); } //// For now we have to be content without IfcOpeningStandardCase from the openings created by this native call because it is too much to //// "reverse engineer" the IFChandle //foreach (IFCAnyHandle slabHandle in slabHnds) //{ // updateOpeningProfileRep(exporterIFC, slabHandle); //} } if (!exportParts) { if (nonBrepSlabHnds.Count > 0) { HostObjectExporter.ExportHostObjectMaterials(exporterIFC, floorElement, nonBrepSlabHnds, geometryElement, productWrapper, ElementId.InvalidElementId, Toolkit.IFCLayerSetDirection.Axis3, false); } if (brepSlabHnds.Count > 0) { HostObjectExporter.ExportHostObjectMaterials(exporterIFC, floorElement, brepSlabHnds, geometryElement, productWrapper, ElementId.InvalidElementId, Toolkit.IFCLayerSetDirection.Axis3, true); } } } tr.Commit(); return; } }
/// <summary> /// Exports a geometry element to boundary representation. /// </summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="element">The element.</param> /// <param name="geometryElement">The geometry element.</param> /// <param name="exportBoundaryRep">True if to export boundary representation.</param> /// <param name="exportAsFacetation">True if to export the geometry as facetation.</param> /// <param name="bodyRep">Body representation.</param> /// <param name="boundaryRep">Boundary representation.</param> /// <returns>True if success, false if fail.</returns> public static bool ExportSurface(ExporterIFC exporterIFC, Element element, GeometryElement geometryElement, bool exportBoundaryRep, bool exportAsFacetation, ref IFCAnyHandle bodyRep, ref IFCAnyHandle boundaryRep) { if (geometryElement == null) { return(false); } IFCGeometryInfo ifcGeomInfo = null; Document doc = element.Document; Plane plane = GeometryUtil.CreateDefaultPlane(); XYZ projDir = new XYZ(0, 0, 1); double eps = UnitUtil.ScaleLength(doc.Application.VertexTolerance); IFCFile file = exporterIFC.GetFile(); IFCAnyHandle surface; ICollection <IFCAnyHandle> boundaryRepresentations = new List <IFCAnyHandle>(); // Use tessellated geometry for surface in IFC Reference View if (ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView) { BodyExporterOptions options = new BodyExporterOptions(false, ExportOptionsCache.ExportTessellationLevel.ExtraLow); surface = BodyExporter.ExportBodyAsTessellatedFaceSet(exporterIFC, element, options, geometryElement); if (element is Autodesk.Revit.DB.Architecture.TopographySurface) { // TODO: need to find a good way to create the right boundary outline! //IList<XYZ> boundaryPoints = (element as Autodesk.Revit.DB.Architecture.TopographySurface).GetBoundaryPoints(); //if (boundaryPoints != null && boundaryPoints.Count > 0) //{ // IList<IFCAnyHandle> coords = new List<IFCAnyHandle>(); // foreach (XYZ point in boundaryPoints) // { // XYZ scPoint = ExporterIFCUtils.TransformAndScalePoint(exporterIFC, point); // IList<double> uvPoint = new List<double>(); // // SInce the projection direction is on Z-axis, simply ignoring the Z-value will do for this. And also the Site reference will follow the WCS // uvPoint.Add(scPoint.X); // uvPoint.Add(scPoint.Y); // IFCAnyHandle ifcCartesianPoint = IFCInstanceExporter.CreateCartesianPoint(file, uvPoint); // coords.Add(ifcCartesianPoint); // } // if (coords.Count >= 2) // { // IFCAnyHandle boundaryLines = IFCInstanceExporter.CreatePolyline(file, coords); // boundaryRepresentations.Add(boundaryLines); // } //} } } else { ifcGeomInfo = IFCGeometryInfo.CreateFaceGeometryInfo(exporterIFC, plane, projDir, eps, exportBoundaryRep); ExporterIFCUtils.CollectGeometryInfo(exporterIFC, ifcGeomInfo, geometryElement, XYZ.Zero, true); HashSet <IFCAnyHandle> faceSets = new HashSet <IFCAnyHandle>(); IList <ICollection <IFCAnyHandle> > faceList = ifcGeomInfo.GetFaces(); foreach (ICollection <IFCAnyHandle> faces in faceList) { // no faces, don't complain. if (faces.Count == 0) { continue; } HashSet <IFCAnyHandle> faceSet = new HashSet <IFCAnyHandle>(faces); faceSets.Add(IFCInstanceExporter.CreateConnectedFaceSet(file, faceSet)); } if (faceSets.Count == 0) { return(false); } surface = IFCInstanceExporter.CreateFaceBasedSurfaceModel(file, faceSets); // Collect Footprint data boundaryRepresentations = ifcGeomInfo.GetRepresentations(); } if (IFCAnyHandleUtil.IsNullOrHasNoValue(surface)) { return(false); } BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, doc, surface, BodyExporter.GetBestMaterialIdFromGeometryOrParameter(geometryElement, exporterIFC, element)); ISet <IFCAnyHandle> surfaceItems = new HashSet <IFCAnyHandle>(); surfaceItems.Add(surface); ElementId catId = CategoryUtil.GetSafeCategoryId(element); bodyRep = RepresentationUtil.CreateSurfaceRep(exporterIFC, element, catId, exporterIFC.Get3DContextHandle("Body"), surfaceItems, exportAsFacetation, bodyRep); if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep)) { return(false); } if (exportBoundaryRep && boundaryRepresentations.Count > 0) { HashSet <IFCAnyHandle> boundaryRepresentationSet = new HashSet <IFCAnyHandle>(); boundaryRepresentationSet.UnionWith(boundaryRepresentations); boundaryRep = RepresentationUtil.CreateBoundaryRep(exporterIFC, element, catId, exporterIFC.Get3DContextHandle("FootPrint"), boundaryRepresentationSet, boundaryRep); } return(true); }