/// <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.SpaceInfoCache.FindSpaceHandle(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(), ExporterCacheManager.OwnerHistoryHandle, spaceBoundaryName, null, spatialElemHnd, buildingElemHnd, boundary.ConnectGeometryHandle, boundaryType, boundary.InternalOrExternal); return true; }
/// <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 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); 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); }