/// <summary> /// Export spatial elements, including rooms, areas and spaces. 1st level space boundaries. /// </summary> /// <param name="exporterIFC"> /// The ExporterIFC object. /// </param> /// <param name="spatialElement"> /// The spatial element. /// </param> /// <param name="productWrapper"> /// The IFCProductWrapper. /// </param> public static void ExportSpatialElement(ExporterIFC exporterIFC, SpatialElement spatialElement, IFCProductWrapper productWrapper) { //quick reject bool isArea = spatialElement is Area; if (isArea) { if (!IsAreaGrossInterior(exporterIFC, spatialElement)) return; } IFCFile file = exporterIFC.GetFile(); using (IFCTransaction tr = new IFCTransaction(file)) { ElementId levelId = spatialElement.Level != null ? spatialElement.Level.Id : ElementId.InvalidElementId; using (IFCPlacementSetter setter = IFCPlacementSetter.Create(exporterIFC, spatialElement, null, null, levelId)) { CreateIFCSpace(exporterIFC, spatialElement, productWrapper, setter); // Do not create boundary information, or extra property sets. if (spatialElement is Area) { tr.Commit(); return; } if (exporterIFC.SpaceBoundaryLevel == 1) { Document document = spatialElement.Document; IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(levelId); double baseHeightNonScaled = levelInfo.Elevation; SpatialElementGeometryResults spatialElemGeomResult = s_SpatialElemGeometryCalculator.CalculateSpatialElementGeometry(spatialElement); Solid spatialElemGeomSolid = spatialElemGeomResult.GetGeometry(); FaceArray faces = spatialElemGeomSolid.Faces; foreach (Face face in faces) { IList<SpatialElementBoundarySubface> spatialElemBoundarySubfaces = spatialElemGeomResult.GetBoundaryFaceInfo(face); foreach (SpatialElementBoundarySubface spatialElemBSubface in spatialElemBoundarySubfaces) { if (spatialElemBSubface.SubfaceType == SubfaceType.Side) continue; if (spatialElemBSubface.GetSubface() == null) continue; ElementId elemId = spatialElemBSubface.SpatialBoundaryElement.LinkInstanceId; if (elemId == ElementId.InvalidElementId) { elemId = spatialElemBSubface.SpatialBoundaryElement.HostElementId; } Element boundingElement = document.get_Element(elemId); if (boundingElement == null) continue; bool isObjectExt = CategoryUtil.IsElementExternal(boundingElement); IFCGeometryInfo info = IFCGeometryInfo.CreateSurfaceGeometryInfo(spatialElement.Document.Application.VertexTolerance); Face subFace = spatialElemBSubface.GetSubface(); ExporterIFCUtils.CollectGeometryInfo(exporterIFC, info, subFace, XYZ.Zero, false); IFCAnyHandle ifcOptionalHnd = IFCAnyHandle.Create(); foreach (IFCAnyHandle surfaceHnd in info.GetSurfaces()) { IFCAnyHandle connectionGeometry = file.CreateConnectionSurfaceGeometry(surfaceHnd, ifcOptionalHnd); IFCSpaceBoundary spaceBoundary = IFCSpaceBoundary.Create(spatialElement.Id, boundingElement.Id, connectionGeometry, IFCSpaceBoundaryType.Physical, isObjectExt); if (!ProcessIFCSpaceBoundary(exporterIFC, spaceBoundary, file)) exporterIFC.RegisterIFCSpaceBoundary(spaceBoundary); } } } IList<IList<BoundarySegment>> roomBoundaries = spatialElement.GetBoundarySegments(ExporterIFCUtils.GetSpatialElementBoundaryOptions(exporterIFC, spatialElement)); double roomHeight = GetHeight(spatialElement, exporterIFC.LinearScale, levelInfo); XYZ zDir = new XYZ(0, 0, 1); foreach (IList<BoundarySegment> roomBoundaryList in roomBoundaries) { foreach (BoundarySegment roomBoundary in roomBoundaryList) { Element boundingElement = roomBoundary.Element; if (boundingElement == null) continue; ElementId buildingElemId = boundingElement.Id; Curve trimmedCurve = roomBoundary.Curve; if (trimmedCurve == null) continue; //trimmedCurve.Visibility = Visibility.Visible; readonly IFCAnyHandle connectionGeometry = ExporterIFCUtils.CreateExtrudedSurfaceFromCurve( exporterIFC, trimmedCurve, zDir, roomHeight, baseHeightNonScaled); IFCSpaceBoundaryType physOrVirt = IFCSpaceBoundaryType.Physical; if (boundingElement is CurveElement) physOrVirt = IFCSpaceBoundaryType.Virtual; else if (boundingElement is Autodesk.Revit.DB.Architecture.Room) physOrVirt = IFCSpaceBoundaryType.Undefined; bool isObjectExt = CategoryUtil.IsElementExternal(boundingElement); bool isObjectPhys = (physOrVirt == IFCSpaceBoundaryType.Physical); ElementId actualBuildingElemId = isObjectPhys ? buildingElemId : ElementId.InvalidElementId; IFCSpaceBoundary boundary = IFCSpaceBoundary.Create(spatialElement.Id, actualBuildingElemId, connectionGeometry, physOrVirt, isObjectExt); if (!ProcessIFCSpaceBoundary(exporterIFC, boundary, file)) exporterIFC.RegisterIFCSpaceBoundary(boundary); // try to add doors and windows for host objects if appropriate. if (isObjectPhys && boundingElement is HostObject) { HostObject hostObj = boundingElement as HostObject; IList<ElementId> elemIds = hostObj.FindInserts(false, false, false, false); foreach (ElementId elemId in elemIds) { // we are going to do a simple bbox export, not complicated geometry. Element instElem = document.get_Element(elemId); if (instElem == null) continue; BoundingBoxXYZ instBBox = instElem.get_BoundingBox(null); // make copy of original trimmed curve. Curve instCurve = trimmedCurve.Clone(); XYZ instOrig = instCurve.get_EndPoint(0); // make sure that the insert is on this level. if (instBBox.Max.Z < instOrig.Z) continue; if (instBBox.Min.Z > instOrig.Z + roomHeight) continue; double insHeight = Math.Min(instBBox.Max.Z, instOrig.Z + roomHeight) - Math.Max(instOrig.Z, instBBox.Min.Z); if (insHeight < (1.0 / (12.0 * 16.0))) continue; // move base curve to bottom of bbox. XYZ moveDir = new XYZ(0.0, 0.0, instBBox.Min.Z - instOrig.Z); Transform moveTrf = Transform.get_Translation(moveDir); instCurve = instCurve.get_Transformed(moveTrf); bool isHorizOrVert = false; if (instCurve is Line) { Line instLine = instCurve as Line; XYZ lineDir = instLine.Direction; if (MathUtil.IsAlmostEqual(Math.Abs(lineDir.X), 1.0) || (MathUtil.IsAlmostEqual(Math.Abs(lineDir.Y), 1.0))) isHorizOrVert = true; } double[] parameters = new double[2]; double[] origEndParams = new double[2]; if (isHorizOrVert) { parameters[0] = instCurve.Project(instBBox.Min).Parameter; parameters[1] = instCurve.Project(instBBox.Max).Parameter; } else { FamilyInstance famInst = instElem as FamilyInstance; if (famInst == null) continue; ElementType elementType = document.get_Element(famInst.GetTypeId()) as ElementType; if (elementType == null) continue; BoundingBoxXYZ symBBox = elementType.get_BoundingBox(null); Curve symCurve = trimmedCurve.Clone(); Transform trf = famInst.GetTransform(); Transform invTrf = trf.Inverse; Curve trfCurve = symCurve.get_Transformed(invTrf); parameters[0] = trfCurve.Project(symBBox.Min).Parameter; parameters[1] = trfCurve.Project(symBBox.Max).Parameter; } // ignore if less than 1/16". if (Math.Abs(parameters[1] - parameters[0]) < 1.0 / (12.0 * 16.0)) continue; if (parameters[0] > parameters[1]) { //swap double tempParam = parameters[0]; parameters[0] = parameters[1]; parameters[1] = tempParam; } origEndParams[0] = instCurve.get_EndParameter(0); origEndParams[1] = instCurve.get_EndParameter(1); if (origEndParams[0] > parameters[1] - (1.0 / (12.0 * 16.0))) continue; if (origEndParams[1] < parameters[0] + (1.0 / (12.0 * 16.0))) continue; if (parameters[0] > origEndParams[0]) instCurve.set_EndParameter(0, parameters[0]); if (parameters[1] < origEndParams[1]) instCurve.set_EndParameter(1, parameters[1]); IFCAnyHandle insConnectionGeom = ExporterIFCUtils.CreateExtrudedSurfaceFromCurve(exporterIFC, instCurve, zDir, insHeight, baseHeightNonScaled); IFCSpaceBoundary instBoundary = IFCSpaceBoundary.Create(spatialElement.Id, elemId, insConnectionGeom, physOrVirt, isObjectExt); if (!ProcessIFCSpaceBoundary(exporterIFC, instBoundary, file)) exporterIFC.RegisterIFCSpaceBoundary(instBoundary); } } } } } ExporterIFCUtils.CreateSpatialElementPropertySet(exporterIFC, spatialElement, productWrapper); } tr.Commit(); } }
/// <summary> /// 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="connectionGeometry"> /// The connection geometry handle. /// </param> static void CreateIFCSpaceBoundary(IFCFile file, ExporterIFC exporterIFC, SpatialElement spatialElement, Element boundingElement, IFCAnyHandle connectionGeometry) { IFCSpaceBoundaryType physOrVirt = IFCSpaceBoundaryType.Physical; if (boundingElement is CurveElement) physOrVirt = IFCSpaceBoundaryType.Virtual; else if (boundingElement is Autodesk.Revit.DB.Architecture.Room) physOrVirt = IFCSpaceBoundaryType.Undefined; bool isObjectExt = CategoryUtil.IsElementExternal(boundingElement); IFCSpaceBoundary spaceBoundary = IFCSpaceBoundary.Create(spatialElement.Id, boundingElement.Id, connectionGeometry, physOrVirt, isObjectExt); if (!ProcessIFCSpaceBoundary(exporterIFC, spaceBoundary, file)) exporterIFC.RegisterIFCSpaceBoundary(spaceBoundary); }