Пример #1
0
        public static List <List <RoomEdge> > GetRoomEdges(Document doc, SpatialElement room)
        {
            //Extract the boundary curves for a room based on the center of the enclosing element
            SpatialElementBoundaryOptions opt = new SpatialElementBoundaryOptions();

            opt.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Center;
            IList <IList <BoundarySegment> > boundarySegments = room.GetBoundarySegments(opt);
            List <List <RoomEdge> >          allRoomEdges     = new List <List <RoomEdge> >();

            foreach (List <BoundarySegment> l1 in boundarySegments)
            {
                List <RoomEdge> roomEdges = new List <RoomEdge>();
                foreach (BoundarySegment l2 in l1)
                {
                    RoomEdge roomEdge = new RoomEdge()
                    {
                        _Edge       = l2.GetCurve(),
                        _StartPoint = l2.GetCurve().GetEndPoint(0),
                    };
                    roomEdges.Add(roomEdge);
                }
                allRoomEdges.Add(roomEdges);
            }

            return(allRoomEdges);
        }
Пример #2
0
        private static void GetstructuralWallArea(Document doc, SpatialElement spElem, out double wallArea)
        {
            SpatialElementBoundaryOptions boundaryOptions =
                new SpatialElementBoundaryOptions
            {
                SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Center
            };

            IList <IList <BoundarySegment> > bndSegmentsList =
                spElem.GetBoundarySegments(boundaryOptions);

            wallArea = 0;
            for (int i = 0; i < bndSegmentsList.Count; ++i)
            {
                for (int j = 0; j < bndSegmentsList[i].Count; ++j)
                {
                    Element boundaryElem = doc.GetElement(bndSegmentsList[i][j].ElementId);
                    if (boundaryElem is Wall &&
                        ((Wall)boundaryElem).get_Parameter(BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT).AsInteger() == 1)
                    {
                        Wall strWall = (Wall)boundaryElem;
                        wallArea += (strWall.WallType.Width / 2) *
                                    (bndSegmentsList[i][j].GetCurve().Length);
                    }
                }
            }
        }
Пример #3
0
        /// <summary>
        ///     Gets intersect element list.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="room"></param>
        /// <param name="doc"></param>
        /// <returns></returns>
        public static List <T> GetIntersectElements <T>(this SpatialElement room, Document doc) where T : Element
        {
            if (room == null)
            {
                throw new ArgumentNullException(nameof(room));
            }

            if (doc == null)
            {
                throw new ArgumentNullException(nameof(doc));
            }

            var results = new List <T>();
            var elms    = room.GetIntersectElements(doc);

            foreach (var elm in elms)
            {
                if (elm is T t)
                {
                    results.Add(t);
                }
            }

            return(results);
        }
Пример #4
0
        /***************************************************/
        /****               Public Methods              ****/
        /***************************************************/

        public static oM.Architecture.Elements.Room RoomFromRevit(this SpatialElement spatialElement, RevitSettings settings = null, Dictionary <string, List <IBHoMObject> > refObjects = null)
        {
            settings = settings.DefaultIfNull();

            oM.Architecture.Elements.Room room = refObjects.GetValue <oM.Architecture.Elements.Room>(spatialElement.Id);
            if (room != null)
            {
                return(room);
            }

            room = new oM.Architecture.Elements.Room()
            {
                Perimeter = spatialElement.Perimeter(settings).First()
            };
            room.Name = spatialElement.Name;

            //Set location
            if (spatialElement.Location != null && spatialElement.Location is LocationPoint)
            {
                room.Location = ((LocationPoint)spatialElement.Location).FromRevit();
            }

            //Set identifiers, parameters & custom data
            room.SetIdentifiers(spatialElement);
            room.CopyParameters(spatialElement, settings.ParameterSettings);
            room.SetProperties(spatialElement, settings.ParameterSettings);

            refObjects.AddOrReplace(spatialElement.Id, room);
            return(room);
        }
    public override float Evaluate(Representation representation)
    {
        RepresentationMesh repre = representation as RepresentationMesh;

        if (repre == null)
        {
            return(0);
        }

        if (repre.structure == null)
        {
            return(0);
        }

        asymetryList.Clear();
        symmetryNode = null;

        symmetryNode = _getSymNode(repre.structure as LSystemGraph, level);

        _fillNodeValues(symmetryNode);

        float returnValue = 0;

        for (int i = 0; i < asymetryList.Count; i++)
        {
            returnValue += asymetryList[i].delta * asymetryList[i].weight;
        }

        return(returnValue);
    }
Пример #6
0
        //Energy Analysis

        public void EnergyAnalysis()
        {
            // Collect space and surface data from the building's analytical thermal model
            EnergyAnalysisDetailModelOptions options = new EnergyAnalysisDetailModelOptions();

            options.Tier            = EnergyAnalysisDetailModelTier.Final; // include constructions, schedules, and non-graphical data in the computation of the energy analysis model
            options.EnergyModelType = EnergyModelType.SpatialElement;      // Energy model based on rooms or spaces
            options.EnergyModelType = EnergyModelType.BuildingElement;

            EnergyAnalysisDetailModel   eadm   = EnergyAnalysisDetailModel.Create(doc, options); // Create a new energy analysis detailed model from the physical model
            IList <EnergyAnalysisSpace> spaces = eadm.GetAnalyticalSpaces();
            StringBuilder builder = new StringBuilder();

            builder.AppendLine("Spaces: " + spaces.Count);
            foreach (EnergyAnalysisSpace space in spaces)
            {
                SpatialElement spatialElement   = doc.GetElement(space.CADObjectUniqueId) as SpatialElement;
                ElementId      spatialElementId = spatialElement == null ? ElementId.InvalidElementId : spatialElement.Id;
                builder.AppendLine("   >>> " + space.SpaceName + " related to " + spatialElementId);
                IList <EnergyAnalysisSurface> surfaces = space.GetAnalyticalSurfaces();
                builder.AppendLine("       has " + surfaces.Count + " surfaces.");
                foreach (EnergyAnalysisSurface surface in surfaces)
                {
                    builder.AppendLine("            +++ Surface from " + surface.OriginatingElementDescription);
                }
            }
            TaskDialog.Show("EAM", builder.ToString());
        }
Пример #7
0
        public List <SpatialElement> getVeriticality(SpatialElement el)
        {
            List <SpatialElement> spatialElements = new List <SpatialElement>();
            int nbPerVerticality = 0;
            int caughttemp1      = 0;
            int caughttemp2      = Convert.ToInt16(el.Name[2].ToString()
                                                   + el.Name[3].ToString());

            foreach (var item in localsTech)
            {
                if (item.Name.ToUpper().Contains("GT"))
                {
                    try
                    {
                        caughttemp1 = Convert.ToInt16(item.Name[2].ToString() + item.Name[3].ToString());
                        if (caughttemp1 == caughttemp2)
                        {
                            nbPerVerticality += 1;
                            spatialElements.Add(item);
                        }
                    }
                    catch
                    {
                        TaskDialog.Show("Erreur de codification.", "Codification invalide de la gaine: " + item.Name);
                        System.Environment.Exit(-1);
                    }
                }
                spatialElements.Sort(delegate(SpatialElement c1, SpatialElement c2)
                {
                    return(c1.Level.Elevation.CompareTo(c2.Level.Elevation));
                });
            }
            return(spatialElements);
        }
Пример #8
0
        /// <summary>
        ///     Gets the room's edge list.
        /// </summary>
        /// <param name="room"></param>
        /// <param name="boundary"></param>
        /// <returns></returns>
        public static List <Line> GetEdgeList(this SpatialElement room, SpatialElementBoundaryLocation boundary)
        {
            if (room == null)
            {
                throw new ArgumentNullException(nameof(room));
            }

            var result = new List <Line>();
            var opt    = new SpatialElementBoundaryOptions
            {
                StoreFreeBoundaryFaces         = true,
                SpatialElementBoundaryLocation = boundary
            };
            var segments = room.GetBoundarySegments(opt).SelectMany(s => s);

            foreach (var seg in segments)
            {
                var sp = seg.GetCurve().GetEndPoint(0);
                var ep = seg.GetCurve().GetEndPoint(1);

                result.Add(Line.CreateBound(sp, ep));
            }

            return(result);
        }
Пример #9
0
        /// <summary>
        ///     Gets intersect element list.
        /// </summary>
        /// <param name="room"></param>
        /// <param name="doc"></param>
        /// <returns></returns>
        public static List <Element> GetIntersectElements(this SpatialElement room, Document doc)
        {
            if (room is null)
            {
                throw new ArgumentNullException(nameof(room));
            }

            if (doc is null)
            {
                throw new ArgumentNullException(nameof(doc));
            }

            var opt = new SpatialElementBoundaryOptions  {
                SpatialElementBoundaryLocation = Center
            };

            var calc = new SpatialElementGeometryCalculator(doc, opt);

            var solid = calc.CalculateSpatialElementGeometry(room).GetGeometry();

            var instFilter = new FilteredElementCollector(doc).WhereElementIsNotElementType();

            var itstFilter = new ElementIntersectsSolidFilter(solid);

            return(instFilter.WherePasses(itstFilter).ToList());
        }
    void _fillNodeValues(SpatialElement node)
    {
        SumElement se = new SumElement();

        se.level = node.level;

        float leftSum = 0;

        for (int i = 0; i < node.leftBranches.Count; i++)
        {
            leftSum += node.leftBranches[i].allSize;
        }

        float rightSum = 0;

        for (int i = 0; i < node.rightBranches.Count; i++)
        {
            rightSum += node.rightBranches[i].allSize;
        }

        se.delta  = (leftSum + rightSum) == 0 ? 0 : (float)Mathf.Abs(leftSum - rightSum) / (float)(node.allCount);
        se.weight = (float)node.allSize / (float)symmetryNode.allSize;

        asymetryList.Add(se);

        for (int i = 0; i < node.leftBranches.Count; i++)
        {
            _fillNodeValues(node.leftBranches[i]);
        }

        for (int i = 0; i < node.rightBranches.Count; i++)
        {
            _fillNodeValues(node.rightBranches[i]);
        }
    }
Пример #11
0
        /***************************************************/

        public static IBHoMObject FromRevit(this SpatialElement spatialElement, Discipline discipline, Transform transform = null, RevitSettings settings = null, Dictionary <string, List <IBHoMObject> > refObjects = null)
        {
            IElement2D result = null;

            switch (discipline)
            {
            case Discipline.Environmental:
                result = spatialElement.SpaceFromRevit(settings, refObjects);
                break;

            case Discipline.Facade:
            case Discipline.Architecture:
            case Discipline.Physical:
                result = spatialElement.RoomFromRevit(settings, refObjects);
                break;
            }

            if (result != null && transform?.IsIdentity == false)
            {
                TransformMatrix bHoMTransform = transform.FromRevit();
                result = result.ITransform(bHoMTransform);
            }

            return(result as IBHoMObject);
        }
Пример #12
0
 private bool CreateRoomMass(SpatialElement room)
 {
     if (!SpatialElementGeometryCalculator.CanCalculateGeometry(room))
     {
         return(false);
     }
     try
     {
         SpatialElementGeometryResults results;
         using (var calculator = new SpatialElementGeometryCalculator(doc))
         {
             results = calculator.CalculateSpatialElementGeometry(room);
         }
         using (Solid roomSolid = results.GetGeometry())
         {
             var         eid       = new ElementId(BuiltInCategory.OST_Mass);
             DirectShape roomShape = DirectShape.CreateElement(doc, eid);
             if (roomShape != null && roomSolid.Volume > 0 && roomSolid.Faces.Size > 0)
             {
                 var geomObj = new GeometryObject[] { roomSolid };
                 if (geomObj.Length > 0)
                 {
                     roomShape.SetShape(geomObj);
                     CopyAllRoomParametersToMasses(room, roomShape);
                     return(true);
                 }
             }
         }
     }
     catch (Exception ex)
     {
         System.Diagnostics.Debug.WriteLine(ex.Message);
     }
     return(false);
 }
