Exemple #1
0
        private void GetFabricSheetParams(FabricSheet sheet)
        {
            if (sheet == null)
            {
                return;
            }

            MeshLength = sheet.CutOverallLength;
            MeshWidth  = sheet.CutOverallWidth;

            if (sheet == null)
            {
                return;
            }

            Document        doc = sheet.Document;
            Element         fabricSheetTypeElem = doc?.GetElement(sheet.GetTypeId());
            FabricSheetType fabricSheetType     = fabricSheetTypeElem as FabricSheetType;

            SteelGrade = NamingUtil.GetOverrideStringValue(sheet, "SteelGrade", null);

            Element        majorFabricWireTypeElem = doc?.GetElement(fabricSheetType?.MajorDirectionWireType);
            FabricWireType majorFabricWireType     = (majorFabricWireTypeElem == null) ? null : (majorFabricWireTypeElem as FabricWireType);

            if (majorFabricWireType != null)
            {
                LongitudinalBarNominalDiameter = UnitUtil.ScaleLength(majorFabricWireType.WireDiameter);
                double localRadius = LongitudinalBarNominalDiameter / 2.0;
                LongitudinalBarCrossSectionArea = localRadius * localRadius * Math.PI;
            }

            Element        minorFabricWireTypeElem = doc?.GetElement(fabricSheetType?.MinorDirectionWireType);
            FabricWireType minorFabricWireType     = (minorFabricWireTypeElem == null) ? null : (minorFabricWireTypeElem as FabricWireType);

            if (minorFabricWireType != null)
            {
                TransverseBarNominalDiameter = UnitUtil.ScaleLength(minorFabricWireType.WireDiameter);
                double localRadius = TransverseBarNominalDiameter / 2.0;
                TransverseBarCrossSectionArea = localRadius * localRadius * Math.PI;
            }

            LongitudinalBarSpacing = UnitUtil.ScaleLength(fabricSheetType.MajorSpacing);
            TransverseBarSpacing   = UnitUtil.ScaleLength(fabricSheetType.MinorSpacing);
        }
