/// <summary>
        /// Exports an element as an IFC assembly.
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="element">The element.</param>
        /// <param name="productWrapper">The ProductWrapper.</param>
        /// <returns>True if exported successfully, false otherwise.</returns>
        public static bool ExportAssemblyInstanceElement(ExporterIFC exporterIFC, AssemblyInstance element,
                                                         ProductWrapper productWrapper)
        {
            if (element == null)
            {
                return(false);
            }

            IFCFile file = exporterIFC.GetFile();

            using (IFCTransaction tr = new IFCTransaction(file))
            {
                IFCAnyHandle assemblyInstanceHnd = null;

                string          guid            = GUIDUtil.CreateGUID(element);
                IFCAnyHandle    ownerHistory    = exporterIFC.GetOwnerHistoryHandle();
                string          name            = NamingUtil.GetNameOverride(element, NamingUtil.GetIFCName(element));
                string          description     = NamingUtil.GetDescriptionOverride(element, null);
                string          objectType      = NamingUtil.GetObjectTypeOverride(element, exporterIFC.GetFamilyName());
                IFCAnyHandle    localPlacement  = null;
                PlacementSetter placementSetter = null;
                IFCLevelInfo    levelInfo       = null;

                string        ifcEnumType;
                IFCExportType exportAs = ExporterUtil.GetExportType(exporterIFC, element, out ifcEnumType);
                if (exportAs == IFCExportType.IfcSystem)
                {
                    assemblyInstanceHnd = IFCInstanceExporter.CreateSystem(file, guid,
                                                                           ownerHistory, name, description, objectType);

                    // Create classification reference when System has classification filed name assigned to it
                    ClassificationUtil.CreateClassification(exporterIFC, file, element, assemblyInstanceHnd);

                    HashSet <IFCAnyHandle> relatedBuildings = new HashSet <IFCAnyHandle>();
                    relatedBuildings.Add(ExporterCacheManager.BuildingHandle);

                    IFCAnyHandle relServicesBuildings = IFCInstanceExporter.CreateRelServicesBuildings(file, GUIDUtil.CreateGUID(),
                                                                                                       exporterIFC.GetOwnerHistoryHandle(), null, null, assemblyInstanceHnd, relatedBuildings);
                }
                else
                {
                    using (placementSetter = PlacementSetter.Create(exporterIFC, element))
                    {
                        string       elementTag     = NamingUtil.GetTagOverride(element, NamingUtil.CreateIFCElementId(element));
                        IFCAnyHandle representation = null;

                        // We have limited support for exporting assemblies as other container types.
                        localPlacement = placementSetter.LocalPlacement;
                        levelInfo      = placementSetter.LevelInfo;
                        ifcEnumType    = IFCValidateEntry.GetValidIFCType(element, ifcEnumType);

                        switch (exportAs)
                        {
                        case IFCExportType.IfcCurtainWall:
                            assemblyInstanceHnd = IFCInstanceExporter.CreateCurtainWall(file, guid,
                                                                                        ownerHistory, name, description, objectType, localPlacement, representation, elementTag);
                            break;

                        case IFCExportType.IfcRamp:
                            string rampPredefinedType = RampExporter.GetIFCRampType(ifcEnumType);
                            assemblyInstanceHnd = IFCInstanceExporter.CreateRamp(file, guid,
                                                                                 ownerHistory, name, description, objectType, localPlacement, representation, elementTag,
                                                                                 rampPredefinedType);
                            break;

                        case IFCExportType.IfcRoof:
                            assemblyInstanceHnd = IFCInstanceExporter.CreateRoof(file, guid,
                                                                                 ownerHistory, name, description, objectType, localPlacement, representation, elementTag,
                                                                                 ifcEnumType);
                            break;

                        case IFCExportType.IfcStair:
                            string stairPredefinedType = StairsExporter.GetIFCStairType(ifcEnumType);
                            assemblyInstanceHnd = IFCInstanceExporter.CreateStair(file, guid,
                                                                                  ownerHistory, name, description, objectType, localPlacement, representation, elementTag,
                                                                                  stairPredefinedType);
                            break;

                        case IFCExportType.IfcWall:
                            assemblyInstanceHnd = IFCInstanceExporter.CreateWall(file, guid,
                                                                                 ownerHistory, name, description, objectType, localPlacement, representation, elementTag,
                                                                                 ifcEnumType);
                            break;

                        default:
                            IFCElementAssemblyType assemblyPredefinedType = GetPredefinedTypeFromObjectType(objectType);
                            assemblyInstanceHnd = IFCInstanceExporter.CreateElementAssembly(file, guid,
                                                                                            ownerHistory, name, description, objectType, localPlacement, representation, elementTag,
                                                                                            IFCAssemblyPlace.NotDefined, assemblyPredefinedType);
                            break;
                        }
                    }
                }

                if (assemblyInstanceHnd == null)
                {
                    return(false);
                }

                bool relateToLevel = (levelInfo != null);
                productWrapper.AddElement(element, assemblyInstanceHnd, levelInfo, null, relateToLevel);

                ExporterCacheManager.AssemblyInstanceCache.RegisterAssemblyInstance(element.Id, assemblyInstanceHnd);

                tr.Commit();
                return(true);
            }
        }
        /// <summary>
        /// Exports an element as an IFC assembly.
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="element">The element.</param>
        /// <param name="productWrapper">The ProductWrapper.</param>
        /// <returns>True if exported successfully, false otherwise.</returns>
        public static bool ExportAssemblyInstanceElement(ExporterIFC exporterIFC, AssemblyInstance element,
                                                         ProductWrapper productWrapper)
        {
            if (element == null)
            {
                return(false);
            }

            IFCFile file = exporterIFC.GetFile();

            using (IFCTransaction tr = new IFCTransaction(file))
            {
                IFCAnyHandle assemblyInstanceHnd = null;

                string          guid            = GUIDUtil.CreateGUID(element);
                IFCAnyHandle    ownerHistory    = ExporterCacheManager.OwnerHistoryHandle;
                IFCAnyHandle    localPlacement  = null;
                PlacementSetter placementSetter = null;
                IFCLevelInfo    levelInfo       = null;
                bool            relateToLevel   = true;

                string            ifcEnumType;
                IFCExportInfoPair exportAs = ExporterUtil.GetExportType(exporterIFC, element, out ifcEnumType);
                if (exportAs.ExportInstance == IFCEntityType.IfcSystem)
                {
                    string name        = NamingUtil.GetNameOverride(element, NamingUtil.GetIFCName(element));
                    string description = NamingUtil.GetDescriptionOverride(element, null);
                    string objectType  = NamingUtil.GetObjectTypeOverride(element, NamingUtil.GetFamilyAndTypeName(element));
                    assemblyInstanceHnd = IFCInstanceExporter.CreateSystem(file, guid, ownerHistory, name, description, objectType);

                    // Create classification reference when System has classification filed name assigned to it
                    ClassificationUtil.CreateClassification(exporterIFC, file, element, assemblyInstanceHnd);

                    HashSet <IFCAnyHandle> relatedBuildings = new HashSet <IFCAnyHandle>();
                    relatedBuildings.Add(ExporterCacheManager.BuildingHandle);

                    IFCAnyHandle relServicesBuildings = IFCInstanceExporter.CreateRelServicesBuildings(file, GUIDUtil.CreateGUID(),
                                                                                                       ExporterCacheManager.OwnerHistoryHandle, null, null, assemblyInstanceHnd, relatedBuildings);

                    relateToLevel = false; // Already related to the building via IfcRelServicesBuildings.
                }
                else
                {
                    // Check for containment override
                    IFCAnyHandle overrideContainerHnd = null;
                    ElementId    overrideContainerId  = ParameterUtil.OverrideContainmentParameter(exporterIFC, element, out overrideContainerHnd);

                    using (placementSetter = PlacementSetter.Create(exporterIFC, element, null, null, overrideContainerId, overrideContainerHnd))
                    {
                        IFCAnyHandle representation = null;

                        // We have limited support for exporting assemblies as other container types.
                        localPlacement = placementSetter.LocalPlacement;
                        levelInfo      = placementSetter.LevelInfo;

                        switch (exportAs.ExportInstance)
                        {
                        case IFCEntityType.IfcCurtainWall:
                            //case IFCExportType.IfcCurtainWallType:
                            //string cwPredefinedType = IFCValidateEntry.GetValidIFCPredefinedType(element, ifcEnumType, "IfcCurtainWallType");
                            assemblyInstanceHnd = IFCInstanceExporter.CreateCurtainWall(exporterIFC, element, guid,
                                                                                        ownerHistory, localPlacement, representation, ifcEnumType);
                            break;

                        case IFCEntityType.IfcRamp:
                            string rampPredefinedType = RampExporter.GetIFCRampType(ifcEnumType);
                            //rampPredefinedType = IFCValidateEntry.GetValidIFCPredefinedType(element, rampPredefinedType, "IfcRampType");
                            assemblyInstanceHnd = IFCInstanceExporter.CreateRamp(exporterIFC, element, guid,
                                                                                 ownerHistory, localPlacement, representation, rampPredefinedType);
                            break;

                        case IFCEntityType.IfcRoof:
                            //string roofPredefinedType = IFCValidateEntry.GetValidIFCPredefinedType(element, ifcEnumType, "IfcRoofType");
                            assemblyInstanceHnd = IFCInstanceExporter.CreateRoof(exporterIFC, element, guid,
                                                                                 ownerHistory, localPlacement, representation, ifcEnumType);
                            break;

                        case IFCEntityType.IfcStair:
                            string stairPredefinedType = StairsExporter.GetIFCStairType(ifcEnumType);
                            //stairPredefinedType = IFCValidateEntry.GetValidIFCPredefinedType(element, stairPredefinedType, "IfcStairType");
                            assemblyInstanceHnd = IFCInstanceExporter.CreateStair(exporterIFC, element, guid,
                                                                                  ownerHistory, localPlacement, representation, stairPredefinedType);
                            break;

                        case IFCEntityType.IfcWall:
                            //string wallPredefinedType = IFCValidateEntry.GetValidIFCPredefinedType(element, ifcEnumType, "IfcWallType");
                            assemblyInstanceHnd = IFCInstanceExporter.CreateWall(exporterIFC, element, guid,
                                                                                 ownerHistory, localPlacement, representation, ifcEnumType);
                            break;

                        default:
                            string objectType = NamingUtil.GetObjectTypeOverride(element, NamingUtil.GetFamilyAndTypeName(element));
                            IFCElementAssemblyType assemblyPredefinedType = GetPredefinedTypeFromObjectType(objectType);
                            assemblyInstanceHnd = IFCInstanceExporter.CreateElementAssembly(exporterIFC, element, guid,
                                                                                            ownerHistory, localPlacement, representation, IFCAssemblyPlace.NotDefined, assemblyPredefinedType);
                            break;
                        }
                    }
                }

                if (assemblyInstanceHnd == null)
                {
                    return(false);
                }

                // relateToLevel depends on how the AssemblyInstance is being mapped to IFC, above.
                productWrapper.AddElement(element, assemblyInstanceHnd, levelInfo, null, relateToLevel, exportAs);

                ExporterCacheManager.AssemblyInstanceCache.RegisterAssemblyInstance(element.Id, assemblyInstanceHnd);

                tr.Commit();
                return(true);
            }
        }
        private static bool ExportGenericElementAsMappedItem(ExporterIFC exporterIFC,
                                                             Element element, GeometryElement geomElem, IFCExportInfoPair exportType,
                                                             ProductWrapper wrapper)
        {
            GeometryInstance geometryInstance = GetTheGeometryInstance(geomElem);

            if (geometryInstance == null)
            {
                return(false);
            }

            GeometryElement exportGeometry = geometryInstance.GetSymbolGeometry();

            if (exportGeometry == null)
            {
                return(false);
            }

            ElementId   symbolId    = geometryInstance.GetSymbolGeometryId()?.SymbolId ?? ElementId.InvalidElementId;
            ElementType elementType = element.Document.GetElement(symbolId) as ElementType;

            if (elementType == null)
            {
                return(false);
            }

            Transform originalTrf = geometryInstance.Transform;

            // Can't handle mirrored transforms yet.
            if (originalTrf.HasReflection)
            {
                return(false);
            }

            ElementId categoryId = CategoryUtil.GetSafeCategoryId(element);

            IFCFile file = exporterIFC.GetFile();

            IList <Transform>        repMapTrfList = new List <Transform>();
            BodyData                 bodyData      = null;
            FamilyTypeInfo           typeInfo      = new FamilyTypeInfo();
            IFCExtrusionCreationData extraParams   = typeInfo.extraParams;

            Transform offsetTransform = Transform.Identity;

            // We will create a new mapped type if we haven't already created the type.
            FamilyTypeInfo currentTypeInfo = ExporterCacheManager.FamilySymbolToTypeInfoCache.Find(symbolId, false, exportType);
            bool           found           = currentTypeInfo.IsValid();

            if (!found)
            {
                IList <IFCAnyHandle> representations3D = new List <IFCAnyHandle>();

                IFCAnyHandle dummyPlacement = ExporterUtil.CreateLocalPlacement(file, null, null);
                extraParams.SetLocalPlacement(dummyPlacement);

                using (TransformSetter trfSetter = TransformSetter.Create())
                {
                    BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(false, ExportOptionsCache.ExportTessellationLevel.ExtraLow);

                    bodyData = BodyExporter.ExportBody(exporterIFC, element, categoryId,
                                                       ExporterUtil.GetSingleMaterial(element), exportGeometry,
                                                       bodyExporterOptions, extraParams);
                    typeInfo.MaterialIdList = bodyData.MaterialIds;
                    offsetTransform         = bodyData.OffsetTransform;

                    // This code does not handle openings yet.
                    // The intention for this is FabricationParts and DirectShapes which do not
                    // currently have opening.
                    // If they can have openings in the future, we can add this.
                    IFCAnyHandle bodyRepHnd = bodyData.RepresentationHnd;
                    if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRepHnd) || extraParams.GetOpenings().Count > 0)
                    {
                        return(false);
                    }

                    representations3D.Add(bodyRepHnd);
                    repMapTrfList.Add(null);
                }

                typeInfo.StyleTransform = ExporterIFCUtils.GetUnscaledTransform(exporterIFC,
                                                                                extraParams.GetLocalPlacement());

                IFCAnyHandle typeStyle = FamilyInstanceExporter.CreateTypeEntityHandle(exporterIFC,
                                                                                       ref typeInfo, null, representations3D, repMapTrfList, null,
                                                                                       element, elementType, elementType, false, false,
                                                                                       exportType, out HashSet <IFCAnyHandle> propertySets);

                if (!IFCAnyHandleUtil.IsNullOrHasNoValue(typeStyle))
                {
                    wrapper.RegisterHandleWithElementType(elementType, exportType, typeStyle,
                                                          propertySets);

                    typeInfo.Style = typeStyle;

                    CategoryUtil.TryToCreateMaterialAssocation(exporterIFC, bodyData, elementType,
                                                               element, exportGeometry, typeStyle, typeInfo);

                    // Create other generic classification from ClassificationCode(s)
                    ClassificationUtil.CreateClassification(exporterIFC, file, elementType, typeStyle);
                    ClassificationUtil.CreateUniformatClassification(exporterIFC, file, elementType, typeStyle);
                }
            }

            if (found && !typeInfo.IsValid())
            {
                typeInfo = currentTypeInfo;
            }

            // we'll pretend we succeeded, but we'll do nothing.
            if (!typeInfo.IsValid())
            {
                return(false);
            }

            extraParams = typeInfo.extraParams;

            // We expect no openings, so always add to map.
            ExporterCacheManager.FamilySymbolToTypeInfoCache.Register(symbolId, false, exportType, typeInfo);

            XYZ       scaledMapOrigin = XYZ.Zero;
            Transform scaledTrf       = originalTrf.Multiply(typeInfo.StyleTransform);

            // create instance.
            IList <IFCAnyHandle> shapeReps = FamilyInstanceExporter.CreateShapeRepresentations(exporterIFC,
                                                                                               file, element, categoryId, typeInfo, scaledMapOrigin);

            if (shapeReps == null)
            {
                return(false);
            }

            Transform boundingBoxTrf = (offsetTransform != null) ? offsetTransform.Inverse : Transform.Identity;

            boundingBoxTrf = boundingBoxTrf.Multiply(scaledTrf.Inverse);
            IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geomElem, boundingBoxTrf);

            if (boundingBoxRep != null)
            {
                shapeReps.Add(boundingBoxRep);
            }

            IFCAnyHandle repHnd = (shapeReps.Count > 0) ? IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, shapeReps) : null;

            using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, element, scaledTrf, null))
            {
                IFCAnyHandle instanceHandle            = null;
                IFCAnyHandle localPlacement            = setter.LocalPlacement;
                bool         materialAlreadyAssociated = false;

                // We won't create the instance if:
                // (1) we are exporting to CV2.0/RV, (2) we have no 2D, 3D, or bounding box geometry, and (3) we aren't exporting parts.
                if (!(repHnd == null &&
                      (ExporterCacheManager.ExportOptionsCache.ExportAsCoordinationView2 ||
                       ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView)))
                {
                    string instanceGUID = GUIDUtil.CreateGUID(element);

                    bool isChildInContainer = element.AssemblyInstanceId != ElementId.InvalidElementId;

                    if (IFCAnyHandleUtil.IsNullOrHasNoValue(instanceHandle))
                    {
                        bool isBuildingElementProxy =
                            ((exportType.ExportInstance == IFCEntityType.IfcBuildingElementProxy) ||
                             (exportType.ExportType == IFCEntityType.IfcBuildingElementProxyType));

                        ElementId roomId = setter.UpdateRoomRelativeCoordinates(element,
                                                                                out IFCAnyHandle localPlacementToUse);
                        bool         containedInSpace = (roomId != ElementId.InvalidElementId) && (exportType.ExportInstance != IFCEntityType.IfcSystemFurnitureElement);
                        IFCAnyHandle ownerHistory     = ExporterCacheManager.OwnerHistoryHandle;

                        if (!isBuildingElementProxy)
                        {
                            instanceHandle = IFCInstanceExporter.CreateGenericIFCEntity(exportType, exporterIFC, element, instanceGUID,
                                                                                        ownerHistory, localPlacementToUse, repHnd);
                        }
                        else
                        {
                            instanceHandle = IFCInstanceExporter.CreateBuildingElementProxy(exporterIFC, element, instanceGUID,
                                                                                            ownerHistory, localPlacementToUse, repHnd, exportType.ValidatedPredefinedType);
                        }

                        bool associateToLevel = !containedInSpace && !isChildInContainer;
                        wrapper.AddElement(element, instanceHandle, setter, extraParams, associateToLevel, exportType);
                        if (containedInSpace)
                        {
                            ExporterCacheManager.SpaceInfoCache.RelateToSpace(roomId, instanceHandle);
                        }
                    }

                    if (!IFCAnyHandleUtil.IsNullOrHasNoValue(instanceHandle))
                    {
                        if (ElementFilteringUtil.IsMEPType(exportType) || ElementFilteringUtil.ProxyForMEPType(element, exportType))
                        {
                            ExporterCacheManager.MEPCache.Register(element, instanceHandle);
                        }

                        ExporterCacheManager.HandleToElementCache.Register(instanceHandle, element.Id);

                        if (!materialAlreadyAssociated)
                        {
                            // Create material association for the instance only if the the istance geometry is different from the type
                            // or the type does not have any material association
                            IFCAnyHandle constituentSetHnd = ExporterCacheManager.MaterialSetCache.FindConstituentSetHnd(symbolId);
                            if (IFCAnyHandleUtil.IsNullOrHasNoValue(constituentSetHnd) &&
                                bodyData != null && bodyData.RepresentationItemInfo != null && bodyData.RepresentationItemInfo.Count > 0)
                            {
                                CategoryUtil.CreateMaterialAssociationWithShapeAspect(exporterIFC, element, instanceHandle, bodyData.RepresentationItemInfo);
                            }
                            else
                            {
                                // Create material association in case if bodyData is null
                                CategoryUtil.CreateMaterialAssociation(exporterIFC, instanceHandle, typeInfo.MaterialIdList);
                            }
                        }

                        if (!IFCAnyHandleUtil.IsNullOrHasNoValue(typeInfo.Style))
                        {
                            ExporterCacheManager.TypeRelationsCache.Add(typeInfo.Style, instanceHandle);
                        }
                    }
                }
            }
            return(true);
        }