Пример #13
0
        /***************************************************/
        /****              Public methods               ****/
        /***************************************************/

        public static List <PolyCurve> Perimeter(this SpatialElement spatialElement, RevitSettings settings = null)
        {
            if (spatialElement == null)
            {
                return(null);
            }

            IList <IList <BoundarySegment> > boundarySegments = spatialElement.GetBoundarySegments(new SpatialElementBoundaryOptions());

            if (boundarySegments == null)
            {
                return(null);
            }

            List <PolyCurve> results = new List <PolyCurve>();

            foreach (IList <BoundarySegment> boundarySegmentList in boundarySegments)
            {
                if (boundarySegmentList == null)
                {
                    continue;
                }

                List <BH.oM.Geometry.ICurve> curves = new List <ICurve>();
                foreach (BoundarySegment boundarySegment in boundarySegmentList)
                {
                    curves.Add(boundarySegment.GetCurve().IFromRevit());
                }

                results.Add(BH.Engine.Geometry.Create.PolyCurve(curves));
            }

            return(results);
        }
Пример #14
0
        /// <summary>
        ///     Gets boundary curve list of the room.
        /// </summary>
        /// <param name="room"></param>
        /// <param name="opt"></param>
        /// <returns></returns>
        public static CurveLoop GetRoomProfile(this SpatialElement room, Option opt = null)
        {
            if (room is null)
            {
                throw new ArgumentNullException(nameof(room));
            }

            if (opt == null)
            {
                opt = new Option {
                    SpatialElementBoundaryLocation = Finish
                }
            }
            ;

            var segs = room.GetBoundarySegments(opt).SelectMany(s => s);

            var result = segs.Select(s => s.GetCurve()).ToCurveLoop();

            if (result.IsOpen())
            {
                throw new InvalidDataException("The profile isn't closed!");
            }

            return(result);
        }
Пример #15
0
        /// <summary>
        ///     Curtain system parameter for ceiling, floor, etc.
        /// </summary>
        /// <param name="room"></param>
        /// <param name="typeName"></param>
        /// <param name="tplName"></param>
        public CurtainSystemParameter(SpatialElement room, string typeName, string tplName)
        {
            Room = room ?? throw new ArgumentNullException(nameof(room));

            TypeName = typeName ?? throw new ArgumentNullException(nameof(typeName));

            TemplateFileName = tplName ?? throw new ArgumentNullException(nameof(tplName));
        }
Пример #16
0
        /// <summary>
        ///     Gets the nearest planar face by ray that room cener point to element center point.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="elm"></param>
        /// <param name="room"></param>
        /// <param name="doc"></param>
        /// <param name="view"></param>
        /// <returns></returns>
        public static PlanarFace GetNearestPlanarFace <T>(this T elm, SpatialElement room, Document doc, View3D view) where T : Element
        {
            if (elm is null)
            {
                throw new ArgumentNullException(nameof(elm));
            }

            if (room is null)
            {
                throw new ArgumentNullException(nameof(room));
            }

            if (doc is null)
            {
                throw new ArgumentNullException(nameof(doc));
            }

            if (view is null)
            {
                throw new ArgumentNullException(nameof(view));
            }

            var elmCenter = elm.GetBoundingBox(doc).GetBoxCenter();

            var roomCenter = room.GetBoundingBox(doc).GetBoxCenter();

            var direction = (elmCenter - roomCenter).Normalize();

            var elmFilter = new ElementClassFilter(elm.GetType());

            var intersector = new ReferenceIntersector(elmFilter, FindReferenceTarget.Face, view);

            var context = intersector.FindNearest(roomCenter, direction);

            doc.AutoTransaction(() =>
            {
                doc.CreateModelCurve(Line.CreateBound(roomCenter, elmCenter), out _);
            });

            if (context == null)
            {
                return(null);
            }

            var reference = context.GetReference();

            var refElm = doc.GetElement(reference.ElementId);

            var face = refElm.GetGeometryObjectFromReference(reference) as Face;

            if (face is PlanarFace planarFace)
            {
                return(planarFace);
            }

            return(null);
        }
Пример #17
0
        public static List <Panel> Panels(this SpatialElement spatialElement, SpatialElementBoundaryOptions spatialElementBoundaryOptions, Core.Revit.ConvertSettings convertSettings)
        {
            if (spatialElement == null || spatialElementBoundaryOptions == null)
            {
                return(null);
            }

            SpatialElementGeometryCalculator spatialElementGeometryCalculator = new SpatialElementGeometryCalculator(spatialElement.Document, spatialElementBoundaryOptions);

            return(Panels(spatialElement, spatialElementGeometryCalculator, convertSettings));
        }
        public SpatialElementStream(ArrayList data, object elem)
        {
            this.data      = data;
            spatialElement = elem as SpatialElement;

            boundaryOptions = new SpatialElementBoundaryOptions
            {
                StoreFreeBoundaryFaces         = true,
                SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Center
            };
        }
Пример #19
0
        /***************************************************/

        public static Space SpaceFromRevit(this SpatialElement spatialElement, SpatialElementBoundaryOptions spatialElementBoundaryOptions, RevitSettings settings = null, Dictionary <string, List <IBHoMObject> > refObjects = null)
        {
            if (spatialElement == null || spatialElementBoundaryOptions == null)
            {
                return(new Space());
            }

            SpatialElementGeometryCalculator spatialElementGeometryCalculator = new SpatialElementGeometryCalculator(spatialElement.Document, spatialElementBoundaryOptions);

            return(SpaceFromRevit(spatialElement, spatialElementGeometryCalculator, settings, refObjects));
        }
Пример #20
0
        /***************************************************/
        /****               Public Methods              ****/
        /***************************************************/

        public static Space SpaceFromRevit(this SpatialElement spatialElement, RevitSettings settings = null, Dictionary <string, List <IBHoMObject> > refObjects = null)
        {
            settings = settings.DefaultIfNull();

            SpatialElementBoundaryOptions spatialElementBoundaryOptions = new SpatialElementBoundaryOptions();

            spatialElementBoundaryOptions.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Center;
            spatialElementBoundaryOptions.StoreFreeBoundaryFaces         = false;

            return(spatialElement.SpaceFromRevit(spatialElementBoundaryOptions, settings, refObjects));
        }
Пример #21
0
        /// <summary>
        ///     Gets planar face list by ray that room cener point to element center point.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="elm"></param>
        /// <param name="room"></param>
        /// <param name="doc"></param>
        /// <param name="view"></param>
        /// <returns></returns>
        public static List <PlanarFace> GetPlanarFaceList <T>(this T elm, SpatialElement room, Document doc, View3D view) where T : Element
        {
            if (elm is null)
            {
                throw new ArgumentNullException(nameof(elm));
            }

            if (room is null)
            {
                throw new ArgumentNullException(nameof(room));
            }

            if (doc is null)
            {
                throw new ArgumentNullException(nameof(doc));
            }

            if (view is null)
            {
                throw new ArgumentNullException(nameof(view));
            }

            var elmCenter = elm.GetBoundingBox(doc).GetBoxCenter();

            var roomCenter = room.GetBoundingBox(doc).GetBoxCenter();

            var direction = (elmCenter - roomCenter).Normalize();

            var elmFilter = new ElementClassFilter(elm.GetType());

            var intersector = new ReferenceIntersector(elmFilter, FindReferenceTarget.Face, view);

            var contexts = intersector.Find(roomCenter, direction);

            var results = new List <PlanarFace>();

            foreach (var context in contexts)
            {
                var reference = context.GetReference();

                var refElm = doc.GetElement(reference.ElementId);

                var face = refElm.GetGeometryObjectFromReference(reference) as Face;

                if (face is PlanarFace planarFace)
                {
                    results.Add(planarFace);
                }
            }

            return(results);
        }
Пример #22
0
        /// <summary>
        ///     Gets intersect element list.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="room"></param>
        /// <param name="doc"></param>
        /// <returns></returns>
        public static List <T> GetIntersectElements <T>(this SpatialElement room, Document doc) where T : Element
        {
            if (room is null)
            {
                throw new ArgumentNullException(nameof(room));
            }

            if (doc is null)
            {
                throw new ArgumentNullException(nameof(doc));
            }

            return(room.GetIntersectElements(doc).Where(w => w is T).Cast <T>().ToList());
        }
Пример #23
0
        public static List <Panel> Panels(this SpatialElement spatialElement, Core.Revit.ConvertSettings convertSettings)
        {
            if (spatialElement == null)
            {
                return(null);
            }

            SpatialElementBoundaryOptions spatialElementBoundaryOptions = new SpatialElementBoundaryOptions();

            spatialElementBoundaryOptions.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Center;
            spatialElementBoundaryOptions.StoreFreeBoundaryFaces         = true;

            return(Panels(spatialElement, spatialElementBoundaryOptions, convertSettings));
        }
Пример #24
0
        /***************************************************/

        public static IBHoMObject FromRevit(this SpatialElement spatialElement, Discipline discipline, RevitSettings settings = null, Dictionary <string, List <IBHoMObject> > refObjects = null)
        {
            switch (discipline)
            {
            case Discipline.Environmental:
                return(spatialElement.SpaceFromRevit(settings, refObjects));

            case Discipline.Architecture:
            case Discipline.Physical:
                return(spatialElement.RoomFromRevit(settings, refObjects));

            default:
                return(null);
            }
        }
Пример #25
0
        bool ContainsRoom(Element scopeBox, SpatialElement room)
        {
            BoundingBoxXYZ boundingBox = scopeBox.get_BoundingBox(room.Document.ActiveView);
            XYZ            min         = boundingBox.Min;
            XYZ            max         = boundingBox.Max;
            XYZ            rmPnt       = ((LocationPoint)room.Location).Point;

            if (rmPnt.X >= min.X && rmPnt.X <= max.X &&
                rmPnt.Y >= min.Y && rmPnt.Y <= max.Y &&
                rmPnt.Z >= min.Z && rmPnt.Z <= max.Z)
            {
                return(true);
            }
            return(false);
        }
