Exemplo n.º 1
0
        // NOTE: the useMappedGeometriesIfPossible and useGroupsIfPossible options are experimental and do not yet work well.
        // In shipped code, these are always false, and should be kept false until API support routines are proved to be reliable.
        private static BodyData ExportBodyAsBRep(ExporterIFC exporterIFC, IList<GeometryObject> splitGeometryList, 
            IList<int> exportAsBRep, IList<IFCAnyHandle> bodyItems,
            Element element, ElementId categoryId, IFCAnyHandle contextOfItems, double eps, BodyExporterOptions options, BodyData bodyDataIn)
        {
            bool exportAsBReps = true;
            IFCFile file = exporterIFC.GetFile();
            Document document = element.Document;

            // Can't use the optimization functions below if we already have partially populated our body items with extrusions.
            int numExtrusions = bodyItems.Count;
            bool useMappedGeometriesIfPossible = options.UseMappedGeometriesIfPossible && (numExtrusions != 0);
            bool useGroupsIfPossible = options.UseGroupsIfPossible && (numExtrusions != 0);

            IList<HashSet<IFCAnyHandle>> currentFaceHashSetList = new List<HashSet<IFCAnyHandle>>();
            IList<int> startIndexForObject = new List<int>();
            
            BodyData bodyData = new BodyData(bodyDataIn);

            IDictionary<SolidMetrics, HashSet<Solid>> solidMappingGroups = null;
            IList<KeyValuePair<int, Transform>> solidMappings = null;
            IList<ElementId> materialIds = new List<ElementId>();

            if (useMappedGeometriesIfPossible)
            {
                IList<GeometryObject> newGeometryList = null;
                useMappedGeometriesIfPossible = GatherMappedGeometryGroupings(splitGeometryList, out newGeometryList, out solidMappingGroups, out solidMappings);
                if (useMappedGeometriesIfPossible && (newGeometryList != null))
                    splitGeometryList = newGeometryList;
            }

            BodyGroupKey groupKey = null;
            BodyGroupData groupData = null;
            if (useGroupsIfPossible)
            {
                BodyData bodyDataOut = null;
                useGroupsIfPossible = ProcessGroupMembership(exporterIFC, file, element, categoryId, contextOfItems, splitGeometryList, bodyData,
                    out groupKey, out groupData, out bodyDataOut);
                if (bodyDataOut != null)
                    return bodyDataOut;
                if (useGroupsIfPossible)
                    useMappedGeometriesIfPossible = true;
            }

            bool isCoarse = (options.TessellationLevel == BodyExporterOptions.BodyTessellationLevel.Coarse);
            
            int numBRepsToExport = exportAsBRep.Count;
            bool selectiveBRepExport = (numBRepsToExport > 0);
            int numGeoms = selectiveBRepExport ? numBRepsToExport : splitGeometryList.Count;
            
            for (int index = 0; index < numGeoms; index++)
            {
                GeometryObject geomObject = selectiveBRepExport ? splitGeometryList[exportAsBRep[index]] : splitGeometryList[index];
                startIndexForObject.Add(currentFaceHashSetList.Count);

                ElementId materialId = SetBestMaterialIdInExporter(geomObject, exporterIFC);
                materialIds.Add(materialId);
                bodyData.AddMaterial(materialId);

                bool exportedAsSolid = false;
                if (exportAsBReps || isCoarse)
                {
                    exportedAsSolid = ExportBodyAsSolid(exporterIFC, element, options, currentFaceHashSetList, geomObject);
                }
               
                if (!exportedAsSolid)
                {
                    IFCGeometryInfo faceListInfo = IFCGeometryInfo.CreateFaceGeometryInfo(eps, isCoarse);
                    ExporterIFCUtils.CollectGeometryInfo(exporterIFC, faceListInfo, geomObject, XYZ.Zero, false);

                    IList<ICollection<IFCAnyHandle>> faceSetList = faceListInfo.GetFaces();

                    int numBReps = faceSetList.Count;
                    if (numBReps == 0)
                        continue;

                    foreach (ICollection<IFCAnyHandle> currentFaceSet in faceSetList)
                    {
                        if (currentFaceSet.Count == 0)
                            continue;

                        if (exportAsBReps)
                        {
                            if ((currentFaceSet.Count < 4) || !CanCreateClosedShell(currentFaceSet))
                            {
                                exportAsBReps = false;

                                // We'll need to invalidate the extrusions we created and replace them with BReps.
                                if (selectiveBRepExport && (numGeoms != splitGeometryList.Count))
                                {
                                    for (int fixIndex = 0; fixIndex < numExtrusions; fixIndex++)
                                    {
                                        bodyItems[0].Delete();
                                        bodyItems.RemoveAt(0);
                                    }
                                    numExtrusions = 0;
                                    numGeoms = splitGeometryList.Count;
                                    int brepIndex = 0;
                                    for (int fixIndex = 0; fixIndex < numGeoms; fixIndex++)
                                    {
                                        if ((brepIndex < numBRepsToExport) && (exportAsBRep[brepIndex] == fixIndex))
                                        {
                                            brepIndex++;
                                            continue;
                                        }
                                        exportAsBRep.Add(fixIndex);
                                    }
                                    numBRepsToExport = exportAsBRep.Count;
                                }
                            }
                        }

                        currentFaceHashSetList.Add(new HashSet<IFCAnyHandle>(currentFaceSet));
                    }
                }
            }
            startIndexForObject.Add(currentFaceHashSetList.Count);  // end index for last object.

            IList<IFCAnyHandle> repMapItems = new List<IFCAnyHandle>();
            
            int size = currentFaceHashSetList.Count;
            if (exportAsBReps)
            {
                int matToUse = -1;
                for (int ii = 0; ii < size; ii++)
                {
                    if (startIndexForObject[matToUse + 1] == ii)
                        matToUse++;
                    HashSet<IFCAnyHandle> currentFaceHashSet = currentFaceHashSetList[ii];

                    IFCAnyHandle faceOuter = IFCInstanceExporter.CreateClosedShell(file, currentFaceHashSet);
                    IFCAnyHandle brepHnd = RepresentationUtil.CreateFacetedBRep(exporterIFC, document, faceOuter, materialIds[matToUse]);
                    
                    if (!IFCAnyHandleUtil.IsNullOrHasNoValue(brepHnd))
                    {
                        if (useMappedGeometriesIfPossible)
                        {
                            IFCAnyHandle currMappedRepHnd = CreateBRepRepresentationMap(exporterIFC, file, element, categoryId, contextOfItems, brepHnd);
                            repMapItems.Add(currMappedRepHnd);
                            
                            IFCAnyHandle mappedItemHnd = ExporterUtil.CreateDefaultMappedItem(file, currMappedRepHnd);
                            bodyItems.Add(mappedItemHnd);
                        }
                        else
                            bodyItems.Add(brepHnd);
                    }
                }
            }
            else
            {
                IDictionary<ElementId, HashSet<IFCAnyHandle>> faceSets = new Dictionary<ElementId, HashSet<IFCAnyHandle>>();
                int matToUse = -1;
                for (int ii = 0; ii < size; ii++)
                {
                    HashSet<IFCAnyHandle> currentFaceHashSet = currentFaceHashSetList[ii];
                    if (startIndexForObject[matToUse+1] == ii)
                        matToUse++;

                    IFCAnyHandle faceSetHnd = IFCInstanceExporter.CreateConnectedFaceSet(file, currentFaceHashSet);
                    if (useMappedGeometriesIfPossible)
                    {
                        IFCAnyHandle currMappedRepHnd = CreateSurfaceRepresentationMap(exporterIFC, file, element, categoryId, contextOfItems, faceSetHnd);
                        repMapItems.Add(currMappedRepHnd);

                        IFCAnyHandle mappedItemHnd = ExporterUtil.CreateDefaultMappedItem(file, currMappedRepHnd);
                        bodyItems.Add(mappedItemHnd);
                    }
                    else
                    {
                        HashSet<IFCAnyHandle> surfaceSet = null;
                        if (faceSets.TryGetValue(materialIds[matToUse], out surfaceSet))
                        {
                            surfaceSet.Add(faceSetHnd);
                        }
                        else
                        {
                            surfaceSet = new HashSet<IFCAnyHandle>();
                            surfaceSet.Add(faceSetHnd);
                            faceSets[materialIds[matToUse]] = surfaceSet;
                        }
                    }
                }

                if (faceSets.Count > 0)
                {
                    foreach (KeyValuePair<ElementId, HashSet<IFCAnyHandle>> faceSet in faceSets)
                    {
                        IFCAnyHandle surfaceModel = IFCInstanceExporter.CreateFaceBasedSurfaceModel(file, faceSet.Value);
                        BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, document, surfaceModel, faceSet.Key);

                        bodyItems.Add(surfaceModel);
                    }
                }
            }

            if (bodyItems.Count == 0)
                return bodyData;

            // Add in mapped items.
            if (useMappedGeometriesIfPossible && (solidMappings != null))
            {
                foreach (KeyValuePair<int, Transform> mappedItem in solidMappings)
                {
                    for (int idx = startIndexForObject[mappedItem.Key]; idx < startIndexForObject[mappedItem.Key + 1]; idx++)
                    {
                        IFCAnyHandle mappedItemHnd = ExporterUtil.CreateMappedItemFromTransform(file, repMapItems[idx], mappedItem.Value);
                        bodyItems.Add(mappedItemHnd);
                    }
                }
            }

            if (useMappedGeometriesIfPossible)
            {
                bodyData.RepresentationHnd = RepresentationUtil.CreateBodyMappedItemRep(exporterIFC, element, categoryId, contextOfItems, bodyItems);
            }
            else if (exportAsBReps)
            {
                if (numExtrusions > 0)
                    bodyData.RepresentationHnd = RepresentationUtil.CreateSolidModelRep(exporterIFC, element, categoryId, contextOfItems, bodyItems);
                else
                    bodyData.RepresentationHnd = RepresentationUtil.CreateBRepRep(exporterIFC, element, categoryId, contextOfItems, bodyItems);
            }
            else
                bodyData.RepresentationHnd = RepresentationUtil.CreateSurfaceRep(exporterIFC, element, categoryId, contextOfItems, bodyItems, false, null);

            if (useGroupsIfPossible && (groupKey != null) && (groupData != null))
            {
                groupData.Handles = repMapItems;
                ExporterCacheManager.GroupElementGeometryCache.Register(groupKey, groupData);
            }

            return bodyData;
        }