Exemple #2
0
        /// <summary>
        /// Creates an opening from extrusion data.
        /// </summary>
        /// <param name="exporterIFC">The exporter.</param>
        /// <param name="hostObjHnd">The host handle.</param>
        /// <param name="hostPlacement">The host placement.</param>
        /// <param name="hostElement">The host element.</param>
        /// <param name="insertElement">The opening element.</param>
        /// <param name="openingGUID">The opening GUID.</param>
        /// <param name="extrusionData">The extrusion data.</param>
        /// <param name="plane">The plane.</param>
        /// <param name="isRecess">True if it is a recess.</param>
        /// <returns>The opening handle.</returns>
        static public IFCAnyHandle CreateOpening(ExporterIFC exporterIFC, IFCAnyHandle hostObjHnd, IFCAnyHandle hostPlacement, Element hostElement,
                                                 Element insertElement, string openingGUID, IFCExtrusionData extrusionData, Plane plane, bool isRecess,
                                                 PlacementSetter setter, ProductWrapper localWrapper)
        {
            IFCFile file = exporterIFC.GetFile();

            IList <CurveLoop> curveLoops = extrusionData.GetLoops();

            if (curveLoops.Count == 0)
            {
                return(null);
            }

            if (plane == null)
            {
                // assumption: first curve loop defines the plane.
                if (!curveLoops[0].HasPlane())
                {
                    return(null);
                }
                plane = curveLoops[0].GetPlane();
            }

            ElementId catId = CategoryUtil.GetSafeCategoryId(insertElement);

            IFCAnyHandle openingProdRepHnd = RepresentationUtil.CreateExtrudedProductDefShape(exporterIFC, insertElement, catId,
                                                                                              curveLoops, plane, extrusionData.ExtrusionDirection, extrusionData.ScaledExtrusionLength);

            string       openingObjectType = isRecess ? "Recess" : "Opening";
            IFCAnyHandle ownerHistory      = exporterIFC.GetOwnerHistoryHandle();
            string       openingName       = NamingUtil.GetNameOverride(insertElement, null);

            if (string.IsNullOrEmpty(openingName))
            {
                openingName = NamingUtil.GetNameOverride(hostElement, NamingUtil.CreateIFCObjectName(exporterIFC, hostElement));
            }
            IFCAnyHandle openingHnd = IFCInstanceExporter.CreateOpeningElement(file, openingGUID, ownerHistory, openingName, null,
                                                                               openingObjectType, ExporterUtil.CreateLocalPlacement(file, hostPlacement, null), openingProdRepHnd, null);
            IFCExtrusionCreationData ecData = null;

            if (ExporterCacheManager.ExportOptionsCache.ExportBaseQuantities)
            {
                double height, width;
                ecData = new IFCExtrusionCreationData();
                if (GeometryUtil.ComputeHeightWidthOfCurveLoop(curveLoops[0], plane, out height, out width))
                {
                    ecData.ScaledHeight = UnitUtil.ScaleLength(height);
                    ecData.ScaledWidth  = UnitUtil.ScaleLength(width);
                }
                else
                {
                    double area = ExporterIFCUtils.ComputeAreaOfCurveLoops(curveLoops);
                    ecData.ScaledArea = UnitUtil.ScaleArea(area);
                }
                PropertyUtil.CreateOpeningQuantities(exporterIFC, openingHnd, ecData);
            }

            if (localWrapper != null)
            {
                Element elementForProperties = null;
                if (GUIDUtil.IsGUIDFor(insertElement, openingGUID))
                {
                    elementForProperties = insertElement;
                }

                localWrapper.AddElement(elementForProperties, openingHnd, setter, ecData, true);
            }

            string voidGuid = GUIDUtil.CreateGUID();

            IFCInstanceExporter.CreateRelVoidsElement(file, voidGuid, ownerHistory, null, null, hostObjHnd, openingHnd);
            return(openingHnd);
        }
        /// <summary>
        /// Creates a creator from DoorWindowInfo.
        /// </summary>
        /// <param name="exporterIFC">The exporter.</param>
        /// <param name="doorWindowInfo">The DoorWindowInfo.</param>
        /// <param name="instanceHandle">The instance handle.</param>
        /// <param name="levelId">The level id.</param>
        /// <returns>The creator.</returns>
        public static DoorWindowDelayedOpeningCreator Create(ExporterIFC exporterIFC, DoorWindowInfo doorWindowInfo, IFCAnyHandle instanceHandle, ElementId levelId)
        {
            if (exporterIFC == null || doorWindowInfo == null)
            {
                return(null);
            }

            DoorWindowDelayedOpeningCreator doorWindowDelayedOpeningCreator = null;

            if (doorWindowInfo.HasRealWallHost)
            {
                Document       doc     = doorWindowInfo.HostObject.Document;
                Wall           wall    = doorWindowInfo.HostObject as Wall;
                FamilyInstance famInst = doorWindowInfo.InsertInstance;
                ElementId      hostId  = wall != null ? wall.Id : ElementId.InvalidElementId;
                ElementId      instId  = famInst != null ? famInst.Id : ElementId.InvalidElementId;

                doorWindowDelayedOpeningCreator                           = new DoorWindowDelayedOpeningCreator();
                doorWindowDelayedOpeningCreator.HostId                    = hostId;
                doorWindowDelayedOpeningCreator.InsertId                  = instId;
                doorWindowDelayedOpeningCreator.PosHingeSide              = doorWindowInfo.PosHingeSide;
                doorWindowDelayedOpeningCreator.DoorWindowHnd             = instanceHandle;
                doorWindowDelayedOpeningCreator.LevelId                   = levelId;
                doorWindowDelayedOpeningCreator.CreatedFromDoorWindowInfo = true;

                WallType wallType      = doc.GetElement(wall.GetTypeId()) as WallType;
                double   unScaledWidth = ((wallType != null) && (wallType.Kind != WallKind.Curtain)) ? wallType.Width : 0.0;
                if (!MathUtil.IsAlmostZero(unScaledWidth))
                {
                    IFCAnyHandle openingHnd = exporterIFC.GetDoorWindowOpeningHandle(instId);
                    if (IFCAnyHandleUtil.IsNullOrHasNoValue(openingHnd))
                    {
                        XYZ       cutDir  = null;
                        CurveLoop cutLoop = null;
                        try
                        {
                            cutLoop = ExporterIFCUtils.GetInstanceCutoutFromWall(wall.Document, wall, famInst, out cutDir);
                        }
                        catch
                        {
                            cutLoop = null;
                            // Couldn't create opening for door in wall - report as error in log when we create log file.
                        }

                        if (cutLoop != null)
                        {
                            if (doorWindowDelayedOpeningCreator.ExtrusionData == null)
                            {
                                doorWindowDelayedOpeningCreator.ExtrusionData = new List <IFCExtrusionData>();
                            }

                            IFCExtrusionData extrusionData = new IFCExtrusionData();
                            extrusionData.ExtrusionDirection    = cutDir;
                            extrusionData.ScaledExtrusionLength = UnitUtil.ScaleLength(unScaledWidth);
                            extrusionData.AddLoop(cutLoop);
                            doorWindowDelayedOpeningCreator.ScaledHostWidth = UnitUtil.ScaleLength(unScaledWidth);
                            doorWindowDelayedOpeningCreator.ExtrusionData.Add(extrusionData);
                            doorWindowDelayedOpeningCreator.HasValidGeometry = true;
                        }
                        else
                        {
                            // Couldn't create opening for door in wall - report as error in log when we create log file.
                        }
                    }
                }
            }

            return(doorWindowDelayedOpeningCreator);
        }
        /// <summary>
        /// Excutes the creator.
        /// </summary>
        /// <param name="exporterIFC">The exporter.</param>
        /// <param name="doc">The document.</param>
        public void Execute(ExporterIFC exporterIFC, Document doc)
        {
            IFCAnyHandle hostObjHnd = !IFCAnyHandleUtil.IsNullOrHasNoValue(HostHnd) ? HostHnd :
                                      DoorWindowUtil.GetHndForHostAndLevel(exporterIFC, HostId, LevelId);

            if (IFCAnyHandleUtil.IsNullOrHasNoValue(hostObjHnd))
            {
                return;
            }

            IList <DoorWindowOpeningInfo> doorWindowOpeningInfoList = new List <DoorWindowOpeningInfo>();

            Element doorElem    = doc.GetElement(InsertId);
            string  openingGUID = GUIDUtil.CreateSubElementGUID(doorElem, (int)IFCDoorSubElements.DoorOpening);

            if (ExtrusionData != null)
            {
                foreach (IFCExtrusionData extrusionData in ExtrusionData)
                {
                    if (doorWindowOpeningInfoList.Count > 0)
                    {
                        openingGUID = GUIDUtil.CreateGUID();
                    }
                    DoorWindowOpeningInfo openingInfo = DoorWindowUtil.CreateOpeningForDoorWindow(exporterIFC, doc, hostObjHnd,
                                                                                                  HostId, InsertId, openingGUID, extrusionData.GetLoops()[0], extrusionData.ExtrusionDirection,
                                                                                                  UnitUtil.UnscaleLength(extrusionData.ScaledExtrusionLength), PosHingeSide, IsRecess);
                    if (openingInfo != null && !IFCAnyHandleUtil.IsNullOrHasNoValue(openingInfo.OpeningHnd))
                    {
                        doorWindowOpeningInfoList.Add(openingInfo);
                    }
                }
            }

            if (Solids != null)
            {
                foreach (Solid solid in Solids)
                {
                    if (doorWindowOpeningInfoList.Count > 0)
                    {
                        openingGUID = GUIDUtil.CreateGUID();
                    }
                    DoorWindowOpeningInfo openingInfo = DoorWindowUtil.CreateOpeningForDoorWindow(exporterIFC, doc, hostObjHnd,
                                                                                                  HostId, InsertId, openingGUID, solid, ScaledHostWidth, IsRecess);
                    if (openingInfo != null && !IFCAnyHandleUtil.IsNullOrHasNoValue(openingInfo.OpeningHnd))
                    {
                        doorWindowOpeningInfoList.Add(openingInfo);
                    }
                }
            }

            if (IFCAnyHandleUtil.IsNullOrHasNoValue(DoorWindowHnd))
            {
                return;
            }

            bool foundOpening          = false;
            bool foundHeight           = false;
            bool foundWidth            = false;
            bool?isDoorOrWindowOpening = null;

            foreach (DoorWindowOpeningInfo openingInfo in doorWindowOpeningInfoList)
            {
                // If we've updated the door/window placement, and set its height and width, there's nothing more to do here.
                if (foundOpening && foundHeight && foundWidth)
                {
                    break;
                }

                // update original door or window to be relative to the first opening we find.
                // We only allow one IfcRelFillsElement per door or window, so only do this for the first opening.
                if (!foundOpening)
                {
                    IFCFile      file         = exporterIFC.GetFile();
                    IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle;

                    IFCAnyHandle openingHnd = openingInfo.OpeningHnd;

                    foundOpening = true;
                    string relGUID = GUIDUtil.CreateGUID();
                    IFCInstanceExporter.CreateRelFillsElement(file, relGUID, ownerHistory, null, null, openingHnd, DoorWindowHnd);

                    IFCAnyHandle openingPlacement = IFCAnyHandleUtil.GetObjectPlacement(openingHnd);
                    if (!IFCAnyHandleUtil.IsNullOrHasNoValue(openingPlacement))
                    {
                        IFCAnyHandle origObjectPlacement = IFCAnyHandleUtil.GetObjectPlacement(DoorWindowHnd);
                        Transform    relTransform        = ExporterIFCUtils.GetRelativeLocalPlacementOffsetTransform(origObjectPlacement, openingPlacement);

                        IFCAnyHandle newLocalPlacement = ExporterUtil.CreateLocalPlacement(file, openingPlacement,
                                                                                           relTransform.Origin, relTransform.BasisZ, relTransform.BasisX);

                        IFCAnyHandleUtil.SetAttribute(DoorWindowHnd, "ObjectPlacement", newLocalPlacement);
                        origObjectPlacement.Delete();
                    }
                }

                // The first entry for a particular door may not have the height or width set, so keep looking until we find an entry that does.
                if (!isDoorOrWindowOpening.HasValue)
                {
                    isDoorOrWindowOpening = IFCAnyHandleUtil.IsTypeOf(DoorWindowHnd, IFCEntityType.IfcDoor) || IFCAnyHandleUtil.IsTypeOf(DoorWindowHnd, IFCEntityType.IfcWindow);
                }

                if (!(foundHeight && foundWidth) && isDoorOrWindowOpening.Value)
                {
                    double openingHeight = openingInfo.OpeningHeight;
                    double openingWidth  = openingInfo.OpeningWidth;

                    if (openingHeight > MathUtil.Eps())
                    {
                        foundHeight = true;
                        IFCAnyHandleUtil.SetAttribute(DoorWindowHnd, "OverallHeight", UnitUtil.ScaleLength(openingHeight));
                    }

                    if (openingWidth > MathUtil.Eps())
                    {
                        foundWidth = true;
                        IFCAnyHandleUtil.SetAttribute(DoorWindowHnd, "OverallWidth", UnitUtil.ScaleLength(openingWidth));
                    }
                }
            }
        }
        /// <summary>
        /// Collect information about material layer.
        ///   For IFC4RV Architectural exchange, it will generate IfcMatrialConstituentSet along with the relevant IfcShapeAspect and the width in the quantityset
        ///   For IFC4RV Structural exchange, it will generate multiple components as IfcBuildingElementPart for each layer
        ///   For others IfcMaterialLayer will be created
        /// </summary>
        private void CollectMaterialLayerSet()
        {
            ElementId typeElemId = m_Element.GetTypeId();

            MaterialIds = new List <Tuple <ElementId, string, double> >();
            IFCAnyHandle materialLayerSet = ExporterCacheManager.MaterialSetCache.FindLayerSet(typeElemId);

            // Roofs with no components are only allowed one material.  We will arbitrarily choose the thickest material.
            PrimaryMaterialHandle = ExporterCacheManager.MaterialSetCache.FindPrimaryMaterialHnd(typeElemId);
            if (IFCAnyHandleUtil.IsNullOrHasNoValue(materialLayerSet))
            {
                List <double> widths = new List <double>();
                List <MaterialFunctionAssignment> functions = new List <MaterialFunctionAssignment>();

                HostObjAttributes hostObjAttr = m_Element.Document.GetElement(typeElemId) as HostObjAttributes;
                if (hostObjAttr == null)
                {
                    // It does not have the HostObjAttribute (where we will get the compound structure for material layer set.
                    // We will define a single material instead and create the material layer set of this single material if there is enough information (At least Material id and thickness)
                    FamilyInstance familyInstance = m_Element as FamilyInstance;
                    if (familyInstance == null)
                    {
                        return;
                    }

                    FamilySymbol            familySymbol = familyInstance.Symbol;
                    ICollection <ElementId> famMatIds    = familySymbol.GetMaterialIds(false);
                    if (famMatIds.Count == 0)
                    {
                        // For some reason Plate type may not return any Material id
                        ElementId baseMatId = CategoryUtil.GetBaseMaterialIdForElement(m_Element);
                        Material  material  = m_Element.Document.GetElement(baseMatId) as Material;
                        if (material == null)
                        {
                            return;
                        }

                        string    layerName    = NamingUtil.GetOverrideStringValue(material, "IfcMaterialLayer.Name", material.Name);
                        double    matWidth     = 0.0;
                        Parameter thicknessPar = familySymbol.get_Parameter(BuiltInParameter.CURTAIN_WALL_SYSPANEL_THICKNESS);
                        if (thicknessPar != null)
                        {
                            matWidth = thicknessPar.AsDouble();
                        }
                        widths.Add(matWidth);

                        if (baseMatId != ElementId.InvalidElementId)
                        {
                            MaterialIds.Add(new Tuple <ElementId, string, double>(baseMatId, layerName, matWidth));
                        }
                        // How to get the thickness? For CurtainWall Panel (PanelType), there is a builtin parameter CURTAINWALL_SYSPANEL_THICKNESS

                        functions.Add(MaterialFunctionAssignment.None);
                    }
                    else
                    {
                        foreach (ElementId matid in famMatIds)
                        {
                            // How to get the thickness? For CurtainWall Panel (PanelType), there is a builtin parameter CURTAINWALL_SYSPANEL_THICKNESS
                            Parameter thicknessPar = familySymbol.get_Parameter(BuiltInParameter.CURTAIN_WALL_SYSPANEL_THICKNESS);
                            double    matWidth     = 0.0;
                            if (thicknessPar == null)
                            {
                                matWidth = ParameterUtil.GetSpecialThicknessParameter(familySymbol);
                            }
                            else
                            {
                                matWidth = thicknessPar.AsDouble();
                            }

                            if (MathUtil.IsAlmostZero(matWidth))
                            {
                                continue;
                            }

                            widths.Add(matWidth);
                            ElementId baseMatId = CategoryUtil.GetBaseMaterialIdForElement(m_Element);
                            if (matid != ElementId.InvalidElementId)
                            {
                                Material material = m_Element.Document.GetElement(matid) as Material;
                                if (material != null)
                                {
                                    string layerName = NamingUtil.GetOverrideStringValue(material, "IfcMaterialLayer.Name", material.Name);
                                    MaterialIds.Add(new Tuple <ElementId, string, double>(matid, layerName, matWidth));
                                }
                            }
                            else
                            {
                                MaterialIds.Add(new Tuple <ElementId, string, double>(baseMatId, null, matWidth));
                            }

                            functions.Add(MaterialFunctionAssignment.None);
                        }
                    }
                }
                else
                {
                    ElementId         baseMatId = CategoryUtil.GetBaseMaterialIdForElement(m_Element);
                    CompoundStructure cs        = hostObjAttr.GetCompoundStructure();

                    if (cs != null)
                    {
                        double scaledOffset = 0.0, scaledWallWidth = 0.0, wallHeight = 0.0;
                        Wall   wall = m_Element as Wall;
                        if (wall != null)
                        {
                            scaledWallWidth = UnitUtil.ScaleLength(wall.Width);
                            scaledOffset    = -scaledWallWidth / 2.0;
                            BoundingBoxXYZ boundingBox = wall.get_BoundingBox(null);
                            if (boundingBox != null)
                            {
                                wallHeight = boundingBox.Max.Z - boundingBox.Min.Z;
                            }
                        }

                        //TODO: Vertically compound structures are not yet supported by export.
                        if (!cs.IsVerticallyHomogeneous() && !MathUtil.IsAlmostZero(wallHeight))
                        {
                            cs = cs.GetSimpleCompoundStructure(wallHeight, wallHeight / 2.0);
                        }

                        for (int ii = 0; ii < cs.LayerCount; ++ii)
                        {
                            double matWidth = cs.GetLayerWidth(ii);
                            //if (MathUtil.IsAlmostZero(matWidth))
                            //   continue;

                            ElementId matId = cs.GetMaterialId(ii);
                            if (matId != ElementId.InvalidElementId)
                            {
                                Material material = m_Element.Document.GetElement(matId) as Material;
                                if (material != null)
                                {
                                    string layerName = NamingUtil.GetOverrideStringValue(material, "IfcMaterialLayer.Name", material.Name);
                                    MaterialIds.Add(new Tuple <ElementId, string, double>(matId, layerName, matWidth));
                                }
                            }
                            else
                            {
                                MaterialIds.Add(new Tuple <ElementId, string, double>(baseMatId, null, matWidth));
                            }
                            widths.Add(matWidth);
                            // save layer function into ProductWrapper,
                            // it's used while exporting "Function" of Pset_CoveringCommon
                            functions.Add(cs.GetLayerFunction(ii));
                        }
                    }

                    if (MaterialIds.Count == 0)
                    {
                        double matWidth = cs != null?cs.GetWidth() : 0.0;

                        widths.Add(matWidth);
                        if (baseMatId != ElementId.InvalidElementId)
                        {
                            Material material = m_Element.Document.GetElement(baseMatId) as Material;
                            if (material != null)
                            {
                                string layerName = NamingUtil.GetOverrideStringValue(material, "IfcMaterialLayer.Name", material.Name);
                                MaterialIds.Add(new Tuple <ElementId, string, double>(baseMatId, layerName, matWidth));
                            }
                        }
                        functions.Add(MaterialFunctionAssignment.None);
                    }
                }

                if (m_ProductWrapper != null)
                {
                    m_ProductWrapper.ClearFinishMaterials();
                }

                // We can't create IfcMaterialLayers without creating an IfcMaterialLayerSet.  So we will simply collate here.
                IList <IFCAnyHandle> materialHnds = new List <IFCAnyHandle>();
                IList <int>          widthIndices = new List <int>();
                double thickestLayer = 0.0;
                for (int ii = 0; ii < MaterialIds.Count; ++ii)
                {
                    // Require positive width for IFC2x3 and before, and non-negative width for IFC4.
                    if (widths[ii] < -MathUtil.Eps())
                    {
                        continue;
                    }

                    bool almostZeroWidth = MathUtil.IsAlmostZero(widths[ii]);
                    if (!ExporterCacheManager.ExportOptionsCache.ExportAs4 && almostZeroWidth)
                    {
                        continue;
                    }

                    if (almostZeroWidth)
                    {
                        widths[ii] = 0.0;
                    }

                    IFCAnyHandle materialHnd = CategoryUtil.GetOrCreateMaterialHandle(m_ExporterIFC, MaterialIds[ii].Item1);
                    if (PrimaryMaterialHandle == null || (widths[ii] > thickestLayer))
                    {
                        PrimaryMaterialHandle = materialHnd;
                        thickestLayer         = widths[ii];
                    }

                    widthIndices.Add(ii);
                    materialHnds.Add(materialHnd);

                    if ((m_ProductWrapper != null) && (functions[ii] == MaterialFunctionAssignment.Finish1 || functions[ii] == MaterialFunctionAssignment.Finish2))
                    {
                        m_ProductWrapper.AddFinishMaterial(materialHnd);
                    }
                }

                int numLayersToCreate = widthIndices.Count;
                if (numLayersToCreate == 0)
                {
                    MaterialLayerSetHandle = materialLayerSet;
                    return;
                }

                // If it is a single material, check single material override (only IfcMaterial without IfcMaterialLayerSet with only 1 member)
                if (numLayersToCreate == 1 && ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView)
                {
                    string paramValue;
                    ParameterUtil.GetStringValueFromElementOrSymbol(m_Element, "IfcSingleMaterialOverride", out paramValue);
                    if (!string.IsNullOrEmpty(paramValue))
                    {
                        IFCAnyHandle singleMaterialOverrideHnd = IFCInstanceExporter.CreateMaterial(m_ExporterIFC.GetFile(), paramValue, null, null);
                        ExporterCacheManager.MaterialHandleCache.Register(MaterialIds[0].Item1, singleMaterialOverrideHnd);
                        MaterialLayerSetHandle = singleMaterialOverrideHnd;
                        return;
                    }
                }

                IFCFile  file     = m_ExporterIFC.GetFile();
                Document document = ExporterCacheManager.Document;

                IList <IFCAnyHandle> layers = new List <IFCAnyHandle>(numLayersToCreate);
                IList <Tuple <string, IFCAnyHandle> > layerWidthQuantities = new List <Tuple <string, IFCAnyHandle> >();
                HashSet <string> layerNameUsed = new HashSet <string>();
                double           totalWidth    = 0.0;

                for (int ii = 0; ii < numLayersToCreate; ii++)
                {
                    int    widthIndex  = widthIndices[ii];
                    double scaledWidth = UnitUtil.ScaleLength(widths[widthIndex]);

                    string layerName   = "Layer";
                    string description = null;
                    string category    = null;
                    int?   priority    = null;

                    IFCLogical?isVentilated = null;
                    int        isVentilatedValue;

                    Material material = document.GetElement(MaterialIds[ii].Item1) as Material;
                    if (material != null)
                    {
                        if (ParameterUtil.GetIntValueFromElement(material, "IfcMaterialLayer.IsVentilated", out isVentilatedValue) != null)
                        {
                            if (isVentilatedValue == 0)
                            {
                                isVentilated = IFCLogical.False;
                            }
                            else if (isVentilatedValue == 1)
                            {
                                isVentilated = IFCLogical.True;
                            }
                        }

                        if (ExporterCacheManager.ExportOptionsCache.ExportAs4)
                        {
                            layerName = MaterialIds[ii].Item2;
                            if (string.IsNullOrEmpty(layerName))
                            {
                                layerName = "Layer";
                            }

                            // Ensure layer name is unique
                            layerName = NamingUtil.GetUniqueNameWithinSet(layerName, ref layerNameUsed);

                            description = NamingUtil.GetOverrideStringValue(material, "IfcMaterialLayer.Description",
                                                                            IFCAnyHandleUtil.GetStringAttribute(materialHnds[ii], "Description"));
                            category = NamingUtil.GetOverrideStringValue(material, "IfcMaterialLayer.Category",
                                                                         IFCAnyHandleUtil.GetStringAttribute(materialHnds[ii], "Category"));
                            int priorityValue;
                            if (ParameterUtil.GetIntValueFromElement(material, "IfcMaterialLayer.Priority", out priorityValue) != null)
                            {
                                priority = priorityValue;
                            }
                        }
                    }

                    if (ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView)
                    {
                        // Skip component that has zero width (the will be no geometry associated to it
                        if (MathUtil.IsAlmostZero(scaledWidth))
                        {
                            continue;
                        }

                        IFCAnyHandle materialConstituent = IFCInstanceExporter.CreateMaterialConstituent(file, materialHnds[ii],
                                                                                                         name: layerName, description: description, category: category);
                        layers.Add(materialConstituent);

                        IFCAnyHandle layerQtyHnd = IFCInstanceExporter.CreateQuantityLength(file, "Width", description, null, scaledWidth);
                        totalWidth += scaledWidth;
                        layerWidthQuantities.Add(new Tuple <string, IFCAnyHandle>(layerName, layerQtyHnd));
                    }
                    else
                    {
                        IFCAnyHandle materialLayer = IFCInstanceExporter.CreateMaterialLayer(file, materialHnds[ii], scaledWidth, isVentilated,
                                                                                             name: layerName, description: description, category: category, priority: priority);
                        layers.Add(materialLayer);
                    }
                }

                if (layers.Count > 0)
                {
                    Element type         = document.GetElement(typeElemId);
                    string  layerSetName = NamingUtil.GetOverrideStringValue(type, "IfcMaterialLayerSet.Name", m_ExporterIFC.GetFamilyName());
                    string  layerSetDesc = NamingUtil.GetOverrideStringValue(type, "IfcMaterialLayerSet.Description", null);

                    if (ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView)
                    {
                        HashSet <IFCAnyHandle> constituents = new HashSet <IFCAnyHandle>(layers);
                        MaterialLayerSetHandle = IFCInstanceExporter.CreateMaterialConstituentSet(file, constituents, name: layerSetName, description: layerSetDesc);
                        foreach (Tuple <string, IFCAnyHandle> layerWidthQty in layerWidthQuantities)
                        {
                            LayerQuantityWidthHnd.Add(IFCInstanceExporter.CreatePhysicalComplexQuantity(file, layerWidthQty.Item1, null,
                                                                                                        new HashSet <IFCAnyHandle>()
                            {
                                layerWidthQty.Item2
                            }, "Layer", null, null));
                        }
                        // Finally create the total width as a quantity
                        LayerQuantityWidthHnd.Add(IFCInstanceExporter.CreateQuantityLength(file, "Width", null, null, totalWidth));
                    }
                    else
                    {
                        MaterialLayerSetHandle = IFCInstanceExporter.CreateMaterialLayerSet(file, layers, layerSetName, layerSetDesc);
                    }

                    ExporterCacheManager.MaterialSetCache.RegisterLayerSet(typeElemId, MaterialLayerSetHandle, this);
                }

                if (!IFCAnyHandleUtil.IsNullOrHasNoValue(PrimaryMaterialHandle))
                {
                    ExporterCacheManager.MaterialSetCache.RegisterPrimaryMaterialHnd(typeElemId, PrimaryMaterialHandle);
                }
            }
            else
            {
                MaterialLayerSetHandle = materialLayerSet;

                MaterialLayerSetInfo mlsInfo = ExporterCacheManager.MaterialSetCache.FindMaterialLayerSetInfo(typeElemId);
                if (mlsInfo != null)
                {
                    MaterialIds           = mlsInfo.MaterialIds;
                    PrimaryMaterialHandle = mlsInfo.PrimaryMaterialHandle;
                    LayerQuantityWidthHnd = mlsInfo.LayerQuantityWidthHnd;
                }
            }

            return;
        }
        private void GenerateIFCObjectsIfNeeded()
        {
            if (m_needToGenerateIFCObjects)
            {
                m_needToGenerateIFCObjects = false;
            }
            else
            {
                return;
            }

            IFCAnyHandle materialLayerSet = null;

            if (m_ProductWrapper != null && !m_ProductWrapper.ToNative().IsValidObject)
            {
                m_ProductWrapper = null;
            }

            m_ProductWrapper?.ClearFinishMaterials();

            // We can't create IfcMaterialLayers without creating an IfcMaterialLayerSet.  So we will simply collate here.
            IList <IFCAnyHandle> materialHnds = new List <IFCAnyHandle>();
            IList <int>          widthIndices = new List <int>();
            double thickestLayer = 0.0;

            for (int ii = 0; ii < MaterialIds.Count; ++ii)
            {
                // Require positive width for IFC2x3 and before, and non-negative width for IFC4.
                if (MaterialIds[ii].m_matWidth < -MathUtil.Eps())
                {
                    continue;
                }

                bool almostZeroWidth = MathUtil.IsAlmostZero(MaterialIds[ii].m_matWidth);
                if (!ExporterCacheManager.ExportOptionsCache.ExportAs4 && almostZeroWidth)
                {
                    continue;
                }

                if (almostZeroWidth)
                {
                    MaterialIds[ii].m_matWidth = 0.0;
                }

                IFCAnyHandle materialHnd = CategoryUtil.GetOrCreateMaterialHandle(m_ExporterIFC, MaterialIds[ii].m_baseMatId);
                if (m_PrimaryMaterialHandle == null || (MaterialIds[ii].m_matWidth > thickestLayer))
                {
                    m_PrimaryMaterialHandle = materialHnd;
                    thickestLayer           = MaterialIds[ii].m_matWidth;
                }

                widthIndices.Add(ii);
                materialHnds.Add(materialHnd);

                if ((m_ProductWrapper != null) && (MaterialIds[ii].m_function == MaterialFunctionAssignment.Finish1 || MaterialIds[ii].m_function == MaterialFunctionAssignment.Finish2))
                {
                    m_ProductWrapper.AddFinishMaterial(materialHnd);
                }
            }

            int numLayersToCreate = widthIndices.Count;

            if (numLayersToCreate == 0)
            {
                m_MaterialLayerSetHandle = materialLayerSet;
                return;
            }

            // If it is a single material, check single material override (only IfcMaterial without IfcMaterialLayerSet with only 1 member)
            if (numLayersToCreate == 1 && ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView)
            {
                m_MaterialLayerSetHandle = ExporterUtil.GetSingleMaterial(m_ExporterIFC, m_Element,
                                                                          MaterialIds[0].m_baseMatId) ?? materialHnds[0];
                return;
            }

            IFCFile  file     = m_ExporterIFC.GetFile();
            Document document = ExporterCacheManager.Document;

            IList <IFCAnyHandle> layers = new List <IFCAnyHandle>(numLayersToCreate);
            IList <Tuple <string, IFCAnyHandle> > layerWidthQuantities = new List <Tuple <string, IFCAnyHandle> >();
            HashSet <string> layerNameUsed = new HashSet <string>();
            double           totalWidth    = 0.0;

            for (int ii = 0; ii < numLayersToCreate; ii++)
            {
                int    widthIndex  = widthIndices[ii];
                double scaledWidth = UnitUtil.ScaleLength(MaterialIds[widthIndex].m_matWidth);

                string layerName   = "Layer";
                string description = null;
                string category    = null;
                int?   priority    = null;

                IFCLogical?isVentilated = null;
                int        isVentilatedValue;

                Material material = document.GetElement(MaterialIds[ii].m_baseMatId) as Material;
                if (material != null)
                {
                    if (ParameterUtil.GetIntValueFromElement(material, "IfcMaterialLayer.IsVentilated", out isVentilatedValue) != null)
                    {
                        if (isVentilatedValue == 0)
                        {
                            isVentilated = IFCLogical.False;
                        }
                        else if (isVentilatedValue == 1)
                        {
                            isVentilated = IFCLogical.True;
                        }
                    }

                    if (ExporterCacheManager.ExportOptionsCache.ExportAs4)
                    {
                        layerName = MaterialIds[ii].m_layerName;
                        if (string.IsNullOrEmpty(layerName))
                        {
                            layerName = "Layer";
                        }

                        // Ensure layer name is unique
                        layerName = NamingUtil.GetUniqueNameWithinSet(layerName, ref layerNameUsed);

                        description = NamingUtil.GetOverrideStringValue(material, "IfcMaterialLayer.Description",
                                                                        IFCAnyHandleUtil.GetStringAttribute(materialHnds[ii], "Description"));
                        category = NamingUtil.GetOverrideStringValue(material, "IfcMaterialLayer.Category",
                                                                     IFCAnyHandleUtil.GetStringAttribute(materialHnds[ii], "Category"));
                        int priorityValue;
                        if (ParameterUtil.GetIntValueFromElement(material, "IfcMaterialLayer.Priority", out priorityValue) != null)
                        {
                            priority = priorityValue;
                        }
                    }
                }

                if (ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView)
                {
                    // Skip component that has zero width (the will be no geometry associated to it
                    if (MathUtil.IsAlmostZero(scaledWidth))
                    {
                        continue;
                    }

                    IFCAnyHandle materialConstituent = IFCInstanceExporter.CreateMaterialConstituent(file, materialHnds[ii],
                                                                                                     name: layerName, description: description, category: category);
                    layers.Add(materialConstituent);

                    IFCAnyHandle layerQtyHnd = IFCInstanceExporter.CreateQuantityLength(file, "Width", description, null, scaledWidth);
                    totalWidth += scaledWidth;
                    layerWidthQuantities.Add(new Tuple <string, IFCAnyHandle>(layerName, layerQtyHnd));
                }
                else
                {
                    IFCAnyHandle materialLayer = IFCInstanceExporter.CreateMaterialLayer(file, materialHnds[ii], scaledWidth, isVentilated,
                                                                                         name: layerName, description: description, category: category, priority: priority);
                    layers.Add(materialLayer);
                }
            }

            ElementId typeElemId = m_Element.GetTypeId();

            if (layers.Count > 0)
            {
                Element type         = document.GetElement(typeElemId);
                string  layerSetName = NamingUtil.GetOverrideStringValue(type, "IfcMaterialLayerSet.Name", m_ExporterIFC.GetFamilyName());
                string  layerSetDesc = NamingUtil.GetOverrideStringValue(type, "IfcMaterialLayerSet.Description", null);

                if (ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView)
                {
                    HashSet <IFCAnyHandle> constituents = new HashSet <IFCAnyHandle>(layers);
                    m_MaterialLayerSetHandle = IFCInstanceExporter.CreateMaterialConstituentSet(file, constituents, name: layerSetName, description: layerSetDesc);
                    foreach (Tuple <string, IFCAnyHandle> layerWidthQty in layerWidthQuantities)
                    {
                        m_LayerQuantityWidthHnd.Add(IFCInstanceExporter.CreatePhysicalComplexQuantity(file, layerWidthQty.Item1, null,
                                                                                                      new HashSet <IFCAnyHandle>()
                        {
                            layerWidthQty.Item2
                        }, "Layer", null, null));
                    }
                    // Finally create the total width as a quantity
                    m_LayerQuantityWidthHnd.Add(IFCInstanceExporter.CreateQuantityLength(file, "Width", null, null, totalWidth));
                }
                else
                {
                    m_MaterialLayerSetHandle = IFCInstanceExporter.CreateMaterialLayerSet(file, layers, layerSetName, layerSetDesc);
                }

                ExporterCacheManager.MaterialSetCache.RegisterLayerSet(typeElemId, m_MaterialLayerSetHandle, this);
            }

            if (!IFCAnyHandleUtil.IsNullOrHasNoValue(m_PrimaryMaterialHandle))
            {
                ExporterCacheManager.MaterialSetCache.RegisterPrimaryMaterialHnd(typeElemId, m_PrimaryMaterialHandle);
            }
        }
        /// <summary>
        /// Collect information about material layer.
        ///   For IFC4RV Architectural exchange, it will generate IfcMatrialConstituentSet along with the relevant IfcShapeAspect and the width in the quantityset
        ///   For IFC4RV Structural exchange, it will generate multiple components as IfcBuildingElementPart for each layer
        ///   For others IfcMaterialLayer will be created
        /// </summary>
        private void CollectMaterialLayerSet()
        {
            ElementId    typeElemId       = m_Element.GetTypeId();
            IFCAnyHandle materialLayerSet = ExporterCacheManager.MaterialSetCache.FindLayerSet(typeElemId);

            // Roofs with no components are only allowed one material.  We will arbitrarily choose the thickest material.
            m_PrimaryMaterialHandle = ExporterCacheManager.MaterialSetCache.FindPrimaryMaterialHnd(typeElemId);

            bool materialHandleIsNotValid = IFCAnyHandleUtil.IsNullOrHasNoValue(materialLayerSet);

            if (IFCAnyHandleUtil.IsNullOrHasNoValue(materialLayerSet) || materialHandleIsNotValid)
            {
                if (materialHandleIsNotValid)
                {
                    UnregisterIFCHandles();
                }
                m_needToGenerateIFCObjects = true;

                List <double> widths = new List <double>();
                List <MaterialFunctionAssignment> functions = new List <MaterialFunctionAssignment>();

                HostObjAttributes hostObjAttr = m_Element.Document.GetElement(typeElemId) as HostObjAttributes;
                if (hostObjAttr == null)
                {
                    // It does not have the HostObjAttribute (where we will get the compound structure for material layer set.
                    // We will define a single material instead and create the material layer set of this single material if there is enough information (At least Material id and thickness)
                    FamilyInstance familyInstance = m_Element as FamilyInstance;
                    if (familyInstance == null)
                    {
                        return;
                    }

                    FamilySymbol            familySymbol = familyInstance.Symbol;
                    ICollection <ElementId> famMatIds    = familySymbol.GetMaterialIds(false);
                    if (famMatIds.Count == 0)
                    {
                        // For some reason Plate type may not return any Material id
                        ElementId baseMatId = CategoryUtil.GetBaseMaterialIdForElement(m_Element);
                        Material  material  = m_Element.Document.GetElement(baseMatId) as Material;
                        if (material == null)
                        {
                            return;
                        }

                        string    layerName    = NamingUtil.GetMaterialLayerName(material);
                        double    matWidth     = 0.0;
                        Parameter thicknessPar = familySymbol.get_Parameter(BuiltInParameter.CURTAIN_WALL_SYSPANEL_THICKNESS);
                        if (thicknessPar != null)
                        {
                            matWidth = thicknessPar.AsDouble();
                        }
                        widths.Add(matWidth);

                        if (baseMatId != ElementId.InvalidElementId)
                        {
                            MaterialIds.Add(new MaterialInfo(baseMatId, layerName, matWidth, MaterialFunctionAssignment.None));
                        }
                        // How to get the thickness? For CurtainWall Panel (PanelType), there is a builtin parameter CURTAINWALL_SYSPANEL_THICKNESS

                        functions.Add(MaterialFunctionAssignment.None);
                    }
                    else
                    {
                        foreach (ElementId matid in famMatIds)
                        {
                            // How to get the thickness? For CurtainWall Panel (PanelType), there is a builtin parameter CURTAINWALL_SYSPANEL_THICKNESS
                            double matWidth = familySymbol.get_Parameter(BuiltInParameter.CURTAIN_WALL_SYSPANEL_THICKNESS)?.AsDouble() ??
                                              ParameterUtil.GetSpecialThicknessParameter(familySymbol);

                            if (MathUtil.IsAlmostZero(matWidth))
                            {
                                continue;
                            }

                            widths.Add(matWidth);
                            ElementId baseMatId = CategoryUtil.GetBaseMaterialIdForElement(m_Element);
                            if (matid != ElementId.InvalidElementId)
                            {
                                Material material = m_Element.Document.GetElement(matid) as Material;
                                if (material != null)
                                {
                                    string layerName = NamingUtil.GetMaterialLayerName(material);
                                    MaterialIds.Add(new MaterialInfo(matid, layerName, matWidth, MaterialFunctionAssignment.None));
                                }
                            }
                            else
                            {
                                MaterialIds.Add(new MaterialInfo(baseMatId, null, matWidth, MaterialFunctionAssignment.None));
                            }

                            functions.Add(MaterialFunctionAssignment.None);
                        }
                    }
                }
                else
                {
                    ElementId         baseMatId = CategoryUtil.GetBaseMaterialIdForElement(m_Element);
                    CompoundStructure cs        = hostObjAttr.GetCompoundStructure();

                    if (cs != null)
                    {
                        double scaledOffset = 0.0, scaledWallWidth = 0.0, wallHeight = 0.0;
                        Wall   wall = m_Element as Wall;
                        if (wall != null)
                        {
                            scaledWallWidth = UnitUtil.ScaleLength(wall.Width);
                            scaledOffset    = -scaledWallWidth / 2.0;
                            BoundingBoxXYZ boundingBox = wall.get_BoundingBox(null);
                            if (boundingBox != null)
                            {
                                wallHeight = boundingBox.Max.Z - boundingBox.Min.Z;
                            }
                        }

                        //TODO: Vertically compound structures are not yet supported by export.
                        if (!cs.IsVerticallyHomogeneous() && !MathUtil.IsAlmostZero(wallHeight))
                        {
                            cs = cs.GetSimpleCompoundStructure(wallHeight, wallHeight / 2.0);
                        }

                        for (int ii = 0; ii < cs.LayerCount; ++ii)
                        {
                            double matWidth = cs.GetLayerWidth(ii);

                            ElementId matId = cs.GetMaterialId(ii);
                            widths.Add(matWidth);
                            // save layer function into ProductWrapper,
                            // it's used while exporting "Function" of Pset_CoveringCommon
                            functions.Add(cs.GetLayerFunction(ii));

                            if (matId != ElementId.InvalidElementId)
                            {
                                Material material = m_Element.Document.GetElement(matId) as Material;
                                if (material != null)
                                {
                                    string layerName = NamingUtil.GetMaterialLayerName(material);
                                    MaterialIds.Add(new MaterialInfo(matId, layerName, matWidth, functions.Last()));
                                }
                            }
                            else
                            {
                                MaterialIds.Add(new MaterialInfo(baseMatId, null, matWidth, functions.Last()));
                            }
                        }
                    }

                    if (MaterialIds.Count == 0)
                    {
                        double matWidth = cs?.GetWidth() ?? 0.0;
                        widths.Add(matWidth);
                        if (baseMatId != ElementId.InvalidElementId)
                        {
                            Material material = m_Element.Document.GetElement(baseMatId) as Material;
                            if (material != null)
                            {
                                string layerName = NamingUtil.GetMaterialLayerName(material);
                                MaterialIds.Add(new MaterialInfo(baseMatId, layerName, matWidth, MaterialFunctionAssignment.None));
                            }
                        }
                        functions.Add(MaterialFunctionAssignment.None);
                    }
                }
            }
            else
            {
                m_needToGenerateIFCObjects = false;

                m_MaterialLayerSetHandle = materialLayerSet;

                MaterialLayerSetInfo mlsInfo = ExporterCacheManager.MaterialSetCache.FindMaterialLayerSetInfo(typeElemId);
                if (mlsInfo != null)
                {
                    MaterialIds             = mlsInfo.MaterialIds;
                    m_PrimaryMaterialHandle = mlsInfo.PrimaryMaterialHandle;
                    m_LayerQuantityWidthHnd = mlsInfo.LayerQuantityWidthHnd;
                }
            }

            return;
        }
        /// <summary>
        /// Excutes the creator.
        /// </summary>
        /// <param name="exporterIFC">The exporter.</param>
        /// <param name="doc">The document.</param>
        public void Execute(ExporterIFC exporterIFC, Document doc)
        {
            IFCAnyHandle hostObjHnd = !IFCAnyHandleUtil.IsNullOrHasNoValue(HostHnd) ? HostHnd :
                                      DoorWindowUtil.GetHndForHostAndLevel(exporterIFC, HostId, LevelId);

            if (IFCAnyHandleUtil.IsNullOrHasNoValue(hostObjHnd))
            {
                return;
            }

            IList <DoorWindowOpeningInfo> doorWindowOpeningInfoList = new List <DoorWindowOpeningInfo>();

            Element doorElem    = doc.GetElement(InsertId);
            string  openingGUID = GUIDUtil.CreateSubElementGUID(doorElem, (int)IFCDoorSubElements.DoorOpening);

            if (ExtrusionData != null)
            {
                foreach (IFCExtrusionData extrusionData in ExtrusionData)
                {
                    if (doorWindowOpeningInfoList.Count > 0)
                    {
                        openingGUID = GUIDUtil.CreateGUID();
                    }
                    DoorWindowOpeningInfo openingInfo = DoorWindowUtil.CreateOpeningForDoorWindow(exporterIFC, doc, hostObjHnd,
                                                                                                  HostId, InsertId, openingGUID, extrusionData.GetLoops()[0], extrusionData.ExtrusionDirection,
                                                                                                  UnitUtil.UnscaleLength(extrusionData.ScaledExtrusionLength), PosHingeSide, IsRecess);
                    if (openingInfo != null && !IFCAnyHandleUtil.IsNullOrHasNoValue(openingInfo.OpeningHnd))
                    {
                        doorWindowOpeningInfoList.Add(openingInfo);
                    }
                }
            }

            if (Solids != null)
            {
                foreach (Solid solid in Solids)
                {
                    if (doorWindowOpeningInfoList.Count > 0)
                    {
                        openingGUID = GUIDUtil.CreateGUID();
                    }
                    DoorWindowOpeningInfo openingInfo = DoorWindowUtil.CreateOpeningForDoorWindow(exporterIFC, doc, hostObjHnd,
                                                                                                  HostId, InsertId, openingGUID, solid, ScaledHostWidth, IsRecess);
                    if (openingInfo != null && !IFCAnyHandleUtil.IsNullOrHasNoValue(openingInfo.OpeningHnd))
                    {
                        doorWindowOpeningInfoList.Add(openingInfo);
                    }
                }
            }

            if (IFCAnyHandleUtil.IsNullOrHasNoValue(DoorWindowHnd))
            {
                return;
            }

            foreach (DoorWindowOpeningInfo openingInfo in doorWindowOpeningInfoList)
            {
                IFCFile      file         = exporterIFC.GetFile();
                IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle();

                IFCAnyHandle openingHnd    = openingInfo.OpeningHnd;
                double       openingHeight = openingInfo.OpeningHeight;
                double       openingWidth  = openingInfo.OpeningWidth;

                // update original door.
                string relGUID = GUIDUtil.CreateGUID();
                IFCInstanceExporter.CreateRelFillsElement(file, relGUID, ownerHistory, null, null, openingHnd, DoorWindowHnd);

                IFCAnyHandle openingPlacement = IFCAnyHandleUtil.GetObjectPlacement(openingHnd);
                if (!IFCAnyHandleUtil.IsNullOrHasNoValue(openingPlacement))
                {
                    IFCAnyHandle origObjectPlacement = IFCAnyHandleUtil.GetObjectPlacement(DoorWindowHnd);
                    Transform    relTransform        = ExporterIFCUtils.GetRelativeLocalPlacementOffsetTransform(origObjectPlacement, openingPlacement);

                    IFCAnyHandle newLocalPlacement = ExporterUtil.CreateLocalPlacement(file, openingPlacement,
                                                                                       relTransform.Origin, relTransform.BasisZ, relTransform.BasisX);

                    IFCAnyHandleUtil.SetAttribute(DoorWindowHnd, "ObjectPlacement", newLocalPlacement);
                    origObjectPlacement.Delete();
                }

                if (IFCAnyHandleUtil.IsTypeOf(DoorWindowHnd, IFCEntityType.IfcDoor) ||
                    IFCAnyHandleUtil.IsTypeOf(DoorWindowHnd, IFCEntityType.IfcWindow))
                {
                    if (openingHeight > MathUtil.Eps())
                    {
                        IFCAnyHandleUtil.SetAttribute(DoorWindowHnd, "OverallHeight", UnitUtil.ScaleLength(openingHeight));
                    }
                    if (openingWidth > MathUtil.Eps())
                    {
                        IFCAnyHandleUtil.SetAttribute(DoorWindowHnd, "OverallWidth", UnitUtil.ScaleLength(openingWidth));
                    }
                }
            }
        }