Пример #26
0
        public static InternalCondition ToSAM_InternalCondition(this SpatialElement spatialElement, ConvertSettings convertSettings)
        {
            if (spatialElement == null)
            {
                return(null);
            }

            InternalCondition result = convertSettings?.GetObject <InternalCondition>(spatialElement.Id);

            if (result != null)
            {
                return(result);
            }

            string name = null;

            Core.TypeMap typeMap = ActiveSetting.Setting.GetValue <Core.TypeMap>(Core.Revit.ActiveSetting.Name.ParameterMap);
            if (typeMap != null)
            {
                string parameterName = typeMap.GetName(typeof(InternalCondition), typeof(Autodesk.Revit.DB.Mechanical.Space), "Name", 2);
                if (!string.IsNullOrWhiteSpace(parameterName))
                {
                    Parameter parameter = spatialElement.GetParameters(parameterName)?.ToList().Find(x => x.StorageType == StorageType.String);
                    if (parameter != null)
                    {
                        name = parameter.AsString();
                    }
                }

                if (string.IsNullOrWhiteSpace(name))
                {
                    name = Core.Revit.Query.Name(spatialElement);
                }

                if (string.IsNullOrWhiteSpace(name))
                {
                    name = spatialElement.Name;
                }
            }

            result = new InternalCondition(name);

            result.UpdateParameterSets(spatialElement, typeMap, null, null, false);

            convertSettings?.Add(spatialElement.Id, result);

            return(result);
        }
        /// <summary>
        /// Finds the spatial element to its associated level.
        /// </summary>
        /// <param name="exporterIFC">
        /// The ExporterIFC object.
        /// </param>
        /// <param name="element">
        /// The element.
        /// </param>
        /// <returns>
        /// The handle.
        /// </returns>
        public override IFCAnyHandle RedirectDescription(ExporterIFC exporterIFC, Element element)
        {
            SpatialElement spatialElem = element as SpatialElement;

            if (spatialElem != null)
            {
                ElementId    levelId   = spatialElem.LevelId;
                IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(levelId);
                if (levelInfo != null)
                {
                    return(levelInfo.GetBuildingStorey());
                }
            }

            return(null);
        }
        private object CreateListItem(FamilyInstance familyInstance, Phase phase)
        {
            SpatialElement spatialElement = this.GetSpatialElement(familyInstance, phase);

            if (spatialElement != null)
            {
                return(new object[]
                {
                    familyInstance.Id.IntegerValue,
                    phase.Id.IntegerValue,
                    spatialElement.Id.IntegerValue,
                    APIObjectList.GetElementId(familyInstance.DesignOption)
                });
            }
            return(null);
        }
Пример #29
0
        static public List <List <Curve> > GetCurvesListFromSpatialElement(SpatialElement spatial)
        {
            List <List <Curve> >             profiles   = new List <List <Curve> >();
            SpatialElementBoundaryOptions    opt        = new SpatialElementBoundaryOptions();
            IList <IList <BoundarySegment> > boundaries = spatial.GetBoundarySegments(opt);

            for (int i = 0; i < boundaries.Count; i++)
            {
                profiles.Add(new List <Curve>());
                foreach (BoundarySegment s in boundaries[i])
                {
                    profiles[i].Add(s.GetCurve());
                }
            }
            return(profiles);
        }
