/// <summary>
        /// Caches all parameter value overrides of the subelement.
        /// </summary>
        /// <param name="element">The rebar element.</param>
        /// <param name="parameters">The paramters of the rebar element.</param>
        /// <param name="barIndex">The index of the subelement.</param>
        /// <param name="handleSubelement">The handle of the subelement.</param>
        static void CacheSubelementParameterValues(Element element, ParameterSet parameters, int barIndex, IFCAnyHandle handleSubelement)
        {
            if (element == null)
            {
                return;
            }

            if (element is Rebar)
            {
                Rebar rebar = element as Rebar;
                if (rebar.DistributionType != DistributionType.VaryingLength)
                {
                    return;
                }

                foreach (Parameter param in parameters)
                {
                    ParameterUtil.CacheParameterValuesForSubelementHandle(element.Id, handleSubelement, param, rebar.GetParameterValueAtIndex(param.Id, barIndex));
                }
            }
        }
        /// <summary>
        /// Exports a Rebar to IFC ReinforcingBar.
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="rebarItem">The rebar to be exported.  This might be an element or a sub-element.</param>
        /// <param name="rebarElement">The element that contains the rebar to be exported.  This may be the same as rebarItem.</param>
        /// <param name="itemIndex">If greater than 0, the index of the first rebar in the rebarItem in the rebarElement, used for naming and GUID creation.</param>
        /// <param name="productWrapper">The ProductWrapper object.</param>
        /// <returns>The set of handles created, to add to the ProductWrapper in the calling function.</returns>
        private static ISet <DelayedProductWrapper> ExportRebar(ExporterIFC exporterIFC, object rebarItem, Element rebarElement, int itemIndex, ProductWrapper productWrapper)
        {
            // Check the intended IFC entity or type name is in the exclude list specified in the UI
            Common.Enums.IFCEntityType elementClassTypeEnum;
            if (Enum.TryParse <Common.Enums.IFCEntityType>("IfcReinforcingBar", out elementClassTypeEnum))
            {
                if (ExporterCacheManager.ExportOptionsCache.IsElementInExcludeList(elementClassTypeEnum))
                {
                    return(null);
                }
            }

            IFCFile file = exporterIFC.GetFile();
            HashSet <DelayedProductWrapper> createdRebars = new HashSet <DelayedProductWrapper>();

            int rebarQuantity = GetRebarQuantity(rebarItem);

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

            using (IFCTransaction transaction = new IFCTransaction(file))
            {
                using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, rebarElement))
                {
                    bool         cannotExportRebar = false;
                    IFCAnyHandle rebarHandle       = ExportRebarAsProxyElementInView(exporterIFC, rebarElement, productWrapper, out cannotExportRebar);
                    if (!IFCAnyHandleUtil.IsNullOrHasNoValue(rebarHandle) || cannotExportRebar)
                    {
                        if (!cannotExportRebar)
                        {
                            transaction.Commit();
                        }
                        return(null); // Rebar doesn't create a group.
                    }

                    IFCAnyHandle prodRep = null;

                    double totalBarLengthUnscale = GetRebarTotalLength(rebarItem);
                    double volumeUnscale         = GetRebarVolume(rebarItem);
                    double totalBarLength        = UnitUtil.ScaleLength(totalBarLengthUnscale);

                    if (MathUtil.IsAlmostZero(totalBarLength))
                    {
                        return(null);
                    }

                    ElementId materialId = ElementId.InvalidElementId;
                    ParameterUtil.GetElementIdValueFromElementOrSymbol(rebarElement, BuiltInParameter.MATERIAL_ID_PARAM, out materialId);

                    double diameter = GetBarDiameter(rebarItem);
                    double radius   = diameter / 2.0;
                    double longitudinalBarNominalDiameter  = diameter;
                    double longitudinalBarCrossSectionArea = UnitUtil.ScaleArea(volumeUnscale / totalBarLengthUnscale);

                    int numberOfBarPositions = GetNumberOfBarPositions(rebarItem);

                    string steelGrade = NamingUtil.GetOverrideStringValue(rebarElement, "SteelGrade", null);

                    // Allow use of IFC2x3 or IFC4 naming.
                    string predefinedType = NamingUtil.GetOverrideStringValue(rebarElement, "BarRole", null);
                    if (string.IsNullOrWhiteSpace(predefinedType))
                    {
                        predefinedType = NamingUtil.GetOverrideStringValue(rebarElement, "PredefinedType", null);
                    }
                    IFCReinforcingBarRole role = GetReinforcingBarRole(predefinedType);

                    string origRebarName = NamingUtil.GetNameOverride(rebarElement, NamingUtil.GetIFCName(rebarElement));

                    const int maxBarGUIDS = IFCReinforcingBarSubElements.BarEnd - IFCReinforcingBarSubElements.BarStart + 1;
                    ElementId categoryId  = CategoryUtil.GetSafeCategoryId(rebarElement);

                    IFCAnyHandle originalPlacement = setter.LocalPlacement;

                    // Potential issue : totalBarLength has a rounded value but individual lengths (from centerlines) do not have rounded values.
                    // Also dividing a rounded totalBarLength does not result in barLength rounded by the same round value.
                    double        barLength  = totalBarLength / rebarQuantity;
                    IList <Curve> baseCurves = GetRebarCenterlineCurves(rebarItem, true, false, false);

                    ElementId    barLengthParamId   = new ElementId(BuiltInParameter.REBAR_ELEM_LENGTH);
                    ParameterSet rebarElementParams = rebarElement.Parameters;
                    for (int ii = 0; ii < numberOfBarPositions; ii++)
                    {
                        if (!DoesBarExistAtPosition(rebarItem, ii))
                        {
                            continue;
                        }

                        Rebar rebar = rebarElement as Rebar;
                        if ((rebar != null) && (rebar.DistributionType == DistributionType.VaryingLength || rebar.IsRebarFreeForm()))
                        {
                            baseCurves = GetRebarCenterlineCurves(rebar, true, false, false, MultiplanarOption.IncludeOnlyPlanarCurves, ii);
                            DoubleParameterValue barLengthParamVal = rebar.GetParameterValueAtIndex(barLengthParamId, ii) as DoubleParameterValue;
                            if (barLengthParamVal != null)
                            {
                                barLength = barLengthParamVal.Value;
                            }
                        }

                        int indexForNamingAndGUID = (itemIndex > 0) ? ii + itemIndex : ii + 1;

                        string rebarName = NamingUtil.GetNameOverride(rebarElement, origRebarName + ": " + indexForNamingAndGUID);

                        Transform barTrf = GetBarPositionTransform(rebarItem, ii);

                        IList <Curve> curves   = new List <Curve>();
                        double        endParam = 0.0;
                        foreach (Curve baseCurve in baseCurves)
                        {
                            if (baseCurve is Arc || baseCurve is Ellipse)
                            {
                                if (baseCurve.IsBound)
                                {
                                    endParam += UnitUtil.ScaleAngle(baseCurve.GetEndParameter(1) - baseCurve.GetEndParameter(0));
                                }
                                else
                                {
                                    endParam += UnitUtil.ScaleAngle(2 * Math.PI);
                                }
                            }
                            else
                            {
                                endParam += 1.0;
                            }
                            curves.Add(baseCurve.CreateTransformed(barTrf));
                        }

                        IFCAnyHandle           compositeCurve = GeometryUtil.CreateCompositeCurve(exporterIFC, curves);
                        IFCAnyHandle           sweptDiskSolid = IFCInstanceExporter.CreateSweptDiskSolid(file, compositeCurve, radius, null, 0, endParam);
                        HashSet <IFCAnyHandle> bodyItems      = new HashSet <IFCAnyHandle>();
                        bodyItems.Add(sweptDiskSolid);

                        IFCAnyHandle         shapeRep  = RepresentationUtil.CreateAdvancedSweptSolidRep(exporterIFC, rebarElement, categoryId, exporterIFC.Get3DContextHandle("Body"), bodyItems, null);
                        IList <IFCAnyHandle> shapeReps = new List <IFCAnyHandle>();
                        shapeReps.Add(shapeRep);
                        prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, shapeReps);

                        IFCAnyHandle copyLevelPlacement = (ii == 0) ? originalPlacement : ExporterUtil.CopyLocalPlacement(file, originalPlacement);

                        string rebarGUID = (indexForNamingAndGUID < maxBarGUIDS) ?
                                           GUIDUtil.CreateSubElementGUID(rebarElement, indexForNamingAndGUID + (int)IFCReinforcingBarSubElements.BarStart - 1) :
                                           GUIDUtil.CreateGUID();
                        IFCAnyHandle elemHnd = IFCInstanceExporter.CreateReinforcingBar(exporterIFC, rebarElement, rebarGUID, ExporterCacheManager.OwnerHistoryHandle,
                                                                                        copyLevelPlacement, prodRep, steelGrade, longitudinalBarNominalDiameter, longitudinalBarCrossSectionArea, barLength, role, null);
                        IFCAnyHandleUtil.SetAttribute(elemHnd, "Name", rebarName);

                        // We will not add the element ot the productWrapper here, but instead in the function that calls
                        // ExportRebar.  The reason for this is that we don't currently know if the handles such be associated
                        // to the level or not, depending on whether they will or won't be grouped.
                        createdRebars.Add(new DelayedProductWrapper(rebarElement, elemHnd, setter.LevelInfo));

                        CacheSubelementParameterValues(rebarElement, rebarElementParams, ii, elemHnd);

                        ExporterCacheManager.HandleToElementCache.Register(elemHnd, rebarElement.Id);
                        CategoryUtil.CreateMaterialAssociation(exporterIFC, elemHnd, materialId);
                    }
                }
                transaction.Commit();
            }
            return(createdRebars);
        }