Exemplo n.º 2
0
        /// <summary>
        /// Exports list of geometries to IFC body representation.
        /// </summary>
        /// <param name="application">The Revit application.</param>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="categoryId">The category id.</param>
        /// <param name="geometryListIn">The geometry list.</param>
        /// <param name="options">The settings for how to export the body.</param>
        /// <param name="exportBodyParams">The extrusion creation data.</param>
        /// <returns>The BodyData containing the handle, offset and material ids.</returns>
        public static BodyData ExportBody(Autodesk.Revit.ApplicationServices.Application application, 
            ExporterIFC exporterIFC,
            Element element, 
            ElementId categoryId,
            IList<GeometryObject> geometryListIn,
            BodyExporterOptions options,
            IFCExtrusionCreationData exportBodyParams) 
        {
            BodyData bodyData = new BodyData();
            if (geometryListIn.Count == 0)
                return bodyData;

            Document document = element.Document;
            bool tryToExportAsExtrusion = options.TryToExportAsExtrusion;
            bool canExportSolidModelRep = false;

            IFCFile file = exporterIFC.GetFile();
            IFCAnyHandle contextOfItems = exporterIFC.Get3DContextHandle("Body");
            double scale = exporterIFC.LinearScale;

            double eps = application.VertexTolerance * scale;

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

            bool allFaces = true;
            foreach (GeometryObject geomObject in geometryListIn)
            {
                try
                {
                    bool split = false;
                    if (geomObject is Solid)
                    {
                        Solid solid = geomObject as Solid;
                        IList<Solid> splitVolumes = SolidUtils.SplitVolumes(solid);
                        allFaces = false;

                        if (splitVolumes != null && splitVolumes.Count != 0)
                        {
                            split = true;
                            foreach (Solid currSolid in splitVolumes)
                            {
                                splitGeometryList.Add(currSolid);
                                // The geometry element created by SplitVolumesis a copy which will have its own allocated
                                // membership - this needs to be stored and disposed of (see AllocatedGeometryObjectCache
                                // for details)
                                ExporterCacheManager.AllocatedGeometryObjectCache.AddGeometryObject(currSolid);
                            }
                        }
                    }
                    else if (allFaces && !(geomObject is Face))
                        allFaces = false;

                    if (!split)
                        splitGeometryList.Add(geomObject);
                }
                catch
                {
                    splitGeometryList.Add(geomObject);
                }
            }

            IList<IFCAnyHandle> bodyItems = new List<IFCAnyHandle>();
            IList<ElementId> materialIdsForExtrusions = new List<ElementId>();

            IList<int> exportAsBRep = new List<int>();
            IList<int> exportAsExtrusion = new List<int>();
            
            using (IFCTransaction tr = new IFCTransaction(file))
            {
                if (tryToExportAsExtrusion)
                {
                    // Check to see if we have Geometries or GFaces.
                    // We will have the specific all GFaces case and then the generic case.
                    IList<Face> faces = null;

                    if (allFaces)
                    {
                        faces = new List<Face>();
                        foreach (GeometryObject geometryObject in splitGeometryList)
                        {
                            faces.Add(geometryObject as Face);
                        }
                    }

                    int numExtrusionsToCreate = allFaces ? 1 : splitGeometryList.Count;

                    IList<IList<IFCExtrusionData>> extrusionLists = new List<IList<IFCExtrusionData>>();
                    for (int ii = 0; ii < numExtrusionsToCreate && tryToExportAsExtrusion; ii++)
                    {
                        IList<IFCExtrusionData> extrusionList = new List<IFCExtrusionData>();

                        IFCExtrusionAxes axesToExtrudeIn = exportBodyParams != null ? exportBodyParams.PossibleExtrusionAxes : IFCExtrusionAxes.TryDefault;
                        XYZ directionToExtrudeIn = XYZ.Zero;
                        if (exportBodyParams != null && exportBodyParams.HasCustomAxis)
                            directionToExtrudeIn = exportBodyParams.CustomAxis;

                        IFCExtrusionCalculatorOptions extrusionOptions =
                           new IFCExtrusionCalculatorOptions(exporterIFC, axesToExtrudeIn, directionToExtrudeIn, scale);

                        if (allFaces)
                            extrusionList = IFCExtrusionCalculatorUtils.CalculateExtrusionData(extrusionOptions, faces);
                        else
                            extrusionList = IFCExtrusionCalculatorUtils.CalculateExtrusionData(extrusionOptions, splitGeometryList[ii]);

                        if (extrusionList.Count == 0)
                        {
                            if (!canExportSolidModelRep)
                            {
                                tryToExportAsExtrusion = false;
                                break;
                            }
                            exportAsBRep.Add(ii);
                        }
                        else
                        {
                            extrusionLists.Add(extrusionList);
                            exportAsExtrusion.Add(ii);
                        }
                    }

                    int numCreatedExtrusions = extrusionLists.Count;
                    for (int ii = 0; (ii < numCreatedExtrusions) && tryToExportAsExtrusion; ii++)
                    {
                        int geomIndex = exportAsExtrusion[ii];
                        bodyData.AddMaterial(SetBestMaterialIdInExporter(splitGeometryList[geomIndex], exporterIFC));

                        if (exportBodyParams != null && exportBodyParams.AreInnerRegionsOpenings)
                        {
                            IList<CurveLoop> curveLoops = extrusionLists[ii][0].GetLoops();
                            XYZ extrudedDirection = extrusionLists[ii][0].ExtrusionDirection;

                            int numLoops = curveLoops.Count;
                            for (int jj = numLoops - 1; jj > 0; jj--)
                            {
                                ExtrusionExporter.AddOpeningData(exportBodyParams, extrusionLists[ii][0], curveLoops[jj]);
                                extrusionLists[ii][0].RemoveLoopAt(jj);
                            }
                        }

                        bool exportedAsExtrusion = false;
                        IFCExtrusionBasis whichBasis = extrusionLists[ii][0].ExtrusionBasis;
                        if (whichBasis >= 0)
                        {
                            IFCAnyHandle extrusionHandle = ExtrusionExporter.CreateExtrudedSolidFromExtrusionData(exporterIFC, element, extrusionLists[ii][0]);
                            if (!IFCAnyHandleUtil.IsNullOrHasNoValue(extrusionHandle))
                            {
                                bodyItems.Add(extrusionHandle);
                                materialIdsForExtrusions.Add(exporterIFC.GetMaterialIdForCurrentExportState());

                                IList<CurveLoop> curveLoops = extrusionLists[ii][0].GetLoops();
                                XYZ extrusionDirection = extrusionLists[ii][0].ExtrusionDirection;

                                if (exportBodyParams != null)
                                {
                                    double zOff = (whichBasis == IFCExtrusionBasis.BasisZ) ? (1.0 - Math.Abs(extrusionDirection[2])) : Math.Abs(extrusionDirection[2]);
                                    double scaledAngle = Math.Asin(zOff) * 180 / Math.PI;
                                    exportBodyParams.Slope = scaledAngle;
                                    exportBodyParams.ScaledLength = extrusionLists[ii][0].ScaledExtrusionLength;
                                    exportBodyParams.ExtrusionDirection = extrusionDirection;
                                    for (int kk = 1; kk < extrusionLists[ii].Count; kk++)
                                    {
                                        ExtrusionExporter.AddOpeningData(exportBodyParams, extrusionLists[ii][kk]);
                                    }

                                    Plane plane = null;
                                    double height = 0.0, width = 0.0;
                                    if (ExtrusionExporter.ComputeHeightWidthOfCurveLoop(curveLoops[0], plane, out height, out width))
                                    {
                                        exportBodyParams.ScaledHeight = height * scale;
                                        exportBodyParams.ScaledWidth = width * scale;
                                    }

                                    double area = ExporterIFCUtils.ComputeAreaOfCurveLoops(curveLoops);
                                    if (area > 0.0)
                                    {
                                        exportBodyParams.ScaledArea = area * scale * scale;
                                    }

                                    double innerPerimeter = ExtrusionExporter.ComputeInnerPerimeterOfCurveLoops(curveLoops);
                                    double outerPerimeter = ExtrusionExporter.ComputeOuterPerimeterOfCurveLoops(curveLoops);
                                    if (innerPerimeter > 0.0)
                                        exportBodyParams.ScaledInnerPerimeter = innerPerimeter * scale;
                                    if (outerPerimeter > 0.0)
                                        exportBodyParams.ScaledOuterPerimeter = outerPerimeter * scale;
                                }
                                exportedAsExtrusion = true;
                            }
                        }

                        if (!exportedAsExtrusion)
                        {
                            if (!canExportSolidModelRep)
                            {
                                tryToExportAsExtrusion = false;
                                break;
                            }
                            exportAsBRep.Add(ii);
                        }
                    }
                }

                if ((exportAsBRep.Count == 0) && tryToExportAsExtrusion)
                {
                    int sz = bodyItems.Count();
                    for (int ii = 0; ii < sz; ii++)
                        BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, document, bodyItems[ii], materialIdsForExtrusions[ii]);

                    bodyData.RepresentationHnd =
                        RepresentationUtil.CreateSweptSolidRep(exporterIFC, element, categoryId, contextOfItems, bodyItems, bodyData.RepresentationHnd);
                }

                if (tryToExportAsExtrusion)
                    tr.Commit();
                else
                    tr.RollBack();

                if ((exportAsBRep.Count == 0) && tryToExportAsExtrusion)
                    return bodyData;
            }
            
            // We couldn't export it as an extrusion; export as a solid, brep, or a surface model.
            if (!canExportSolidModelRep)
            {
                exportAsExtrusion.Clear();
                bodyItems.Clear();
                if (exportBodyParams != null)
                    exportBodyParams.ClearOpenings();
            }

            if (exportAsExtrusion.Count == 0)
                exportAsBRep.Clear();

            // generate "bottom corner" of bbox; create new local placement if passed in.
            // need to transform, but not scale, this point to make it the new origin.
            // We will only do this if we didn't create any extrusions at all.
            using (IFCTransformSetter transformSetter = IFCTransformSetter.Create())
            {
                if (exportBodyParams != null && (exportAsBRep.Count == 0))
                    bodyData.BrepOffsetTransform = transformSetter.InitializeFromBoundingBox(exporterIFC, splitGeometryList, exportBodyParams);

                return ExportBodyAsBRep(exporterIFC, splitGeometryList, exportAsBRep, bodyItems, element, categoryId, contextOfItems, eps, options, bodyData);
            }
        }
        /// <summary>
        /// Exports list of geometries to IFC body representation.
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="categoryId">The category id.</param>
        /// <param name="geometryListIn">The geometry list.</param>
        /// <param name="options">The settings for how to export the body.</param>
        /// <param name="exportBodyParams">The extrusion creation data.</param>
        /// <returns>The BodyData containing the handle, offset and material ids.</returns>
        public static BodyData ExportBody(ExporterIFC exporterIFC,
            Element element, 
            ElementId categoryId,
            ElementId overrideMaterialId,
            IList<GeometryObject> geometryList,
            BodyExporterOptions options,
            IFCExtrusionCreationData exportBodyParams) 
        {
            BodyData bodyData = new BodyData();
            if (geometryList.Count == 0)
                return bodyData;

            Document document = element.Document;
            bool tryToExportAsExtrusion = options.TryToExportAsExtrusion;
            bool canExportSolidModelRep = tryToExportAsExtrusion && ExporterCacheManager.ExportOptionsCache.CanExportSolidModelRep;
            
            // This will default to false for now in all cases, as swept solids are not included in CV2.0.
            bool tryToExportAsSweptSolid = options.TryToExportAsSweptSolid;
            
            IFCFile file = exporterIFC.GetFile();
            IFCAnyHandle contextOfItems = exporterIFC.Get3DContextHandle("Body");
            double scale = exporterIFC.LinearScale;

            double eps = element.Document.Application.VertexTolerance * scale;

            bool allFaces = true;
            foreach (GeometryObject geomObject in geometryList)
            {
                if (allFaces && !(geomObject is Face))
                        allFaces = false;
                break;
            }

            IList<IFCAnyHandle> bodyItems = new List<IFCAnyHandle>();
            IList<ElementId> materialIdsForExtrusions = new List<ElementId>();

            IList<int> exportAsBRep = new List<int>();
            IList<int> exportAsSweptSolid = new List<int>();
            IList<int> exportAsExtrusion = new List<int>();

            bool hasExtrusions = false;
            bool hasSweptSolids = false;

            XYZ unscaledTrfOrig = new XYZ();
            using (IFCTransaction tr = new IFCTransaction(file))
            {
                // generate "bottom corner" of bbox; create new local placement if passed in.
                // need to transform, but not scale, this point to make it the new origin.
                using (IFCTransformSetter transformSetter = IFCTransformSetter.Create())
                {
                    // We may need to get the original values back, in case the export rolls back.
                    IFCLocalPlacementBackup localPlacementBackup = null;

                    if (options.AllowOffsetTransform && exportBodyParams!= null)
                    {
                        localPlacementBackup = new IFCLocalPlacementBackup(exportBodyParams.GetLocalPlacement());
                        bodyData.OffsetTransform = transformSetter.InitializeFromBoundingBox(exporterIFC, geometryList, exportBodyParams);
                    }

                    if (tryToExportAsExtrusion)
                    {
                        // Check to see if we have Geometries or GFaces.
                        // We will have the specific all GFaces case and then the generic case.
                        IList<Face> faces = null;

                        if (allFaces)
                        {
                            faces = new List<Face>();
                            foreach (GeometryObject geometryObject in geometryList)
                            {
                                faces.Add(geometryObject as Face);
                            }
                        }

                        int numExtrusionsToCreate = allFaces ? 1 : geometryList.Count;

                        IList<IList<IFCExtrusionData>> extrusionLists = new List<IList<IFCExtrusionData>>();
                        for (int ii = 0; ii < numExtrusionsToCreate && tryToExportAsExtrusion; ii++)
                        {
                            IList<IFCExtrusionData> extrusionList = new List<IFCExtrusionData>();

                            IFCExtrusionAxes axesToExtrudeIn = exportBodyParams != null ? exportBodyParams.PossibleExtrusionAxes : IFCExtrusionAxes.TryDefault;
                            XYZ directionToExtrudeIn = XYZ.Zero;
                            if (exportBodyParams != null && exportBodyParams.HasCustomAxis)
                                directionToExtrudeIn = exportBodyParams.CustomAxis;

                            IFCExtrusionCalculatorOptions extrusionOptions =
                               new IFCExtrusionCalculatorOptions(exporterIFC, axesToExtrudeIn, directionToExtrudeIn, scale);

                            if (allFaces)
                                extrusionList = IFCExtrusionCalculatorUtils.CalculateExtrusionData(extrusionOptions, faces);
                            else
                                extrusionList = IFCExtrusionCalculatorUtils.CalculateExtrusionData(extrusionOptions, geometryList[ii]);

                            if (extrusionList.Count == 0)
                            {
                                if (tryToExportAsSweptSolid)
                                    exportAsSweptSolid.Add(ii);
                                else if (!canExportSolidModelRep)
                                {
                                    tryToExportAsExtrusion = false;
                                    break;
                                }
                                else
                                    exportAsBRep.Add(ii);
                            }
                            else
                            {
                                extrusionLists.Add(extrusionList);
                                exportAsExtrusion.Add(ii);
                            }
                        }

                        int numCreatedExtrusions = extrusionLists.Count;
                        for (int ii = 0; ii < numCreatedExtrusions && tryToExportAsExtrusion; ii++)
                        {
                            int geomIndex = exportAsExtrusion[ii];

                            ElementId matId = SetBestMaterialIdInExporter(geometryList[geomIndex], element, overrideMaterialId, exporterIFC);
                            if (matId != ElementId.InvalidElementId)
                                bodyData.AddMaterial(matId);

                            if (exportBodyParams != null && exportBodyParams.AreInnerRegionsOpenings)
                            {
                                IList<CurveLoop> curveLoops = extrusionLists[ii][0].GetLoops();
                                XYZ extrudedDirection = extrusionLists[ii][0].ExtrusionDirection;

                                int numLoops = curveLoops.Count;
                                for (int jj = numLoops - 1; jj > 0; jj--)
                                {
                                    ExtrusionExporter.AddOpeningData(exportBodyParams, extrusionLists[ii][0], curveLoops[jj]);
                                    extrusionLists[ii][0].RemoveLoopAt(jj);
                                }
                            }

                            bool exportedAsExtrusion = false;
                            IFCExtrusionBasis whichBasis = extrusionLists[ii][0].ExtrusionBasis;
                            if (whichBasis >= 0)
                            {
                                IFCAnyHandle extrusionHandle = ExtrusionExporter.CreateExtrudedSolidFromExtrusionData(exporterIFC, element, extrusionLists[ii][0]);
                                if (!IFCAnyHandleUtil.IsNullOrHasNoValue(extrusionHandle))
                                {
                                    bodyItems.Add(extrusionHandle);
                                    materialIdsForExtrusions.Add(exporterIFC.GetMaterialIdForCurrentExportState());

                                    IList<CurveLoop> curveLoops = extrusionLists[ii][0].GetLoops();
                                    XYZ extrusionDirection = extrusionLists[ii][0].ExtrusionDirection;

                                    if (exportBodyParams != null)
                                    {
                                        exportBodyParams.Slope = GeometryUtil.GetSimpleExtrusionSlope(extrusionDirection, whichBasis);
                                        exportBodyParams.ScaledLength = extrusionLists[ii][0].ScaledExtrusionLength;
                                        exportBodyParams.ExtrusionDirection = extrusionDirection;
                                        for (int kk = 1; kk < extrusionLists[ii].Count; kk++)
                                        {
                                            ExtrusionExporter.AddOpeningData(exportBodyParams, extrusionLists[ii][kk]);
                                        }

                                        Plane plane = null;
                                        double height = 0.0, width = 0.0;
                                        if (ExtrusionExporter.ComputeHeightWidthOfCurveLoop(curveLoops[0], plane, out height, out width))
                                        {
                                            exportBodyParams.ScaledHeight = height * scale;
                                            exportBodyParams.ScaledWidth = width * scale;
                                        }

                                        double area = ExporterIFCUtils.ComputeAreaOfCurveLoops(curveLoops);
                                        if (area > 0.0)
                                        {
                                            exportBodyParams.ScaledArea = area * scale * scale;
                                        }

                                        double innerPerimeter = ExtrusionExporter.ComputeInnerPerimeterOfCurveLoops(curveLoops);
                                        double outerPerimeter = ExtrusionExporter.ComputeOuterPerimeterOfCurveLoops(curveLoops);
                                        if (innerPerimeter > 0.0)
                                            exportBodyParams.ScaledInnerPerimeter = innerPerimeter * scale;
                                        if (outerPerimeter > 0.0)
                                            exportBodyParams.ScaledOuterPerimeter = outerPerimeter * scale;
                                    }
                                    exportedAsExtrusion = true;
                                    hasExtrusions = true;
                                }
                            }

                            if (!exportedAsExtrusion)
                            {
                                if (tryToExportAsSweptSolid)
                                    exportAsSweptSolid.Add(ii);
                                else if (!canExportSolidModelRep)
                                {
                                    tryToExportAsExtrusion = false;
                                    break;
                                }
                                else
                                    exportAsBRep.Add(ii);
                            }
                        }
                    }

                    if (tryToExportAsSweptSolid)
                    {
                        int numCreatedSweptSolids = exportAsSweptSolid.Count;
                        for (int ii = 0; (ii < numCreatedSweptSolids) && tryToExportAsSweptSolid; ii++)
                        {
                            bool exported = false;
                            int geomIndex = exportAsSweptSolid[ii];
                            Solid solid = geometryList[geomIndex] as Solid;
                            // TODO: allFaces to SweptSolid
                            if (solid != null)
                            {
                                // TODO: other types of Axes
                                XYZ normal = new XYZ(0, 0, 1);
                                SweptSolidExporter sweptSolidExporter = SweptSolidExporter.Create(exporterIFC, element, solid, normal);
                                if (sweptSolidExporter != null)
                                {
                                    IFCAnyHandle sweptHandle = sweptSolidExporter.RepresentationItem;
                                    if (!IFCAnyHandleUtil.IsNullOrHasNoValue(sweptHandle))
                                    {
                                        bodyItems.Add(sweptHandle);
                                        materialIdsForExtrusions.Add(exporterIFC.GetMaterialIdForCurrentExportState());
                                        exported = true;
                                        if (sweptSolidExporter.IsExtrusion)
                                            hasExtrusions = true;
                                        else
                                            hasSweptSolids = true;
                                    }
                                }
                            }

                            if (!exported)
                                exportAsBRep.Add(ii);
                        }
                    }

                    bool exportSucceeded = (exportAsBRep.Count == 0) && (tryToExportAsExtrusion || tryToExportAsSweptSolid) && (hasExtrusions || hasSweptSolids);
                    if (exportSucceeded || canExportSolidModelRep)
                    {
                        int sz = bodyItems.Count();
                        for (int ii = 0; ii < sz; ii++)
                            BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, document, bodyItems[ii], materialIdsForExtrusions[ii]);

                        if (exportSucceeded)
                        {
                        if (hasExtrusions && !hasSweptSolids)
                        {
                            bodyData.RepresentationHnd =
                                RepresentationUtil.CreateSweptSolidRep(exporterIFC, element, categoryId, contextOfItems, bodyItems, bodyData.RepresentationHnd);
                            bodyData.ShapeRepresentationType = ShapeRepresentationType.SweptSolid;
                        }
                        else if (hasSweptSolids && !hasExtrusions)
                        {
                            bodyData.RepresentationHnd =
                                RepresentationUtil.CreateAdvancedSweptSolidRep(exporterIFC, element, categoryId, contextOfItems, bodyItems, bodyData.RepresentationHnd);
                            bodyData.ShapeRepresentationType = ShapeRepresentationType.AdvancedSweptSolid;
                        }
                        else
                        {
                            bodyData.RepresentationHnd =
                                RepresentationUtil.CreateSolidModelRep(exporterIFC, element, categoryId, contextOfItems, bodyItems);
                            bodyData.ShapeRepresentationType = ShapeRepresentationType.SolidModel;
                        }
                        
                        // TODO: include BRep, CSG, Clipping
                        tr.Commit();
                        return bodyData;
                    }
                    }

                    // If we are going to export a solid model, keep the created items.
                    if (!canExportSolidModelRep)
                    {
                        tr.RollBack();

                        // Revert to the original local placement, and re-set the relative placement, as the rollback may delete either.
                        if (localPlacementBackup != null)
                        {
                           IFCAnyHandle origLocalPlacement = localPlacementBackup.Restore();
                           if (!IFCAnyHandleUtil.IsNullOrHasNoValue(origLocalPlacement))
                               exportBodyParams.SetLocalPlacement(origLocalPlacement);
                        }
                    }
                    else
                        tr.Commit();
                }

                // We couldn't export it as an extrusion; export as a solid, brep, or a surface model.
                if (!canExportSolidModelRep)
                {
                    exportAsExtrusion.Clear();
                    bodyItems.Clear();
                    if (exportBodyParams != null)
                        exportBodyParams.ClearOpenings();
                }

                if (exportAsExtrusion.Count == 0)
                    exportAsBRep.Clear();
            }

            using (IFCTransaction tr = new IFCTransaction(file))
            {
                using (IFCTransformSetter transformSetter = IFCTransformSetter.Create())
                {
                    if (exportBodyParams != null && (exportAsBRep.Count == 0))
                        bodyData.OffsetTransform = transformSetter.InitializeFromBoundingBox(exporterIFC, geometryList, exportBodyParams);

                    BodyData retBodyData = ExportBodyAsBRep(exporterIFC, geometryList, exportAsBRep, bodyItems, element, categoryId, overrideMaterialId, contextOfItems, eps, options, bodyData);
                    if (retBodyData != null)
                        tr.Commit();
                    else
                        tr.RollBack();
                    return retBodyData;
                }
            }
        }