Пример #30
0
        /// <summary>
        ///     Gets boundary wall list of the room.
        /// </summary>
        /// <param name="room"></param>
        /// <param name="doc"></param>
        /// <param name="opt"></param>
        /// <returns></returns>
        public static List <Wall> GetBoundaryWallList(this SpatialElement room, Document doc, Option opt = null)
        {
            if (room is null)
            {
                throw new ArgumentNullException(nameof(room));
            }

            if (doc is null)
            {
                throw new ArgumentNullException(nameof(doc));
            }

            var results = new List <Wall>();

            if (opt == null)
            {
                opt = new Option {
                    SpatialElementBoundaryLocation = Finish
                }
            }
            ;

            var segments = room.GetBoundarySegments(opt).SelectMany(s => s);

            foreach (var segment in segments)
            {
                // It's invalid!
                if (segment.ElementId.IntegerValue == -1)
                {
                    continue;
                }

                // Because base room boundary to do, so one wall maybe be picked up some times.
                if (results.FirstOrDefault(f => f.Id == segment.ElementId) != null)
                {
                    continue;
                }

                if (doc.GetElement(segment.ElementId) is Wall wall)
                {
                    results.Add(wall);
                }
            }

            return(results);
        }
    }
        /// <summary>
        /// Exports spatial elements, including rooms, areas and spaces. 1st level space boundaries.
        /// </summary>
        /// <param name="exporterIFC">
        /// The ExporterIFC object.
        /// </param>
        /// <param name="spatialElement">
        /// The spatial element.
        /// </param>
        /// <param name="productWrapper">
        /// The ProductWrapper.
        /// </param>
        public static void ExportSpatialElement(ExporterIFC exporterIFC, SpatialElement spatialElement, ProductWrapper productWrapper)
        {
            IFCFile file = exporterIFC.GetFile();
            using (IFCTransaction transaction = new IFCTransaction(file))
            {
                using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, spatialElement, null, null))
                {
                    SpatialElementGeometryResults spatialElemGeomResult = null;
                    if (!CreateIFCSpace(exporterIFC, spatialElement, productWrapper, setter, out spatialElemGeomResult))
                        return;

                    bool isArea = (spatialElement is Area);

                    // Do not create boundary information for areas.
                    if (!isArea && (ExporterCacheManager.ExportOptionsCache.SpaceBoundaryLevel == 1))
                    {
                        Document document = spatialElement.Document;
                        ElementId levelId = spatialElement.LevelId;
                        IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(levelId);
                  double baseHeightNonScaled = (levelInfo != null) ? levelInfo.Elevation : 0.0;

                        try
                        {
                            // This can throw an exception.  If it does, continue to export element without boundary information.
                            // We will re-use the previously generated value, if we have it.
                            // TODO: warn user.
                            if (spatialElemGeomResult == null)
                                spatialElemGeomResult = s_SpatialElementGeometryCalculator.CalculateSpatialElementGeometry(spatialElement);

                            Solid spatialElemGeomSolid = spatialElemGeomResult.GetGeometry();
                            FaceArray faces = spatialElemGeomSolid.Faces;
                            foreach (Face face in faces)
                            {
                                IList<SpatialElementBoundarySubface> spatialElemBoundarySubfaces = spatialElemGeomResult.GetBoundaryFaceInfo(face);
                                foreach (SpatialElementBoundarySubface spatialElemBSubface in spatialElemBoundarySubfaces)
                                {
                                    if (spatialElemBSubface.SubfaceType == SubfaceType.Side)
                                        continue;

                                    if (spatialElemBSubface.GetSubface() == null)
                                        continue;

                                    ElementId elemId = spatialElemBSubface.SpatialBoundaryElement.LinkInstanceId;
                                    if (elemId == ElementId.InvalidElementId)
                                    {
                                        elemId = spatialElemBSubface.SpatialBoundaryElement.HostElementId;
                                    }

                                    Element boundingElement = document.GetElement(elemId);
                                    if (boundingElement == null)
                                        continue;

                                    bool isObjectExt = CategoryUtil.IsElementExternal(boundingElement);

                                    IFCGeometryInfo info = IFCGeometryInfo.CreateSurfaceGeometryInfo(spatialElement.Document.Application.VertexTolerance);

                                    Face subFace = spatialElemBSubface.GetSubface();
                                    ExporterIFCUtils.CollectGeometryInfo(exporterIFC, info, subFace, XYZ.Zero, false);

                                    foreach (IFCAnyHandle surfaceHnd in info.GetSurfaces())
                                    {
                                        IFCAnyHandle connectionGeometry = IFCInstanceExporter.CreateConnectionSurfaceGeometry(file, surfaceHnd, null);

                                        SpaceBoundary spaceBoundary = new SpaceBoundary(spatialElement.Id, boundingElement.Id, setter.LevelId, connectionGeometry, IFCPhysicalOrVirtual.Physical,
                                            isObjectExt ? IFCInternalOrExternal.External : IFCInternalOrExternal.Internal);

                                        if (!ProcessIFCSpaceBoundary(exporterIFC, spaceBoundary, file))
                                            ExporterCacheManager.SpaceBoundaryCache.Add(spaceBoundary);
                                    }
                                }
                            }
                        }
                        catch
                        {
                        }

                        IList<IList<BoundarySegment>> roomBoundaries = spatialElement.GetBoundarySegments(GetSpatialElementBoundaryOptions(spatialElement));
                        double scaledRoomHeight = GetScaledHeight(spatialElement, levelId, levelInfo);
                        double unscaledHeight = UnitUtil.UnscaleLength(scaledRoomHeight);

                        Plane xyPlane = new Plane(XYZ.BasisZ, XYZ.Zero);

                        foreach (IList<BoundarySegment> roomBoundaryList in roomBoundaries)
                        {
                            foreach (BoundarySegment roomBoundary in roomBoundaryList)
                            {
                                Element boundingElement = roomBoundary.Element;

                                if (boundingElement == null)
                                    continue;

                                ElementId buildingElemId = boundingElement.Id;
                                Curve trimmedCurve = roomBoundary.Curve;

                                if (trimmedCurve == null)
                                    continue;

                                //trimmedCurve.Visibility = Visibility.Visible; readonly
                                IFCAnyHandle connectionGeometry = ExtrusionExporter.CreateConnectionSurfaceGeometry(
                                   exporterIFC, trimmedCurve, xyPlane, scaledRoomHeight, baseHeightNonScaled);

                                IFCPhysicalOrVirtual physOrVirt = IFCPhysicalOrVirtual.Physical;
                                if (boundingElement is CurveElement)
                                    physOrVirt = IFCPhysicalOrVirtual.Virtual;
                                else if (boundingElement is Autodesk.Revit.DB.Architecture.Room)
                                    physOrVirt = IFCPhysicalOrVirtual.NotDefined;

                                bool isObjectExt = CategoryUtil.IsElementExternal(boundingElement);
                                bool isObjectPhys = (physOrVirt == IFCPhysicalOrVirtual.Physical);

                                ElementId actualBuildingElemId = isObjectPhys ? buildingElemId : ElementId.InvalidElementId;

                                SpaceBoundary spaceBoundary = new SpaceBoundary(spatialElement.Id, actualBuildingElemId, setter.LevelId, !IFCAnyHandleUtil.IsNullOrHasNoValue(connectionGeometry) ? connectionGeometry : null,
                                    physOrVirt, isObjectExt ? IFCInternalOrExternal.External : IFCInternalOrExternal.Internal);

                                if (!ProcessIFCSpaceBoundary(exporterIFC, spaceBoundary, file))
                                    ExporterCacheManager.SpaceBoundaryCache.Add(spaceBoundary);

                                // try to add doors and windows for host objects if appropriate.
                                if (isObjectPhys && boundingElement is HostObject)
                                {
                                    HostObject hostObj = boundingElement as HostObject;
                                    HashSet<ElementId> elemIds = new HashSet<ElementId>();
                                    elemIds.UnionWith(hostObj.FindInserts(false, false, false, false));
                                    if (elemIds.Count == 0)
                                    {
                                        CurtainGridSet curtainGridSet = CurtainSystemExporter.GetCurtainGridSet(hostObj);
                                        if (curtainGridSet != null)
                                        {
                                            foreach (CurtainGrid curtainGrid in curtainGridSet)
                                                elemIds.UnionWith(CurtainSystemExporter.GetVisiblePanelsForGrid(curtainGrid));
                                        }
                                    }

                                    foreach (ElementId elemId in elemIds)
                                    {
                                        // we are going to do a simple bbox export, not complicated geometry.
                                        Element instElem = document.GetElement(elemId);
                                        if (instElem == null)
                                            continue;

                                        BoundingBoxXYZ instBBox = instElem.get_BoundingBox(null);
                                        if (instBBox == null)
                                            continue;

                                        // make copy of original trimmed curve.
                                        Curve instCurve = trimmedCurve.Clone();
                                        XYZ instOrig = instCurve.GetEndPoint(0);

                                        // make sure that the insert is on this level.
                                        if (instBBox.Max.Z < instOrig.Z)
                                            continue;
                                        if (instBBox.Min.Z > instOrig.Z + unscaledHeight)
                                            continue;

                                        double insHeight = Math.Min(instBBox.Max.Z, instOrig.Z + unscaledHeight) - Math.Max(instOrig.Z, instBBox.Min.Z);
                                        if (insHeight < (1.0 / (12.0 * 16.0)))
                                            continue;

                                        // move base curve to bottom of bbox.
                                        XYZ moveDir = new XYZ(0.0, 0.0, instBBox.Min.Z - instOrig.Z);
                                        Transform moveTrf = Transform.CreateTranslation(moveDir);
                                        instCurve = instCurve.CreateTransformed(moveTrf);

                                        bool isHorizOrVert = false;
                                        if (instCurve is Line)
                                        {
                                            Line instLine = instCurve as Line;
                                            XYZ lineDir = instLine.Direction;
                                            if (MathUtil.IsAlmostEqual(Math.Abs(lineDir.X), 1.0) || (MathUtil.IsAlmostEqual(Math.Abs(lineDir.Y), 1.0)))
                                                isHorizOrVert = true;
                                        }

                                        double[] parameters = new double[2];
                                        double[] origEndParams = new double[2];
                                        bool paramsSet = false;

                                        if (!isHorizOrVert)
                                        {
                                            FamilyInstance famInst = instElem as FamilyInstance;
                                            if (famInst == null)
                                                continue;

                                            ElementType elementType = document.GetElement(famInst.GetTypeId()) as ElementType;
                                            if (elementType == null)
                                                continue;

                                            BoundingBoxXYZ symBBox = elementType.get_BoundingBox(null);
                                            if (symBBox != null)
                                            {
                                                Curve symCurve = trimmedCurve.Clone();
                                                Transform trf = famInst.GetTransform();
                                                Transform invTrf = trf.Inverse;
                                                Curve trfCurve = symCurve.CreateTransformed(invTrf);
                                                parameters[0] = trfCurve.Project(symBBox.Min).Parameter;
                                                parameters[1] = trfCurve.Project(symBBox.Max).Parameter;
                                                paramsSet = true;
                                            }
                                        }

                                        if (!paramsSet)
                                        {
                                            parameters[0] = instCurve.Project(instBBox.Min).Parameter;
                                            parameters[1] = instCurve.Project(instBBox.Max).Parameter;
                                        }

                                        // ignore if less than 1/16".
                                        if (Math.Abs(parameters[1] - parameters[0]) < 1.0 / (12.0 * 16.0))
                                            continue;
                                        if (parameters[0] > parameters[1])
                                        {
                                            //swap
                                            double tempParam = parameters[0];
                                            parameters[0] = parameters[1];
                                            parameters[1] = tempParam;
                                        }

                                        origEndParams[0] = instCurve.GetEndParameter(0);
                                        origEndParams[1] = instCurve.GetEndParameter(1);

                                        if (origEndParams[0] > parameters[1] - (1.0 / (12.0 * 16.0)))
                                            continue;
                                        if (origEndParams[1] < parameters[0] + (1.0 / (12.0 * 16.0)))
                                            continue;

                                        instCurve.MakeBound(parameters[0] > origEndParams[0] ? parameters[0] : origEndParams[0],
                                                            parameters[1] < origEndParams[1] ? parameters[1] : origEndParams[1]);

                                        double insHeightScaled = UnitUtil.ScaleLength(insHeight);
                                        IFCAnyHandle insConnectionGeom = ExtrusionExporter.CreateConnectionSurfaceGeometry(exporterIFC, instCurve, xyPlane,
                                           insHeightScaled, baseHeightNonScaled);

                                        SpaceBoundary instBoundary = new SpaceBoundary(spatialElement.Id, elemId, setter.LevelId, !IFCAnyHandleUtil.IsNullOrHasNoValue(insConnectionGeom) ? insConnectionGeom : null, physOrVirt,
                                            isObjectExt ? IFCInternalOrExternal.External : IFCInternalOrExternal.Internal);
                                        if (!ProcessIFCSpaceBoundary(exporterIFC, instBoundary, file))
                                            ExporterCacheManager.SpaceBoundaryCache.Add(instBoundary);
                                    }
                                }
                            }
                        }
                    }

                    CreateZoneInfos(exporterIFC, file, spatialElement, productWrapper);
                    CreateSpaceOccupantInfo(exporterIFC, file, spatialElement, productWrapper);
                }
                transaction.Commit();
            }
        }
        /// <summary>
        /// Creates IFC room/space/area item, not include boundaries. 
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="spatialElement">The spatial element.</param>
        /// <param name="productWrapper">The ProductWrapper.</param>
        /// <param name="setter">The PlacementSetter.</param>
        /// <returns>True if created successfully, false otherwise.</returns>
        static bool CreateIFCSpace(ExporterIFC exporterIFC, SpatialElement spatialElement, ProductWrapper productWrapper, 
            PlacementSetter setter, out SpatialElementGeometryResults results)
        {
            results = null;

            IList<CurveLoop> curveLoops = null;
            try
            {
                // Avoid throwing for a spatial element with no location.
                if (spatialElement.Location == null)
                    return false;

                SpatialElementBoundaryOptions options = GetSpatialElementBoundaryOptions(spatialElement);
                curveLoops = ExporterIFCUtils.GetRoomBoundaryAsCurveLoopArray(spatialElement, options, true);
            }
            catch (Autodesk.Revit.Exceptions.InvalidOperationException)
            {
                //Some spatial elements are not placed that have no boundary loops. Don't export them.
                return false;
            }

            Autodesk.Revit.DB.Document document = spatialElement.Document;
            ElementId levelId = spatialElement.LevelId;

            ElementId catId = spatialElement.Category != null ? spatialElement.Category.Id : ElementId.InvalidElementId;

            double dArea = 0.0;
            if (ParameterUtil.GetDoubleValueFromElement(spatialElement, BuiltInParameter.ROOM_AREA, out dArea) != null)
                dArea = UnitUtil.ScaleArea(dArea);

            IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(levelId);

            string strSpaceNumber = null;
            string strSpaceName = null;
            string strSpaceDesc = null;

            if (ParameterUtil.GetStringValueFromElement(spatialElement, BuiltInParameter.ROOM_NUMBER, out strSpaceNumber) == null)
                strSpaceNumber = null;

            if (ParameterUtil.GetStringValueFromElement(spatialElement, BuiltInParameter.ROOM_NAME, out strSpaceName) == null)
                strSpaceName = null;

            if (ParameterUtil.GetStringValueFromElement(spatialElement, BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS, out strSpaceDesc) == null)
                strSpaceDesc = null;

            string name = strSpaceNumber;
            string longName = strSpaceName;
            string desc = strSpaceDesc;

            IFCFile file = exporterIFC.GetFile();

            IFCAnyHandle localPlacement = setter.LocalPlacement;
            ElementType elemType = document.GetElement(spatialElement.GetTypeId()) as ElementType;
            IFCInternalOrExternal internalOrExternal = CategoryUtil.IsElementExternal(spatialElement) ? IFCInternalOrExternal.External : IFCInternalOrExternal.Internal;

            double scaledRoomHeight = GetScaledHeight(spatialElement, levelId, levelInfo);
            if (scaledRoomHeight <= 0.0)
                return false;

            double bottomOffset;
            ParameterUtil.GetDoubleValueFromElement(spatialElement, BuiltInParameter.ROOM_LOWER_OFFSET, out bottomOffset);

         double elevation = (levelInfo != null) ? levelInfo.Elevation : 0.0;
            XYZ zDir = new XYZ(0, 0, 1);
         XYZ orig = new XYZ(0, 0, elevation + bottomOffset);

            Plane plane = new Plane(zDir, orig); // room calculated as level offset.

            GeometryElement geomElem = null;
            bool isArea = (spatialElement is Area);
            Area spatialElementAsArea = isArea ? (spatialElement as Area) : null;

            if (spatialElement is Autodesk.Revit.DB.Architecture.Room)
            {
                Autodesk.Revit.DB.Architecture.Room room = spatialElement as Autodesk.Revit.DB.Architecture.Room;
                geomElem = room.ClosedShell;
            }
            else if (spatialElement is Autodesk.Revit.DB.Mechanical.Space)
            {
                Autodesk.Revit.DB.Mechanical.Space space = spatialElement as Autodesk.Revit.DB.Mechanical.Space;
                geomElem = space.ClosedShell;
            }
            else if (isArea)
            {
                Options geomOptions = GeometryUtil.GetIFCExportGeometryOptions();
                geomElem = spatialElementAsArea.get_Geometry(geomOptions);
            }

            IFCAnyHandle spaceHnd = null;
            string spatialElementName = null;
            using (IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData())
            {
                extraParams.SetLocalPlacement(localPlacement);
                extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ;

                using (IFCTransaction transaction2 = new IFCTransaction(file))
                {
                    IFCAnyHandle repHnd = null;
                    if (!ExporterCacheManager.ExportOptionsCache.Use2DRoomBoundaryForRoomVolumeCreation && geomElem != null)
                    {
                        BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true);
                        bodyExporterOptions.TessellationLevel = BodyExporter.GetTessellationLevel();
                        repHnd = RepresentationUtil.CreateAppropriateProductDefinitionShape(exporterIFC, spatialElement,
                            catId, geomElem, bodyExporterOptions, null, extraParams, false);
                        if (IFCAnyHandleUtil.IsNullOrHasNoValue(repHnd))
                            extraParams.ClearOpenings();
                    }
                    else
                    {
                        IFCAnyHandle shapeRep = ExtrusionExporter.CreateExtrudedSolidFromCurveLoop(exporterIFC, null, curveLoops, plane, zDir, scaledRoomHeight);
                        if (IFCAnyHandleUtil.IsNullOrHasNoValue(shapeRep))
                            return false;
                        IFCAnyHandle styledItemHnd = BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, document,
                            shapeRep, ElementId.InvalidElementId);

                        HashSet<IFCAnyHandle> bodyItems = new HashSet<IFCAnyHandle>();
                        bodyItems.Add(shapeRep);
                        shapeRep = RepresentationUtil.CreateSweptSolidRep(exporterIFC, spatialElement, catId, exporterIFC.Get3DContextHandle("Body"), bodyItems, null);
                        IList<IFCAnyHandle> shapeReps = new List<IFCAnyHandle>();
                        shapeReps.Add(shapeRep);

                        IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geomElem, Transform.Identity);
                        if (boundingBoxRep != null)
                            shapeReps.Add(boundingBoxRep);

                        repHnd = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, shapeReps);
                    }

                    extraParams.ScaledHeight = scaledRoomHeight;
                    extraParams.ScaledArea = dArea;

                    spatialElementName = NamingUtil.GetNameOverride(spatialElement, name);
                    string spatialElementDescription = NamingUtil.GetDescriptionOverride(spatialElement, desc);
                    string spatialElementObjectType = NamingUtil.GetObjectTypeOverride(spatialElement, null);
                    string spatialElementLongName = NamingUtil.GetLongNameOverride(spatialElement, longName);
                    
                    double? spaceElevationWithFlooring = null;
                    double elevationWithFlooring = 0.0;
                    if (ParameterUtil.GetDoubleValueFromElement(spatialElement, null, "IfcElevationWithFlooring", out elevationWithFlooring) != null)
                        spaceElevationWithFlooring = UnitUtil.ScaleLength(elevationWithFlooring);
                    spaceHnd = IFCInstanceExporter.CreateSpace(file, GUIDUtil.CreateGUID(spatialElement),
                                                  ExporterCacheManager.OwnerHistoryHandle,
                                                  spatialElementName, spatialElementDescription, spatialElementObjectType,
                                                  extraParams.GetLocalPlacement(), repHnd, spatialElementLongName, Toolkit.IFCElementComposition.Element,
                                                  internalOrExternal, spaceElevationWithFlooring);

                    transaction2.Commit();
                }

                if (spaceHnd != null)
                {
                    productWrapper.AddSpace(spatialElement, spaceHnd, levelInfo, extraParams, true);
                    if (isArea)
                    {
                        Element areaScheme = spatialElementAsArea.AreaScheme;
                        if (areaScheme != null)
                        {
                            ElementId areaSchemeId = areaScheme.Id;
                            HashSet<IFCAnyHandle> areas = null;
                            if (!ExporterCacheManager.AreaSchemeCache.TryGetValue(areaSchemeId, out areas))
                            {
                                areas = new HashSet<IFCAnyHandle>();
                                ExporterCacheManager.AreaSchemeCache[areaSchemeId] = areas;
                            }
                            areas.Add(spaceHnd);
                        }
                    }
                }
            }

            // Save room handle for later use/relationships
            ExporterCacheManager.SpaceInfoCache.SetSpaceHandle(spatialElement, spaceHnd);

            // Find Ceiling as a Space boundary and keep the relationship in a cache for use later
            bool ret = GetCeilingSpaceBoundary(spatialElement, out results);

         if (!MathUtil.IsAlmostZero(dArea) && !(ExporterCacheManager.ExportOptionsCache.ExportAsCOBIE) &&
                !ExporterCacheManager.ExportOptionsCache.ExportAs2x3CoordinationView2 && !ExporterCacheManager.ExportOptionsCache.ExportBaseQuantities)
            {
                bool isDesignGrossArea = (string.Compare(spatialElementName, "GSA Design Gross Area") > 0);
                PropertyUtil.CreatePreCOBIEGSAQuantities(exporterIFC, spaceHnd, "GSA Space Areas", (isDesignGrossArea ? "GSA Design Gross Area" : "GSA BIM Area"), dArea);
            }

            // Export Classifications for SpatialElement for GSA/COBIE.
         if (ExporterCacheManager.ExportOptionsCache.ExportAsCOBIE)
            {
                ProjectInfo projectInfo = document.ProjectInformation;
                if (projectInfo != null)
                    CreateCOBIESpaceClassifications(exporterIFC, file, spaceHnd, projectInfo, spatialElement);
            }

            return true;
        }
        /// <summary>
        /// Creates COBIESpaceClassifications.
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC.</param>
        /// <param name="file">The file.</param>
        /// <param name="spaceHnd">The space handle.</param>
        /// <param name="projectInfo">The project info.</param>
        /// <param name="spatialElement">The spatial element.</param>
        private static void CreateCOBIESpaceClassifications(ExporterIFC exporterIFC, IFCFile file, IFCAnyHandle spaceHnd,
            ProjectInfo projectInfo, SpatialElement spatialElement)
        {
            HashSet<IFCAnyHandle> spaceHnds = new HashSet<IFCAnyHandle>();
            spaceHnds.Add(spaceHnd);

            string bimStandardsLocation = null;
            if (projectInfo != null)
                ParameterUtil.GetStringValueFromElement(projectInfo.Id, "BIM Standards URL", out bimStandardsLocation);

            // OCCS - Space by Function.
            string itemReference = "";
            if (ParameterUtil.GetStringValueFromElement(spatialElement.Id, "OmniClass Number", out itemReference) != null)
            {
                string itemName;
                ParameterUtil.GetStringValueFromElement(spatialElement.Id, "OmniClass Title", out itemName);

                IFCAnyHandle classification;
                if (!ExporterCacheManager.ClassificationCache.ClassificationHandles.TryGetValue("OmniClass", out classification))
                {
                    classification = IFCInstanceExporter.CreateClassification(file, "http://www.omniclass.org", "v 1.0", null, "OmniClass");
                    ExporterCacheManager.ClassificationCache.ClassificationHandles.Add("OmniClass", classification);
                }

                IFCAnyHandle classificationReference = IFCInstanceExporter.CreateClassificationReference(file,
                  "http://www.omniclass.org/tables/OmniClass_13_2006-03-28.pdf", itemReference, itemName, classification);
                IFCAnyHandle relAssociates = IFCInstanceExporter.CreateRelAssociatesClassification(file, GUIDUtil.CreateGUID(),
                   ExporterCacheManager.OwnerHistoryHandle, "OmniClass", null, spaceHnds, classificationReference);
            }

            // Space Type (Owner)
            itemReference = "";
            if (ParameterUtil.GetStringValueFromElement(spatialElement.Id, "Space Type (Owner) Reference", out itemReference) != null)
            {
                string itemName;
                ParameterUtil.GetStringValueFromElement(spatialElement.Id, "Space Type (Owner) Name", out itemName);

                IFCAnyHandle classificationReference = IFCInstanceExporter.CreateClassificationReference(file,
                  bimStandardsLocation, itemReference, itemName, null);
                IFCAnyHandle relAssociates = IFCInstanceExporter.CreateRelAssociatesClassification(file, GUIDUtil.CreateGUID(),
                   ExporterCacheManager.OwnerHistoryHandle, "Space Type (Owner)", null, spaceHnds, classificationReference);
            }

            // Space Category (Owner)
            itemReference = "";
            if (ParameterUtil.GetStringValueFromElement(spatialElement.Id, "Space Category (Owner) Reference", out itemReference) != null)
            {
                string itemName;
                ParameterUtil.GetStringValueFromElement(spatialElement.Id, "Space Category (Owner) Name", out itemName);

                IFCAnyHandle classificationReference = IFCInstanceExporter.CreateClassificationReference(file,
                  bimStandardsLocation, itemReference, itemName, null);
                IFCAnyHandle relAssociates = IFCInstanceExporter.CreateRelAssociatesClassification(file, GUIDUtil.CreateGUID(),
                   ExporterCacheManager.OwnerHistoryHandle, "Space Category (Owner)", null, spaceHnds, classificationReference);
            }

            // Space Category (BOMA)
            itemReference = "";
            if (ParameterUtil.GetStringValueFromElement(spatialElement.Id, "Space Category (BOMA) Reference", out itemReference) != null)
            {
                string itemName;
                ParameterUtil.GetStringValueFromElement(spatialElement.Id, "Space Category (BOMA) Name", out itemName);

                IFCAnyHandle classificationReference = IFCInstanceExporter.CreateClassificationReference(file,
                  "http://www.BOMA.org", itemReference, itemName, null);
                IFCAnyHandle relAssociates = IFCInstanceExporter.CreateRelAssociatesClassification(file, GUIDUtil.CreateGUID(),
                   ExporterCacheManager.OwnerHistoryHandle, "Space Category (BOMA)", "", spaceHnds, classificationReference);
            }
        }
        /// <summary>
        /// Gets the height of a spatial element.
        /// </summary>
        /// <param name="spatialElement">The spatial element.</param>
        /// <param name="levelId">The level id.</param>
        /// <param name="levelInfo">The level info.</param>
        /// <returns>
        /// The height, scaled in IFC units.
        /// </returns>
        static double GetScaledHeight(SpatialElement spatialElement, ElementId levelId, IFCLevelInfo levelInfo)
        {
            Document document = spatialElement.Document;
            bool isArea = spatialElement is Area;

            ElementId topLevelId = ElementId.InvalidElementId;
            double topOffset = 0.0;

            // These values are internally set for areas, but are invalid.  Ignore them and just use the level height.
            if (!isArea)
            {
                ParameterUtil.GetElementIdValueFromElement(spatialElement, BuiltInParameter.ROOM_UPPER_LEVEL, out topLevelId);
                ParameterUtil.GetDoubleValueFromElement(spatialElement, BuiltInParameter.ROOM_UPPER_OFFSET, out topOffset);
            }

            double bottomOffset;
            ParameterUtil.GetDoubleValueFromElement(spatialElement, BuiltInParameter.ROOM_LOWER_OFFSET, out bottomOffset);

            Level bottomLevel = document.GetElement(levelId) as Level;
            Level topLevel =
               (levelId == topLevelId) ? bottomLevel : document.GetElement(topLevelId) as Level;

            double roomHeight = 0.0;
            if (bottomLevel != null && topLevel != null)
            {
                roomHeight = (topLevel.Elevation - bottomLevel.Elevation) + (topOffset - bottomOffset);
                roomHeight = UnitUtil.ScaleLength(roomHeight);
            }

            if (MathUtil.IsAlmostZero(roomHeight))
            {
                double levelHeight = ExporterCacheManager.LevelInfoCache.FindHeight(levelId);
                if (levelHeight < 0.0)
                    levelHeight = LevelUtil.CalculateDistanceToNextLevel(document, levelId, levelInfo);

                roomHeight = UnitUtil.ScaleLength(levelHeight);
            }

            // For area spaces, we assign a dummy height (1 unit), as we are not allowed to export IfcSpaces without a volumetric representation.
            if (MathUtil.IsAlmostZero(roomHeight) && spatialElement is Area)
            {
                roomHeight = 1.0;
            }

            return roomHeight;
        }
        /// <summary>
        /// Gets the boundary options of a spatial element.
        /// </summary>
        /// <param name="spatialElement">The spatial element. null to get the default options.</param>
        /// <returns>The SpatialElementBoundaryOptions.</returns>
        static SpatialElementBoundaryOptions GetSpatialElementBoundaryOptions(SpatialElement spatialElement)
        {
            SpatialElementBoundaryOptions spatialElementBoundaryOptions = new SpatialElementBoundaryOptions();
            spatialElementBoundaryOptions.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Finish;

            if (spatialElement == null)
                return spatialElementBoundaryOptions;

            SpatialElementType spatialElementType = SpatialElementType.Room;
            if (spatialElement is Autodesk.Revit.DB.Architecture.Room)
            {
                spatialElementType = SpatialElementType.Room;
            }
            else if (spatialElement is Area)
            {
                spatialElementType = SpatialElementType.Area;
            }
            else if (spatialElement is Autodesk.Revit.DB.Mechanical.Space)
            {
                spatialElementType = SpatialElementType.Space;
            }
            else
                return spatialElementBoundaryOptions;

            AreaVolumeSettings areaSettings = AreaVolumeSettings.GetAreaVolumeSettings(spatialElement.Document);
            if (areaSettings != null)
            {
                spatialElementBoundaryOptions.SpatialElementBoundaryLocation = areaSettings.GetSpatialElementBoundaryLocation(spatialElementType);
            }

            return spatialElementBoundaryOptions;
        }
        /// <summary>
        /// Creates IFC room/space/area item, not include boundaries. 
        /// </summary>
        /// <param name="exporterIFC">
        /// The ExporterIFC object.
        /// </param>
        /// <param name="spatialElement">
        /// The spatial element.
        /// </param>
        /// <param name="productWrapper">
        /// The ProductWrapper.
        /// </param>
        /// <param name="setter">
        /// The IFCPlacementSetter.
        /// </param>
        /// <returns>
        /// True if created successfully, false otherwise.
        /// </returns>
        static bool CreateIFCSpace(ExporterIFC exporterIFC, SpatialElement spatialElement, ProductWrapper productWrapper, IFCPlacementSetter setter)
        {
            IList<CurveLoop> curveLoops = null;
            try
            {
                SpatialElementBoundaryOptions options = ExporterIFCUtils.GetSpatialElementBoundaryOptions(exporterIFC, spatialElement);
                curveLoops = ExporterIFCUtils.GetRoomBoundaryAsCurveLoopArray(spatialElement, options, true);
            }
            catch (Autodesk.Revit.Exceptions.InvalidOperationException)
            {
                //Some spatial elements are not placed that have no boundary loops. Don't export them.
                return false;
            }

            Autodesk.Revit.DB.Document document = spatialElement.Document;
            ElementId levelId = spatialElement.Level != null ? spatialElement.Level.Id : ElementId.InvalidElementId;
            double scale = exporterIFC.LinearScale;

            ElementId catId = spatialElement.Category != null ? spatialElement.Category.Id : ElementId.InvalidElementId;

            double dArea = 0.0;
            if (ParameterUtil.GetDoubleValueFromElement(spatialElement, BuiltInParameter.ROOM_AREA, out dArea))
                dArea *= (scale * scale);

            IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(levelId);

            string strSpaceNumber = null;
            string strSpaceName = null;
            string strSpaceDesc = null;

            bool isArea = spatialElement is Area;
            if (!isArea)
            {
                if (!ParameterUtil.GetStringValueFromElement(spatialElement, BuiltInParameter.ROOM_NUMBER, out strSpaceNumber))
                    strSpaceNumber = null;

                if (!ParameterUtil.GetStringValueFromElement(spatialElement, BuiltInParameter.ROOM_NAME, out strSpaceName))
                    strSpaceName = null;

                if (!ParameterUtil.GetStringValueFromElement(spatialElement, BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS, out strSpaceDesc))
                    strSpaceDesc = null;
            }
            else
            {
                // Default to true to preserve previous behavior.
                bool? exportGSADesignGrossArea = ExporterCacheManager.ExportOptionsCache.ExportGSAGrossDesignArea;
                if (!exportGSADesignGrossArea.HasValue || exportGSADesignGrossArea.Value)
                {
                    Element level = document.GetElement(levelId);
                    if (level != null)
                    {
                        strSpaceNumber = level.Name + " GSA Design Gross Area";
                    }
                }
            }

            string name = strSpaceNumber;
            string longName = strSpaceName;
            string desc = strSpaceDesc;

            IFCFile file = exporterIFC.GetFile();

            IFCAnyHandle localPlacement = setter.GetPlacement();
            ElementType elemType = document.GetElement(spatialElement.GetTypeId()) as ElementType;
            IFCInternalOrExternal internalOrExternal = CategoryUtil.IsElementExternal(spatialElement, true) ? IFCInternalOrExternal.External : IFCInternalOrExternal.Internal;

            double roomHeight = 0.0;

            roomHeight = GetHeight(spatialElement, scale, levelId, levelInfo);
            if (roomHeight <= 0.0)
                return false;

            double bottomOffset;
            ParameterUtil.GetDoubleValueFromElement(spatialElement, BuiltInParameter.ROOM_LOWER_OFFSET, out bottomOffset);

            XYZ zDir = new XYZ(0, 0, 1);
            XYZ orig = new XYZ(0, 0, levelInfo.Elevation + bottomOffset);

            Plane plane = new Plane(zDir, orig); // room calculated as level offset.

            GeometryElement geomElem = null;
            if (spatialElement is Autodesk.Revit.DB.Architecture.Room)
            {
                Autodesk.Revit.DB.Architecture.Room room = spatialElement as Autodesk.Revit.DB.Architecture.Room;
                geomElem = room.ClosedShell;
            }
            else if (spatialElement is Autodesk.Revit.DB.Mechanical.Space)
            {
                Autodesk.Revit.DB.Mechanical.Space space = spatialElement as Autodesk.Revit.DB.Mechanical.Space;
                geomElem = space.ClosedShell;
            }

            IFCAnyHandle spaceHnd = null;
            using (IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData())
            {
                extraParams.SetLocalPlacement(localPlacement);
                extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ;

                using (IFCTransaction transaction2 = new IFCTransaction(file))
                {
                    IFCAnyHandle repHnd = null;
                    if (!ExporterCacheManager.ExportOptionsCache.Use2DRoomBoundaryForRoomVolumeCreation && geomElem != null)
                    {
                        BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true);
                        bodyExporterOptions.TessellationLevel = BodyExporterOptions.BodyTessellationLevel.Coarse;
                        repHnd = RepresentationUtil.CreateAppropriateProductDefinitionShape(exporterIFC, spatialElement,
                            catId, geomElem, bodyExporterOptions, null, extraParams);
                        if (IFCAnyHandleUtil.IsNullOrHasNoValue(repHnd))
                            extraParams.ClearOpenings();
                    }
                    else
                    {
                        IFCAnyHandle shapeRep = ExtrusionExporter.CreateExtrudedSolidFromCurveLoop(exporterIFC, null, curveLoops, plane, zDir, roomHeight);
                        if (IFCAnyHandleUtil.IsNullOrHasNoValue(shapeRep))
                            return false;
                        IFCAnyHandle styledItemHnd = BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, document,
                            shapeRep, ElementId.InvalidElementId);

                        HashSet<IFCAnyHandle> bodyItems = new HashSet<IFCAnyHandle>();
                        bodyItems.Add(shapeRep);
                        shapeRep = RepresentationUtil.CreateSweptSolidRep(exporterIFC, spatialElement, catId, exporterIFC.Get3DContextHandle("Body"), bodyItems, null);
                        IList<IFCAnyHandle> shapeReps = new List<IFCAnyHandle>();
                        shapeReps.Add(shapeRep);

                        IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geomElem, Transform.Identity);
                        if (boundingBoxRep != null)
                            shapeReps.Add(boundingBoxRep);

                        repHnd = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, shapeReps);
                    }

                    extraParams.ScaledHeight = roomHeight;
                    extraParams.ScaledArea = dArea;

                    string spatialElementName = NamingUtil.GetNameOverride(spatialElement, name);
                    string spatialElementDescription = NamingUtil.GetDescriptionOverride(spatialElement, desc);
                    string spatialElementObjectType = NamingUtil.GetObjectTypeOverride(spatialElement, null);

                    double? spaceElevationWithFlooring = null;
                    double elevationWithFlooring = 0.0;
                    if (ParameterUtil.GetDoubleValueFromElement(spatialElement, "IfcElevationWithFlooring", out elevationWithFlooring) == true)
                        spaceElevationWithFlooring = elevationWithFlooring;
                    spaceHnd = IFCInstanceExporter.CreateSpace(file, GUIDUtil.CreateGUID(spatialElement),
                                                  exporterIFC.GetOwnerHistoryHandle(),
                                                  spatialElementName,spatialElementDescription, spatialElementObjectType,
                                                  extraParams.GetLocalPlacement(), repHnd, longName, Toolkit.IFCElementComposition.Element,
                                                  internalOrExternal, spaceElevationWithFlooring);

                    transaction2.Commit();
                }

                productWrapper.AddSpace(spaceHnd, levelInfo, extraParams, true);
            }

            // Save room handle for later use/relationships
            ExporterCacheManager.SpatialElementHandleCache.Register(spatialElement.Id, spaceHnd);
            exporterIFC.RegisterSpatialElementHandle(spatialElement.Id, spaceHnd);

            // Find Ceiling as a Space boundary and keep the relationship in a cache for use later
            Boolean ret = getCeilingSpaceBoundary(spatialElement);

            if (!MathUtil.IsAlmostZero(dArea) && !(ExporterCacheManager.ExportOptionsCache.FileVersion == IFCVersion.IFCCOBIE) &&
                !ExporterCacheManager.ExportOptionsCache.ExportAs2x3CoordinationView2 && !ExporterCacheManager.ExportOptionsCache.ExportBaseQuantities)
            {
                ExporterIFCUtils.CreatePreCOBIEGSAQuantities(exporterIFC, spaceHnd, "GSA Space Areas", (isArea ? "GSA Design Gross Area" : "GSA BIM Area"), dArea);
            }

            // Export BaseQuantities for SpatialElement
            if (ExporterCacheManager.ExportOptionsCache.ExportBaseQuantities && !(ExporterCacheManager.ExportOptionsCache.FileVersion == IFCVersion.IFCCOBIE))
            {
                // Skip this step. The "standard" quantities will be exported at the end of export element process in exportElement (Exporter.cs)
                // ExporterIFCUtils.CreateNonCOBIERoomQuantities(exporterIFC, spaceHnd, spatialElement, dArea, roomHeight);
            }

            // Create general classification for Spatial element from ClassificationCode(s). This is not done here but rather at the end of exportElement process
            // ClassificationUtil.CreateClassification(exporterIFC, file, spatialElement, spaceHnd, "");

            // Export Classifications for SpatialElement for GSA/COBIE.
            if (ExporterCacheManager.ExportOptionsCache.FileVersion == IFCVersion.IFCCOBIE)
            {
                CreateCOBIESpaceClassifications(exporterIFC, file, spaceHnd, document.ProjectInformation, spatialElement);
            }

            return true;
        }
        /// <summary>
        /// Collect relationship information from Ceiling to Room to be used later to determine whether a Ceiling can be contained in a Room
        /// </summary>
        /// <param name="spatialElement">The revit spatial object to process</param>
        /// <param name="results">The results of the CalculateSpatialElementGeometry call, for caching for later use.</param>
        /// <returns>True if it found a ceiling, false otherwise.</returns>
        static private bool GetCeilingSpaceBoundary(SpatialElement spatialElement, out SpatialElementGeometryResults results)
        {
            results = null;
            
            // Areas don't have a 3D rep, so no ceiling space boundaries.
            if (spatialElement is Area)
                return false;

            // Represents the criteria for boundary elements to be considered bounding Ceiling
            LogicalOrFilter categoryFilter = new LogicalOrFilter(new ElementCategoryFilter(BuiltInCategory.OST_Ceilings),
                                                        new ElementCategoryFilter(BuiltInCategory.OST_Ceilings));

            try
            {
                results = s_SpatialElementGeometryCalculator.CalculateSpatialElementGeometry(spatialElement);
            }
            catch
            {
                return false;
            }
            Solid geometry = results.GetGeometry();

            // Go through the boundary faces to identify whether it is bounded by a Ceiling. If it is Ceiling, add into the Cache
            foreach (Face face in geometry.Faces)
            {
                IList<SpatialElementBoundarySubface> boundaryFaces = results.GetBoundaryFaceInfo(face);
                foreach (SpatialElementBoundarySubface boundaryFace in boundaryFaces)
                {
                    // Get boundary element
                    LinkElementId boundaryElementId = boundaryFace.SpatialBoundaryElement;

                    // Only considering local file room bounding elements
                    ElementId localElementId = boundaryElementId.HostElementId;
                    // Evaluate if element meets criteria using PassesFilter()
                    if (localElementId != ElementId.InvalidElementId && categoryFilter.PassesFilter(spatialElement.Document, localElementId))
                    {
                        if (ExporterCacheManager.CeilingSpaceRelCache.ContainsKey(localElementId))
                        {
                            // The ceiling already exists in the Dictionary, add the Space into list
                            IList<ElementId> roomlist = ExporterCacheManager.CeilingSpaceRelCache[localElementId];
                            roomlist.Add(spatialElement.Id);
                        }
                        else
                        {
                            // The first time this Ceiling Id appears
                            IList<ElementId> roomlist = new List<ElementId>();
                            roomlist.Add(spatialElement.Id);
                            ExporterCacheManager.CeilingSpaceRelCache.Add(localElementId, roomlist);
                        }

                    }
                }
            }

            return true;
        }
        /// <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);
        }
        /// <summary>
        /// Get the height of a spatial element.
        /// </summary>
        /// <param name="spatialElement">
        /// The spatial element.
        /// </param>
        /// <param name="scale">
        /// The scale value.
        /// </param>
        /// <param name="levelInfo">
        /// The level info.
        /// </param>
        /// <returns>
        /// The height.
        /// </returns>
        static double GetHeight(SpatialElement spatialElement, double scale, IFCLevelInfo levelInfo)
        {
            Document document = spatialElement.Document;

            double roomHeight = 0.0;
            double bottomOffset = 0.0;

            ElementId bottomLevelId = spatialElement.Level.Id;

            Parameter paramTopLevelId = spatialElement.get_Parameter(BuiltInParameter.ROOM_UPPER_LEVEL);
            ElementId topLevelId = paramTopLevelId != null ? paramTopLevelId.AsElementId() : ElementId.InvalidElementId;

            Parameter paramTopOffset = spatialElement.get_Parameter(BuiltInParameter.ROOM_UPPER_OFFSET);
            double topOffset = paramTopOffset != null ? paramTopOffset.AsDouble() : 0.0;

            Parameter paramBottomOffset = spatialElement.get_Parameter(BuiltInParameter.ROOM_LOWER_OFFSET);
            bottomOffset = paramBottomOffset != null ? paramBottomOffset.AsDouble() : 0.0;

            Level bottomLevel = document.get_Element(bottomLevelId) as Level;
            Level topLevel =
               (bottomLevelId == topLevelId) ? bottomLevel : document.get_Element(topLevelId) as Level;

            if (bottomLevel != null && topLevel != null)
            {
                roomHeight = (topLevel.Elevation - bottomLevel.Elevation) + (topOffset - bottomOffset);
                roomHeight *= scale;
            }

            if (MathUtil.IsAlmostZero(roomHeight))
            {
                roomHeight = levelInfo.DistanceToNextLevel * scale;
            }

            // For area spaces, we assign a dummy height (1'), as we are not allowed to export IfcSpaces without a volumetric representation.
            if (MathUtil.IsAlmostZero(roomHeight) && spatialElement is Area)
            {
                roomHeight = 1.0;
            }

            return roomHeight;
        }
        /// <summary>
        /// Create IFC room/space/area item, not include boundaries. 
        /// </summary>
        /// <param name="exporterIFC">
        /// The ExporterIFC object.
        /// </param>
        /// <param name="spatialElement">
        /// The spatial element.
        /// </param>
        /// <param name="productWrapper">
        /// The IFCProductWrapper.
        /// </param>
        /// <param name="setter">
        /// The IFCPlacementSetter.
        /// </param>
        /// <returns>
        /// True if created successfully, false otherwise.
        /// </returns>
        static void CreateIFCSpace(ExporterIFC exporterIFC, SpatialElement spatialElement, IFCProductWrapper productWrapper, IFCPlacementSetter setter)
        {
            Autodesk.Revit.DB.Document document = spatialElement.Document;
            ElementId levelId = spatialElement.Level != null ? spatialElement.Level.Id : ElementId.InvalidElementId;
            double scale = exporterIFC.LinearScale;

            ElementId catId = spatialElement.Category != null ? spatialElement.Category.Id : ElementId.InvalidElementId;

            double dArea = 0.0;

            Parameter param = spatialElement.get_Parameter(BuiltInParameter.ROOM_AREA);
            if (param != null)
            {
                dArea = param.AsDouble();
                dArea *= (scale * scale);
            }


            SpatialElementBoundaryOptions options = ExporterIFCUtils.GetSpatialElementBoundaryOptions(exporterIFC, spatialElement);
            IList<CurveLoop> curveLoops = ExporterIFCUtils.GetRoomBoundaryAsCurveLoopArray(spatialElement, options, true);

            IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(levelId);

            string strSpaceNumber = null;
            string strSpaceName = null;
            string strSpaceDesc = null;

            bool isArea = spatialElement is Area;
            if (!isArea)
            {
                Parameter paramRoomNum = spatialElement.get_Parameter(BuiltInParameter.ROOM_NUMBER);
                if (paramRoomNum != null)
                {
                    strSpaceNumber = paramRoomNum.AsString();
                }

                Parameter paramRoomName = spatialElement.get_Parameter(BuiltInParameter.ROOM_NAME);
                if (paramRoomName != null)
                {
                    strSpaceName = paramRoomName.AsString();
                }

                Parameter paramRoomComm = spatialElement.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS);
                if (paramRoomComm != null)
                {
                    strSpaceDesc = paramRoomComm.AsString();
                }
            }
            else
            {
                Element level = document.get_Element(levelId);
                if (level != null)
                {
                    strSpaceNumber = level.Name + " GSA Design Gross Area";
                }
            }

            //assign empty string if it is null
            if (strSpaceNumber == null) strSpaceNumber = "";
            if (strSpaceName == null) strSpaceName = "";
            if (strSpaceDesc == null) strSpaceDesc = "";
            IFCLabel name = IFCLabel.Create(strSpaceNumber);
            IFCLabel longName = IFCLabel.Create(strSpaceName);
            IFCLabel desc = IFCLabel.Create(strSpaceDesc);

            IFCFile file = exporterIFC.GetFile();

            IFCAnyHandle localPlacement = setter.GetPlacement();
            ElementType elemType = document.get_Element(spatialElement.GetTypeId()) as ElementType;
            bool isObjectExternal = CategoryUtil.IsElementExternal(spatialElement);
            IFCMeasureValue elevationWithFlooring = IFCMeasureValue.Create();

            double roomHeight = 0.0;

            roomHeight = GetHeight(spatialElement, scale, levelInfo);

            double bottomOffset = 0.0;
            Parameter paramBottomOffset = spatialElement.get_Parameter(BuiltInParameter.ROOM_LOWER_OFFSET);
            bottomOffset = paramBottomOffset != null ? paramBottomOffset.AsDouble() : 0.0;

            XYZ zDir = new XYZ(0, 0, 1);
            XYZ orig = new XYZ(0, 0, levelInfo.Elevation + bottomOffset);

            Plane plane = new Plane(zDir, orig); // room calculated as level offset.

            GeometryElement geomElem = null;
            if (spatialElement is Autodesk.Revit.DB.Architecture.Room)
            {
                Autodesk.Revit.DB.Architecture.Room room = spatialElement as Autodesk.Revit.DB.Architecture.Room;
                geomElem = room.ClosedShell;
            }
            else if (spatialElement is Autodesk.Revit.DB.Mechanical.Space)
            {
                Autodesk.Revit.DB.Mechanical.Space space = spatialElement as Autodesk.Revit.DB.Mechanical.Space;
                geomElem = space.ClosedShell;
            }

            IFCAnyHandle spaceHnd = null;
            IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData();
            extraParams.SetLocalPlacement(localPlacement);
            extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ;

            using (IFCTransaction tr2 = new IFCTransaction(file))
            {
                IFCAnyHandle repHnd = null;
                if (!(exporterIFC.ExportAs2x2 || Use2DRoomBoundaryForRoomVolumeCalculation()) && geomElem != null)
                {

                    IFCSolidMeshGeometryInfo solidMeshInfo = ExporterIFCUtils.GetSolidMeshGeometry(exporterIFC, geomElem, Transform.Identity);
                    IList<Solid> solids = solidMeshInfo.GetSolids();
                    IList<Mesh> polyMeshes = solidMeshInfo.GetMeshes();

                    bool tryToExportAsExtrusion = true;
                    if (solids.Count != 1 || polyMeshes.Count != 0)
                        tryToExportAsExtrusion = false;

                    IList<GeometryObject> geomObjects = new List<GeometryObject>();

                    foreach (Solid solid in solids)
                        geomObjects.Add(solid);

                    IFCAnyHandle shapeRep = BodyExporter.ExportBody(spatialElement.Document.Application, exporterIFC, catId, geomObjects, tryToExportAsExtrusion, extraParams);
                    IList<IFCAnyHandle> shapeReps = new List<IFCAnyHandle>();
                    shapeReps.Add(shapeRep);
                    repHnd = file.CreateProductDefinitionShape(IFCLabel.Create(), IFCLabel.Create(), shapeReps);
                }
                else
                {
                    IFCAnyHandle shapeRep = file.CreateExtrudedSolidFromCurveLoop(exporterIFC, catId, curveLoops, plane, zDir, roomHeight); //pScaledOrig?
                    HashSet<IFCAnyHandle> bodyItems = new HashSet<IFCAnyHandle>();
                    bodyItems.Add(shapeRep);
                    shapeRep = RepresentationUtil.CreateSweptSolidRep(exporterIFC, catId, exporterIFC.Get3DContextHandle(), bodyItems, IFCAnyHandle.Create());
                    IList<IFCAnyHandle> shapeReps = new List<IFCAnyHandle>();
                    shapeReps.Add(shapeRep);
                    repHnd = file.CreateProductDefinitionShape(IFCLabel.Create(), IFCLabel.Create(), shapeReps);
                }

                extraParams.ScaledHeight = roomHeight;
                extraParams.ScaledArea = dArea;

                spaceHnd = file.CreateSpace(IFCLabel.CreateGUID(spatialElement),
                                                  exporterIFC.GetOwnerHistoryHandle(),
                                                  NamingUtil.GetNameOverride(spatialElement, name),
                                                  NamingUtil.GetDescriptionOverride(spatialElement, desc),
                                                  NamingUtil.GetObjectTypeOverride(spatialElement, IFCLabel.Create()),
                                                  extraParams.GetLocalPlacement(), repHnd, longName, IFCElementComposition.Element
                                                  , isObjectExternal, elevationWithFlooring);
                tr2.Commit();
            }

            productWrapper.AddSpace(spaceHnd, levelInfo, extraParams, true);

            // Save room handle for later use/relationships
            exporterIFC.RegisterSpatialElementHandle(spatialElement.Id, spaceHnd);

            if (!MathUtil.IsAlmostZero(dArea) && !(exporterIFC.FileVersion == IFCVersion.IFCCOBIE))
            {
                ExporterIFCUtils.CreatePreCOBIEGSAQuantities(exporterIFC, spaceHnd, "GSA Space Areas", (isArea ? "GSA Design Gross Area" : "GSA BIM Area"), dArea);
            }

            // Export BaseQuantities for RoomElem
            if (exporterIFC.ExportBaseQuantities && !(exporterIFC.FileVersion == IFCVersion.IFCCOBIE))
            {
                ExporterIFCUtils.CreateNonCOBIERoomQuantities(exporterIFC, spaceHnd, spatialElement, dArea, roomHeight);
            }
        }
        /// <summary>
        /// Checks if the spatial element is gross interior.
        /// </summary>
        /// <param name="exporterIFC">
        /// The ExporterIFC object.
        /// </param>
        /// <param name="spatialElement">
        /// The spatial element.
        /// </param>
        /// <returns>
        /// True if the area is gross interior.
        /// </returns>
        static bool IsAreaGrossInterior(ExporterIFC exporterIFC, SpatialElement spatialElement)
        {
            Area area = spatialElement as Area;
            if (area != null)
            {
                if (!area.IsGrossInterior)
                    return false;

                double dArea;
                if (!ParameterUtil.GetDoubleValueFromElement(area, BuiltInParameter.ROOM_AREA, out dArea))
                    return false;

                return !MathUtil.IsAlmostZero(dArea);
            }
            return false;
        }
