/// <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) { //quick reject bool isArea = spatialElement is Area; if (isArea) { if (!IsAreaGrossInterior(exporterIFC, spatialElement)) return; } IFCFile file = exporterIFC.GetFile(); using (IFCTransaction transaction = new IFCTransaction(file)) { ElementId levelId = spatialElement.Level != null ? spatialElement.Level.Id : ElementId.InvalidElementId; using (IFCPlacementSetter setter = IFCPlacementSetter.Create(exporterIFC, spatialElement, null, null, levelId)) { if (!CreateIFCSpace(exporterIFC, spatialElement, productWrapper, setter)) return; // Do not create boundary information, or extra property sets. if (spatialElement is Area) { transaction.Commit(); return; } if (ExporterCacheManager.ExportOptionsCache.SpaceBoundaryLevel == 1) { Document document = spatialElement.Document; IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(levelId); double baseHeightNonScaled = levelInfo.Elevation; try { // This can throw an exception. If it does, continue to export element without boundary information. // TODO: warn user. SpatialElementGeometryResults 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, true); 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(ExporterIFCUtils.GetSpatialElementBoundaryOptions(exporterIFC, spatialElement)); double roomHeight = GetHeight(spatialElement, exporterIFC.LinearScale, levelId, 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 = ExtrusionExporter.CreateExtrudedSurfaceFromCurve( exporterIFC, trimmedCurve, zDir, roomHeight, 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, true); 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(curtainGrid.GetPanelIds()); } } 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.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]; 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.get_Transformed(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.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]); double insHeightScaled = insHeight * exporterIFC.LinearScale; IFCAnyHandle insConnectionGeom = ExtrusionExporter.CreateExtrudedSurfaceFromCurve(exporterIFC, instCurve, zDir, 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); } } } } } PropertyUtil.CreateInternalRevitPropertySets(exporterIFC, spatialElement, productWrapper); CreateZoneInfos(exporterIFC, file, spatialElement, productWrapper); CreateSpaceOccupantInfo(exporterIFC, file, spatialElement, productWrapper); } transaction.Commit(); } }
/// <summary> /// Creates space boundary. /// </summary> /// <param name="exporterIFC"> /// The ExporterIFC object. /// </param> /// <param name="boundary"> /// The space boundary object. /// </param> /// <param name="file"> /// The IFC file. /// </param> /// <returns> /// True if processed successfully, false otherwise. /// </returns> public static bool ProcessIFCSpaceBoundary(ExporterIFC exporterIFC, SpaceBoundary boundary, IFCFile file) { string spaceBoundaryName = String.Empty; if (ExporterCacheManager.ExportOptionsCache.SpaceBoundaryLevel == 1) spaceBoundaryName = "1stLevel"; else if (ExporterCacheManager.ExportOptionsCache.SpaceBoundaryLevel == 2) spaceBoundaryName = "2ndLevel"; IFCAnyHandle spatialElemHnd = ExporterCacheManager.SpatialElementHandleCache.Find(boundary.SpatialElementId); if (IFCAnyHandleUtil.IsNullOrHasNoValue(spatialElemHnd)) return false; IFCPhysicalOrVirtual boundaryType = boundary.SpaceBoundaryType; IFCAnyHandle buildingElemHnd = null; if (boundaryType == IFCPhysicalOrVirtual.Physical) { buildingElemHnd = exporterIFC.FindSpaceBoundingElementHandle(boundary.BuildingElementId, boundary.LevelId); if (IFCAnyHandleUtil.IsNullOrHasNoValue(buildingElemHnd)) return false; } IFCInstanceExporter.CreateRelSpaceBoundary(file, GUIDUtil.CreateGUID(), exporterIFC.GetOwnerHistoryHandle(), spaceBoundaryName, null, spatialElemHnd, buildingElemHnd, boundary.ConnectGeometryHandle, boundaryType, boundary.InternalOrExternal); return true; }
/// <summary> /// Creates SpaceBoundary from a bounding element. /// </summary> /// <param name="file"> /// The IFC file. /// </param> /// <param name="exporterIFC"> /// The ExporterIFC object. /// </param> /// <param name="spatialElement"> /// The spatial element. /// </param> /// <param name="boundingElement"> /// The bounding element. /// </param> /// <param name="levelId"> /// The level id. /// </param> /// <param name="connectionGeometry"> /// The connection geometry handle. /// </param> static void CreateIFCSpaceBoundary(IFCFile file, ExporterIFC exporterIFC, SpatialElement spatialElement, Element boundingElement, ElementId levelId, IFCAnyHandle connectionGeometry) { IFCPhysicalOrVirtual physOrVirt = IFCPhysicalOrVirtual.Physical; if (boundingElement == null || boundingElement is CurveElement) physOrVirt = IFCPhysicalOrVirtual.Virtual; else if (boundingElement is Autodesk.Revit.DB.Architecture.Room) physOrVirt = IFCPhysicalOrVirtual.NotDefined; bool isObjectExt = CategoryUtil.IsElementExternal(boundingElement, true); SpaceBoundary spaceBoundary = new SpaceBoundary(spatialElement.Id, boundingElement != null ? boundingElement.Id : ElementId.InvalidElementId, levelId, connectionGeometry, physOrVirt, isObjectExt ? IFCInternalOrExternal.External : IFCInternalOrExternal.Internal); if (!ProcessIFCSpaceBoundary(exporterIFC, spaceBoundary, file)) ExporterCacheManager.SpaceBoundaryCache.Add(spaceBoundary); }