Пример #43
0
        /// <summary>
        /// Creates IFC room/space/area item, not include boundaries. 
        /// </summary>
        /// <param name="exporterIFC">
        /// The ExporterIFC object.
        /// </param>
        /// <param name="spatialElement">
        /// The spatial element.
        /// </param>
        /// <param name="productWrapper">
        /// The IFCProductWrapper.
        /// </param>
        /// <param name="setter">
        /// The IFCPlacementSetter.
        /// </param>
        /// <returns>
        /// True if created successfully, false otherwise.
        /// </returns>
        static bool CreateIFCSpace(ExporterIFC exporterIFC, SpatialElement spatialElement, IFCProductWrapper productWrapper, IFCPlacementSetter setter)
        {
            IList<CurveLoop> curveLoops = null;
            try
            {
                SpatialElementBoundaryOptions options = ExporterIFCUtils.GetSpatialElementBoundaryOptions(exporterIFC, spatialElement);
                curveLoops = ExporterIFCUtils.GetRoomBoundaryAsCurveLoopArray(spatialElement, options, true);
            }
            catch (Autodesk.Revit.Exceptions.InvalidOperationException)
            {
                //Some spatial elements are not placed that have no boundary loops. Don't export them.
                return false;
            }

            Autodesk.Revit.DB.Document document = spatialElement.Document;
            ElementId levelId = spatialElement.Level != null ? spatialElement.Level.Id : ElementId.InvalidElementId;
            double scale = exporterIFC.LinearScale;

            ElementId catId = spatialElement.Category != null ? spatialElement.Category.Id : ElementId.InvalidElementId;

            double dArea = 0.0;

            Parameter param = spatialElement.get_Parameter(BuiltInParameter.ROOM_AREA);
            if (param != null)
            {
                dArea = param.AsDouble();
                dArea *= (scale * scale);
            }

            IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(levelId);

            string strSpaceNumber = null;
            string strSpaceName = null;
            string strSpaceDesc = null;

            bool isArea = spatialElement is Area;
            if (!isArea)
            {
                Parameter paramRoomNum = spatialElement.get_Parameter(BuiltInParameter.ROOM_NUMBER);
                if (paramRoomNum != null)
                {
                    strSpaceNumber = paramRoomNum.AsString();
                }

                Parameter paramRoomName = spatialElement.get_Parameter(BuiltInParameter.ROOM_NAME);
                if (paramRoomName != null)
                {
                    strSpaceName = paramRoomName.AsString();
                }

                Parameter paramRoomComm = spatialElement.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS);
                if (paramRoomComm != null)
                {
                    strSpaceDesc = paramRoomComm.AsString();
                }
            }
            else
            {
                Element level = document.GetElement(levelId);
                if (level != null)
                {
                    strSpaceNumber = level.Name + " GSA Design Gross Area";
                }
            }

            string name = strSpaceNumber;
            string longName = strSpaceName;
            string desc = strSpaceDesc;

            IFCFile file = exporterIFC.GetFile();

            IFCAnyHandle localPlacement = setter.GetPlacement();
            ElementType elemType = document.GetElement(spatialElement.GetTypeId()) as ElementType;
            IFCInternalOrExternal internalOrExternal = CategoryUtil.IsElementExternal(spatialElement) ? IFCInternalOrExternal.External : IFCInternalOrExternal.Internal;

            double roomHeight = 0.0;

            roomHeight = GetHeight(spatialElement, scale, levelId, levelInfo);

            double bottomOffset = 0.0;
            Parameter paramBottomOffset = spatialElement.get_Parameter(BuiltInParameter.ROOM_LOWER_OFFSET);
            bottomOffset = paramBottomOffset != null ? paramBottomOffset.AsDouble() : 0.0;

            XYZ zDir = new XYZ(0, 0, 1);
            XYZ orig = new XYZ(0, 0, levelInfo.Elevation + bottomOffset);

            Plane plane = new Plane(zDir, orig); // room calculated as level offset.

            GeometryElement geomElem = null;
            if (spatialElement is Autodesk.Revit.DB.Architecture.Room)
            {
                Autodesk.Revit.DB.Architecture.Room room = spatialElement as Autodesk.Revit.DB.Architecture.Room;
                geomElem = room.ClosedShell;
            }
            else if (spatialElement is Autodesk.Revit.DB.Mechanical.Space)
            {
                Autodesk.Revit.DB.Mechanical.Space space = spatialElement as Autodesk.Revit.DB.Mechanical.Space;
                geomElem = space.ClosedShell;
            }

            IFCAnyHandle spaceHnd = null;
            using (IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData())
            {
                extraParams.SetLocalPlacement(localPlacement);
                extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ;

                using (IFCTransaction transaction2 = new IFCTransaction(file))
                {
                    IFCAnyHandle repHnd = null;
                    if (!ExporterCacheManager.ExportOptionsCache.Use2DRoomBoundaryForRoomVolumeCreation && geomElem != null)
                    {
                        BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true);
                        bodyExporterOptions.TessellationLevel = BodyExporterOptions.BodyTessellationLevel.Coarse;
                        repHnd = RepresentationUtil.CreateBRepProductDefinitionShape(spatialElement.Document.Application, exporterIFC, spatialElement,
                            catId, geomElem, bodyExporterOptions, null, extraParams);
                        if (IFCAnyHandleUtil.IsNullOrHasNoValue(repHnd))
                            extraParams.ClearOpenings();
                    }
                    else
                    {
                        IFCAnyHandle shapeRep = ExtrusionExporter.CreateExtrudedSolidFromCurveLoop(exporterIFC, null, curveLoops, plane, zDir, roomHeight);
                        if (IFCAnyHandleUtil.IsNullOrHasNoValue(shapeRep))
                            return false;
                        IFCAnyHandle styledItemHnd = BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, document,
                            shapeRep, ElementId.InvalidElementId);

                        HashSet<IFCAnyHandle> bodyItems = new HashSet<IFCAnyHandle>();
                        bodyItems.Add(shapeRep);
                        shapeRep = RepresentationUtil.CreateSweptSolidRep(exporterIFC, spatialElement, catId, exporterIFC.Get3DContextHandle("Body"), bodyItems, null);
                        IList<IFCAnyHandle> shapeReps = new List<IFCAnyHandle>();
                        shapeReps.Add(shapeRep);
                        repHnd = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, shapeReps);
                    }

                    extraParams.ScaledHeight = roomHeight;
                    extraParams.ScaledArea = dArea;

                    spaceHnd = IFCInstanceExporter.CreateSpace(file, ExporterIFCUtils.CreateGUID(spatialElement),
                                                      exporterIFC.GetOwnerHistoryHandle(),
                                                      NamingUtil.GetNameOverride(spatialElement, name),
                                                      NamingUtil.GetDescriptionOverride(spatialElement, desc),
                                                      NamingUtil.GetObjectTypeOverride(spatialElement, null),
                                                      extraParams.GetLocalPlacement(), repHnd, longName, Toolkit.IFCElementComposition.Element
                                                      , internalOrExternal, null);
                    transaction2.Commit();
                }

                productWrapper.AddSpace(spaceHnd, levelInfo, extraParams, true);
            }

            // Save room handle for later use/relationships
            ExporterCacheManager.SpatialElementHandleCache.Register(spatialElement.Id, spaceHnd);
            exporterIFC.RegisterSpatialElementHandle(spatialElement.Id, spaceHnd);

            if (!MathUtil.IsAlmostZero(dArea) && !(ExporterCacheManager.ExportOptionsCache.FileVersion == IFCVersion.IFCCOBIE))
            {
                ExporterIFCUtils.CreatePreCOBIEGSAQuantities(exporterIFC, spaceHnd, "GSA Space Areas", (isArea ? "GSA Design Gross Area" : "GSA BIM Area"), dArea);
            }

            // Export BaseQuantities for SpatialElement
            if (ExporterCacheManager.ExportOptionsCache.ExportBaseQuantities && !(ExporterCacheManager.ExportOptionsCache.FileVersion == IFCVersion.IFCCOBIE))
            {
                ExporterIFCUtils.CreateNonCOBIERoomQuantities(exporterIFC, spaceHnd, spatialElement, dArea, roomHeight);
            }

            // Export Classifications for SpatialElement for GSA/COBIE.
            if (ExporterCacheManager.ExportOptionsCache.FileVersion == IFCVersion.IFCCOBIE)
            {
                CreateCOBIESpaceClassifications(exporterIFC, file, spaceHnd, document.ProjectInformation, spatialElement);
            }

            return true;
        }
        /// <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);
        }
        /// <summary>
        /// Check if the spatial element is gross interior.
        /// </summary>
        /// <param name="exporterIFC">
        /// The ExporterIFC object.
        /// </param>
        /// <param name="spatialElement">
        /// The spatial element.
        /// </param>
        /// <returns>
        /// True if the area is gross interior.
        /// </returns>
        static bool IsAreaGrossInterior(ExporterIFC exporterIFC, SpatialElement spatialElement)
        {
            Area area = spatialElement as Area;
            if (area != null)
            {
                double scale = exporterIFC.LinearScale;

                double dArea = 0.0;
                Parameter paramRoomArea = area.get_Parameter(BuiltInParameter.ROOM_AREA);
                if (paramRoomArea != null && paramRoomArea.StorageType == StorageType.Double)
                {
                    dArea = paramRoomArea.AsDouble();
                    dArea *= (scale * scale);
                }  // convert scale to export scale; area is scale squared.

                if (!MathUtil.IsAlmostZero(dArea) && area.IsGrossInterior)
                    return true;
            }
            return false;
        }
        /// <summary>
        /// Gets the height of a spatial element.
        /// </summary>
        /// <param name="spatialElement">
        /// The spatial element.
        /// </param>
        /// <param name="scale">
        /// The scale value.
        /// </param>
        /// <param name="levelInfo">
        /// The level info.
        /// </param>
        /// <returns>
        /// The height.
        /// </returns>
        static double GetHeight(SpatialElement spatialElement, double scale, ElementId levelId, IFCLevelInfo levelInfo)
        {
            Document document = spatialElement.Document;

            ElementId topLevelId;
            ParameterUtil.GetElementIdValueFromElement(spatialElement, BuiltInParameter.ROOM_UPPER_LEVEL, out topLevelId);

            double topOffset;
            ParameterUtil.GetDoubleValueFromElement(spatialElement, BuiltInParameter.ROOM_UPPER_OFFSET, out topOffset);

            double bottomOffset;
            ParameterUtil.GetDoubleValueFromElement(spatialElement, BuiltInParameter.ROOM_LOWER_OFFSET, out bottomOffset);

            Level bottomLevel = document.GetElement(levelId) as Level;
            Level topLevel =
               (levelId == topLevelId) ? bottomLevel : document.GetElement(topLevelId) as Level;

            double roomHeight = 0.0;
            if (bottomLevel != null && topLevel != null)
            {
                roomHeight = (topLevel.Elevation - bottomLevel.Elevation) + (topOffset - bottomOffset);
                roomHeight *= scale;
            }

            if (MathUtil.IsAlmostZero(roomHeight))
            {
                double levelHeight = ExporterCacheManager.LevelInfoCache.FindHeight(levelId);
                if (levelHeight < 0.0)
                    levelHeight = LevelUtil.calculateDistanceToNextLevel(document, levelId, levelInfo);

                roomHeight = levelHeight * scale;
            }

            // For area spaces, we assign a dummy height (1'), as we are not allowed to export IfcSpaces without a volumetric representation.
            if (MathUtil.IsAlmostZero(roomHeight) && spatialElement is Area)
            {
                roomHeight = 1.0;
            }

            return roomHeight;
        }