Example #1
0
        private static bool IsInRange(IFCRange range, CurveLoop loop, Plane plane, XYZ extrusionDirection, out bool clipCompletely)
        {
            clipCompletely = false;
            if (range != null)
            {
                // This check is only applicable for cuts that are perpendicular to the extrusion direction.
                // For cuts that aren't, we can't easily tell if this cut is extraneous or not.
                if (!MathUtil.IsAlmostEqual(Math.Abs(plane.Normal.DotProduct(extrusionDirection)), 1.0))
                {
                    return(true);
                }

                double eps = MathUtil.Eps();

                double parameterValue = plane.Origin.DotProduct(extrusionDirection);

                if (range.Start > parameterValue - eps)
                {
                    clipCompletely = true;
                    return(false);
                }
                if (range.End < parameterValue + eps)
                {
                    return(false);
                }
            }

            return(true);
        }
Example #2
0
 /// <summary>
 /// Adds openings to an element.
 /// </summary>
 /// <param name="exporterIFC">The exporter.</param>
 /// <param name="elementHandle">The parent handle.</param>
 /// <param name="element">The element.</param>
 /// <param name="lcs">The local coordinate system.</param>
 /// <param name="scaledWidth">The width.</param>
 /// <param name="range">The range.</param>
 /// <param name="setter">The placement setter.</param>
 /// <param name="localPlacement">The local placement.</param>
 /// <param name="localWrapper">The wrapper.</param>
 public static void AddOpeningsToElement(ExporterIFC exporterIFC, IFCAnyHandle elementHandle, Element element, Transform lcs, double scaledWidth,
     IFCRange range, PlacementSetter setter, IFCAnyHandle localPlacement, ProductWrapper localWrapper)
 {
     IList<IFCAnyHandle> elementHandles = new List<IFCAnyHandle>();
      elementHandles.Add(elementHandle);
      AddOpeningsToElement(exporterIFC, elementHandles, null, element, lcs, scaledWidth, range, setter, localPlacement, localWrapper);
 }
Example #3
0
        private static string CreateOpeningGUID(Element openingElem, IFCRange range, int openingIndex,
                                                int solidIndex)
        {
            // GUID_TODO: Range can be potentially unstable; getting the corresponding level would be
            // better.
            string openingId = (range != null) ?
                               "(" + range.Start.ToString() + ":" + range.End.ToString() + ")" :
                               string.Empty;

            openingId += "Opening:" + openingIndex.ToString() + "Solid:" + solidIndex.ToString();
            return(GUIDUtil.GenerateIFCGuidFrom(openingElem, openingId));
        }
Example #4
0
 /// <summary>
 /// Gets origin, X direction and curve bound from a curve.
 /// </summary>
 /// <param name="curve">
 /// The curve.
 /// </param>
 /// <param name="curveBounds">
 /// The output curve bounds.
 /// </param>
 /// <param name="xDirection">
 /// The output X direction.
 /// </param>
 /// <param name="origin">
 /// The output origin.
 /// </param>
 public static void GetAxisAndRangeFromCurve(Curve curve,
                                             out IFCRange curveBounds, out XYZ xDirection, out XYZ origin)
 {
     curveBounds = new IFCRange(curve.get_EndParameter(0), curve.get_EndParameter(1));
     origin      = curve.Evaluate(curveBounds.Start, false);
     if (curve is Arc)
     {
         Arc arc = curve as Arc;
         xDirection = arc.XDirection;
     }
     else
     {
         Transform trf = curve.ComputeDerivatives(curveBounds.Start, false);
         xDirection = trf.get_Basis(0);
     }
 }
Example #5
0
        private static IFCRange GetExtrusionRangeOfCurveLoop(CurveLoop loop, XYZ extrusionDirection)
        {
            IFCRange range = new IFCRange();
            bool     init  = false;

            foreach (Curve curve in loop)
            {
                if (!init)
                {
                    if (curve.IsBound)
                    {
                        IList <XYZ> coords = curve.Tessellate();
                        foreach (XYZ coord in coords)
                        {
                            double val = coord.DotProduct(extrusionDirection);
                            if (!init)
                            {
                                range.Start = val;
                                range.End   = val;
                                init        = true;
                            }
                            else
                            {
                                range.Start = Math.Min(range.Start, val);
                                range.End   = Math.Max(range.End, val);
                            }
                        }
                    }
                    else
                    {
                        double val = curve.get_EndPoint(0).DotProduct(extrusionDirection);
                        range.Start = val;
                        range.End   = val;
                        init        = true;
                    }
                }
                else
                {
                    double val = curve.get_EndPoint(0).DotProduct(extrusionDirection);
                    range.Start = Math.Min(range.Start, val);
                    range.End   = Math.Max(range.End, val);
                }
            }
            return(range);
        }
Example #6
0
        // returns true if either, but not both, the start or end of the extrusion is clipped.
        private static KeyValuePair <bool, bool> CollectionClipsExtrusionEnds(IList <CurveLoop> curveLoopBoundaries, XYZ extrusionDirection,
                                                                              IFCRange extrusionRange)
        {
            bool   clipStart = false;
            bool   clipEnd   = false;
            double eps       = MathUtil.Eps();

            foreach (CurveLoop curveLoop in curveLoopBoundaries)
            {
                IFCRange loopRange = GetExtrusionRangeOfCurveLoop(curveLoop, extrusionDirection);
                if (loopRange.End >= extrusionRange.End - eps)
                {
                    clipEnd = true;
                }
                if (loopRange.Start <= extrusionRange.Start + eps)
                {
                    clipStart = true;
                }
            }

            KeyValuePair <bool, bool> clipResults = new KeyValuePair <bool, bool>(clipStart, clipEnd);

            return(clipResults);
        }
        // returns true if either, but not both, the start or end of the extrusion is clipped.
        private static KeyValuePair<bool, bool> CollectionClipsExtrusionEnds(IList<CurveLoop> curveLoopBoundaries, XYZ extrusionDirection, 
            IFCRange extrusionRange)
        {
            bool clipStart = false;
            bool clipEnd = false;
            double eps = MathUtil.Eps();

            foreach (CurveLoop curveLoop in curveLoopBoundaries)
            {
                IFCRange loopRange = GetExtrusionRangeOfCurveLoop(curveLoop, extrusionDirection);
                if (loopRange.End >= extrusionRange.End - eps)
                    clipEnd = true;
                if (loopRange.Start <= extrusionRange.Start + eps)
                    clipStart = true;
            }

            KeyValuePair<bool, bool> clipResults = new KeyValuePair<bool, bool>(clipStart, clipEnd);
            return clipResults;
        }
        private static bool IsInRange(IFCRange range, CurveLoop loop, Plane plane, XYZ extrusionDirection, out bool clipCompletely)
        {
            clipCompletely = false;
            if (range != null)
            {
                // This check is only applicable for cuts that are perpendicular to the extrusion direction.
                // For cuts that aren't, we can't easily tell if this cut is extraneous or not.
                if (!MathUtil.IsAlmostEqual(Math.Abs(plane.Normal.DotProduct(extrusionDirection)), 1.0))
                    return true;

                double eps = MathUtil.Eps();

                double parameterValue = plane.Origin.DotProduct(extrusionDirection);

                if (range.Start > parameterValue - eps)
                {
                    clipCompletely = true;
                    return false;
                }
                if (range.End < parameterValue + eps)
                    return false;
            }

            return true;
        }
 /// <summary>
 /// Collects all solids and meshes within a GeometryElement; the solids which consist of multiple closed volumes
 /// will be split into single closed volume Solids.
 /// </summary>
 /// <remarks>
 /// Added in 2013 to replace the temporary API method ExporterIFCUtils.GetSplitClippedSolidMeshGeometry.
 /// </remarks>
 /// <param name="range">
 /// The upper and lower levels which act as the clipping boundaries.
 /// </param>
 /// <param name="geomElemToUse">The GeometryElement.</param>
 /// <returns>The collection of solids and meshes.</returns>
 public static SolidMeshGeometryInfo GetSplitClippedSolidMeshGeometry(GeometryElement geomElemToUse, IFCRange range)
 {
     SolidMeshGeometryInfo geometryInfo = GetClippedSolidMeshGeometry(geomElemToUse, range);
     geometryInfo.SplitSolidsList();
     return geometryInfo;
 }
 /// <summary>
 /// Gets origin, X direction and curve bound from a curve.
 /// </summary>
 /// <param name="curve">
 /// The curve.
 /// </param>
 /// <param name="curveBounds">
 /// The output curve bounds.
 /// </param>
 /// <param name="xDirection">
 /// The output X direction.
 /// </param>
 /// <param name="origin">
 /// The output origin.
 /// </param>
 public static void GetAxisAndRangeFromCurve(Curve curve,
    out IFCRange curveBounds, out XYZ xDirection, out XYZ origin)
 {
     curveBounds = new IFCRange(curve.get_EndParameter(0), curve.get_EndParameter(1));
     origin = curve.Evaluate(curveBounds.Start, false);
     if (curve is Arc)
     {
         Arc arc = curve as Arc;
         xDirection = arc.XDirection;
     }
     else
     {
         Transform trf = curve.ComputeDerivatives(curveBounds.Start, false);
         xDirection = trf.get_Basis(0);
     }
 }
Example #11
0
        /// <summary>
        /// Split associated parts when host element is split by level.
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="hostElement">The host element havign associtaed parts.</param>
        /// <param name="associatedPartsList">The list of associtated parts.</param>
        private static void SplitParts(ExporterIFC exporterIFC, Element hostElement, List <ElementId> associatedPartsList)
        {
            string        ifcEnumType;
            IFCExportType exportType = ExporterUtil.GetExportType(exporterIFC, hostElement, out ifcEnumType);

            // Split the host to find the orphan parts.
            IList <ElementId> orphanLevels = new List <ElementId>();
            IList <ElementId> hostLevels   = new List <ElementId>();
            IList <IFCRange>  hostRanges   = new List <IFCRange>();

            LevelUtil.CreateSplitLevelRangesForElement(exporterIFC, exportType, hostElement, out hostLevels, out hostRanges);
            orphanLevels = hostLevels;

            // Split each Parts
            IList <ElementId> levels = new List <ElementId>();
            IList <IFCRange>  ranges = new List <IFCRange>();
            // Dictionary to storage the level and its parts.
            Dictionary <ElementId, List <KeyValuePair <Part, IFCRange> > > levelParts = new Dictionary <ElementId, List <KeyValuePair <Part, IFCRange> > >();

            foreach (ElementId partId in associatedPartsList)
            {
                Part part = hostElement.Document.GetElement(partId) as Part;
                LevelUtil.CreateSplitLevelRangesForElement(exporterIFC, exportType, part, out levels, out ranges);

                // if the parts are above top level, associate them with nearest bottom level.
                if (ranges.Count == 0)
                {
                    ElementId bottomLevelId = FindPartSplitLevel(exporterIFC, part);

                    if (bottomLevelId == ElementId.InvalidElementId)
                    {
                        bottomLevelId = part.LevelId;
                    }

                    if (!levelParts.ContainsKey(bottomLevelId))
                    {
                        levelParts.Add(bottomLevelId, new List <KeyValuePair <Part, IFCRange> >());
                    }

                    KeyValuePair <Part, IFCRange> splitPartRange = new KeyValuePair <Part, IFCRange>(part, null);
                    levelParts[bottomLevelId].Add(splitPartRange);

                    continue;
                }

                // The parts split by levels are stored in dictionary.
                for (int ii = 0; ii < ranges.Count; ii++)
                {
                    if (!levelParts.ContainsKey(levels[ii]))
                    {
                        levelParts.Add(levels[ii], new List <KeyValuePair <Part, IFCRange> >());
                    }

                    KeyValuePair <Part, IFCRange> splitPartRange = new KeyValuePair <Part, IFCRange>(part, ranges[ii]);
                    levelParts[levels[ii]].Add(splitPartRange);
                }

                if (levels.Count > hostLevels.Count)
                {
                    orphanLevels = orphanLevels.Union <ElementId>(levels).ToList();
                }
            }

            ExporterCacheManager.HostPartsCache.Register(hostElement.Id, levelParts);

            // The levels of orphan part.
            orphanLevels = orphanLevels.Where(number => !hostLevels.Contains(number)).ToList();
            List <KeyValuePair <ElementId, IFCRange> > levelRangePairList = new List <KeyValuePair <ElementId, IFCRange> >();

            foreach (ElementId orphanLevelId in orphanLevels)
            {
                IFCLevelInfo levelInfo = ExporterCacheManager.LevelInfoCache.GetLevelInfo(exporterIFC, orphanLevelId);
                if (levelInfo == null)
                {
                    continue;
                }
                double   levelHeight = ExporterCacheManager.LevelInfoCache.FindHeight(orphanLevelId);
                IFCRange levelRange  = new IFCRange(levelInfo.Elevation, levelInfo.Elevation + levelHeight);

                List <KeyValuePair <Part, IFCRange> > splitPartRangeList = new List <KeyValuePair <Part, IFCRange> >();
                splitPartRangeList = ExporterCacheManager.HostPartsCache.Find(hostElement.Id, orphanLevelId);
                IFCRange highestRange = levelRange;
                foreach (KeyValuePair <Part, IFCRange> partRange in splitPartRangeList)
                {
                    if (partRange.Value.End > highestRange.End)
                    {
                        highestRange = partRange.Value;
                    }
                }
                levelRangePairList.Add(new KeyValuePair <ElementId, IFCRange>(orphanLevelId, highestRange));
            }
            if (levelRangePairList.Count > 0)
            {
                ExporterCacheManager.DummyHostCache.Register(hostElement.Id, levelRangePairList);
            }
        }
Example #12
0
 /// <summary>
 /// Checks if the wall is clipped completely.
 /// </summary>
 /// <param name="exporterIFC">
 /// The ExporterIFC object.
 /// </param>
 /// <param name="wallElement">
 /// The wall element.
 /// </param>
 /// <param name="range">
 /// The range of which may clip the wall.
 /// </param>
 /// <returns>
 /// True if the wall is clipped completely, false otherwise.
 /// </returns>
 static bool IsWallCompletelyClipped(Wall wallElement, ExporterIFC exporterIFC, IFCRange range)
 {
     return ExporterIFCUtils.IsWallCompletelyClipped(wallElement, exporterIFC, range);
 }
Example #13
0
        // return null if parent should be completely clipped.
        // TODO: determine whether or not to use face boundary.
        private static IFCAnyHandle ProcessClippingFace(ExporterIFC exporterIFC, CurveLoop outerBoundary, Plane boundaryPlane,
                                                        Plane extrusionBasePlane, XYZ extrusionDirection, IFCRange range, bool useFaceBoundary, IFCAnyHandle bodyItemHnd)
        {
            if (outerBoundary == null || boundaryPlane == null)
            {
                throw new Exception("Invalid face boundary.");
            }

            double clippingSlant = boundaryPlane.Normal.DotProduct(extrusionDirection);

            if (useFaceBoundary)
            {
                if (MathUtil.IsAlmostZero(clippingSlant))
                {
                    return(bodyItemHnd);
                }
            }

            bool clipCompletely;

            if (!IsInRange(range, outerBoundary, boundaryPlane, extrusionDirection, out clipCompletely))
            {
                return(clipCompletely ? null : bodyItemHnd);
            }

            if (MathUtil.IsAlmostZero(clippingSlant))
            {
                throw new Exception("Can't create clipping perpendicular to extrusion.");
            }

            IFCFile file = exporterIFC.GetFile();

            XYZ scaledOrig = ExporterIFCUtils.TransformAndScalePoint(exporterIFC, boundaryPlane.Origin);
            XYZ scaledNorm = ExporterIFCUtils.TransformAndScaleVector(exporterIFC, boundaryPlane.Normal);
            XYZ scaledXDir = ExporterIFCUtils.TransformAndScaleVector(exporterIFC, boundaryPlane.XVec);

            IFCAnyHandle planeAxisHnd = ExporterUtil.CreateAxis(file, scaledOrig, scaledNorm, scaledXDir);
            IFCAnyHandle surfHnd      = IFCInstanceExporter.CreatePlane(file, planeAxisHnd);

            IFCAnyHandle clippedBodyItemHnd = null;
            IFCAnyHandle halfSpaceHnd       = null;

            if (useFaceBoundary)
            {
                IFCAnyHandle boundedCurveHnd;
                if (boundaryPlane != null)
                {
                    XYZ projScaledOrigin = ExporterIFCUtils.TransformAndScalePoint(exporterIFC, extrusionBasePlane.Origin);
                    XYZ projScaledX      = ExporterIFCUtils.TransformAndScaleVector(exporterIFC, extrusionBasePlane.XVec);
                    XYZ projScaledY      = ExporterIFCUtils.TransformAndScaleVector(exporterIFC, extrusionBasePlane.YVec);
                    XYZ projScaledNorm   = projScaledX.CrossProduct(projScaledY);

                    Plane projScaledPlane = new Plane(projScaledX, projScaledY, projScaledOrigin);

                    IList <UV> polylinePts = TransformAndProjectCurveLoopToPlane(exporterIFC, outerBoundary, projScaledPlane);
                    polylinePts.Add(polylinePts[0]);
                    boundedCurveHnd = ExporterUtil.CreatePolyline(file, polylinePts);

                    IFCAnyHandle boundedAxisHnd = ExporterUtil.CreateAxis(file, projScaledOrigin, projScaledNorm, projScaledX);

                    halfSpaceHnd = IFCInstanceExporter.CreatePolygonalBoundedHalfSpace(file, boundedAxisHnd, boundedCurveHnd, surfHnd, false);
                }
                else
                {
                    throw new Exception("Can't create non-polygonal face boundary.");
                }
            }
            else
            {
                halfSpaceHnd = IFCInstanceExporter.CreateHalfSpaceSolid(file, surfHnd, false);
            }

            if (halfSpaceHnd == null)
            {
                throw new Exception("Can't create clipping.");
            }

            clippedBodyItemHnd = IFCInstanceExporter.CreateBooleanClippingResult(file, IFCBooleanOperator.Difference,
                                                                                 bodyItemHnd, halfSpaceHnd);
            return(clippedBodyItemHnd);
        }
Example #14
0
        /// <summary>
        /// Adds openings to an element.
        /// </summary>
        /// <param name="exporterIFC">The exporter.</param>
        /// <param name="elementHandles">The parent handles.</param>
        /// <param name="curveLoops">The parent CurveLoops.</param>
        /// <param name="element">The element.</param>
        /// <param name="lcs">The local coordinate system.</param>
        /// <param name="scaledWidth">The width.</param>
        /// <param name="range">The range.</param>
        /// <param name="setter">The placement setter.</param>
        /// <param name="localPlacement">The local placement.</param>
        /// <param name="localWrapper">The wrapper.</param>
        public static void AddOpeningsToElement(ExporterIFC exporterIFC,
                                                IList <IFCAnyHandle> elementHandles, IList <CurveLoop> curveLoops, Element element,
                                                Transform lcs, double scaledWidth, IFCRange range, PlacementSetter setter,
                                                IFCAnyHandle localPlacement, ProductWrapper localWrapper)
        {
            if (lcs == null && ((curveLoops?.Count ?? 0) > 0))
            {
                // assumption: first curve loop defines the plane.
                Plane hostObjPlane = curveLoops[0].HasPlane() ? curveLoops[0].GetPlane(): null;

                if (hostObjPlane != null)
                {
                    lcs = GeometryUtil.CreateTransformFromPlane(hostObjPlane);
                }
            }

            IList <IFCOpeningData> openingDataList = ExporterIFCUtils.GetOpeningData(exporterIFC,
                                                                                     element, lcs, range);
            IFCFile file = exporterIFC.GetFile();

            int openingIndex = 0;

            foreach (IFCOpeningData openingData in openingDataList)
            {
                openingIndex++;

                Element openingElem = element.Document.GetElement(openingData.OpeningElementId);
                if (openingElem == null)
                {
                    openingElem = element;
                }

                bool           currentWallIsHost = false;
                FamilyInstance openingFInst      = openingElem as FamilyInstance;
                if (openingFInst != null && openingFInst.Host != null)
                {
                    if (openingFInst.Host.Id == element.Id)
                    {
                        currentWallIsHost = true;
                    }
                }

                // Don't export the opening if WallSweep category has been turned off.
                // This is currently restricted to WallSweeps because the element responsible for the opening could be a variety of things,
                // including a line as part of the elevation profile of the wall.
                // As such, we will restrict which element types we check for CanExportElement.
                if ((openingElem is WallSweep) &&
                    (!ElementFilteringUtil.CanExportElement(exporterIFC, openingElem, true)))
                {
                    continue;
                }

                IList <IFCExtrusionData> extrusionDataList = openingData.GetExtrusionData();
                IFCAnyHandle             parentHandle      = FindParentHandle(elementHandles, curveLoops, extrusionDataList);

                string            predefinedType;
                IFCExportInfoPair exportType = ExporterUtil.GetProductExportType(exporterIFC,
                                                                                 openingElem, out predefinedType);
                bool exportingDoorOrWindow = (exportType.ExportInstance == IFCEntityType.IfcDoor ||
                                              exportType.ExportType == IFCEntityType.IfcDoorType ||
                                              exportType.ExportInstance == IFCEntityType.IfcWindow ||
                                              exportType.ExportType == IFCEntityType.IfcWindowType);

                bool isDoorOrWindowOpening = IsDoorOrWindowOpening(openingElem, element,
                                                                   exportingDoorOrWindow);

                if (isDoorOrWindowOpening && currentWallIsHost)
                {
                    DoorWindowDelayedOpeningCreator delayedCreator =
                        DoorWindowDelayedOpeningCreator.Create(exporterIFC, openingData, scaledWidth,
                                                               element.Id, parentHandle, setter.LevelId);
                    if (delayedCreator != null)
                    {
                        ExporterCacheManager.DoorWindowDelayedOpeningCreatorCache.Add(delayedCreator);
                        continue;
                    }
                }

                IList <Solid> solids     = openingData.GetOpeningSolids();
                int           solidIndex = 0;
                foreach (Solid solid in solids)
                {
                    solidIndex++;

                    using (IFCExtrusionCreationData extrusionCreationData = new IFCExtrusionCreationData())
                    {
                        extrusionCreationData.SetLocalPlacement(ExporterUtil.CreateLocalPlacement(file, localPlacement, null));
                        extrusionCreationData.ReuseLocalPlacement = true;

                        string openingGUID = CreateOpeningGUID(openingElem, range, openingIndex, solidIndex);

                        CreateOpening(exporterIFC, parentHandle, element, openingElem, openingGUID, solid, scaledWidth, openingData.IsRecess, extrusionCreationData,
                                      setter, localWrapper);
                    }
                }

                foreach (IFCExtrusionData extrusionData in extrusionDataList)
                {
                    solidIndex++;

                    if (extrusionData.ScaledExtrusionLength < MathUtil.Eps())
                    {
                        extrusionData.ScaledExtrusionLength = scaledWidth;
                    }

                    string openingGUID = CreateOpeningGUID(openingElem, range, openingIndex, solidIndex);

                    CreateOpening(exporterIFC, parentHandle, localPlacement, element, openingElem,
                                  openingGUID, extrusionData, lcs, openingData.IsRecess, setter, localWrapper);
                }
            }
        }
Example #15
0
        /// <summary>
        /// Collects all solids and meshes within a GeometryElement; the solids which consist of multiple closed volumes
        /// will be split into single closed volume Solids.
        /// </summary>
        /// <remarks>
        /// Added in 2013 to replace the temporary API method ExporterIFCUtils.GetSplitClippedSolidMeshGeometry.
        /// </remarks>
        /// <param name="range">
        /// The upper and lower levels which act as the clipping boundaries.
        /// </param>
        /// <param name="geomElemToUse">The GeometryElement.</param>
        /// <returns>The collection of solids and meshes.</returns>
        public static SolidMeshGeometryInfo GetSplitClippedSolidMeshGeometry(GeometryElement geomElemToUse, IFCRange range)
        {
            SolidMeshGeometryInfo geometryInfo = GetClippedSolidMeshGeometry(geomElemToUse, range);

            geometryInfo.SplitSolidsList();
            return(geometryInfo);
        }
Example #16
0
        /// <summary>
        /// Collects all meshes within a GeometryElement and all solids clipped between a given IFCRange.
        /// </summary>
        /// <remarks>
        /// Added in 2013 to replace the temporary API method ExporterIFCUtils.GetClippedSolidMeshGeometry.
        /// </remarks>
        /// <param name="elem">
        /// The Element from which we can obtain a bounding box. Not handled directly in this method, it is used in an internal helper method.
        /// </param>
        /// <param name="geomElemToUse">
        /// The GeometryElement.
        /// </param>
        /// <param name="range">
        /// The upper and lower levels which act as the clipping boundaries.
        /// </param>
        /// <returns>The collection of solids and meshes.</returns>
        public static SolidMeshGeometryInfo GetClippedSolidMeshGeometry(GeometryElement geomElemToUse, IFCRange range)
        {
            SolidMeshGeometryInfo geometryInfo = GetSolidMeshGeometry(geomElemToUse, Transform.Identity);

            geometryInfo.ClipSolidsList(geomElemToUse, range);
            return(geometryInfo);
        }
Example #17
0
 /// <summary>
 /// Processes the geometry of the wall to create an extruded area solid representing the geometry of the wall (including
 /// any clippings imposed by neighboring elements).
 /// </summary>
 /// <param name="exporterIFC">
 /// The exporter.
 /// </param>
 /// <param name="wallElement">
 /// The wall.
 /// </param>
 /// <param name="setterOffset">
 /// The offset from the placement setter.
 /// </param>
 /// <param name="range">
 /// The range.  This consists of two double values representing the height in Z at the start and the end
 /// of the range.  If the values are identical the entire wall is used.
 /// </param>
 /// <param name="zSpan">
 /// The overall span in Z of the wall.
 /// </param>
 /// <param name="baseBodyItemHnd">
 /// The IfcExtrudedAreaSolid handle generated initially for the wall.
 /// </param>
 /// <param name="cutPairOpenings">
 /// A collection of extruded openings that can be derived from the wall geometry.
 /// </param>
 /// <returns>
 /// IfcEtxtrudedAreaSolid handle.  This may be the same handle as was input, or a modified handle derived from the clipping
 /// geometry.  If the function fails this handle will have no value.
 /// </returns>
 static IFCAnyHandle AddClippingsToBaseExtrusion(ExporterIFC exporterIFC, Wall wallElement,
    XYZ setterOffset, IFCRange range, IFCRange zSpan, IFCAnyHandle baseBodyItemHnd, out IList<IFCExtrusionData> cutPairOpenings)
 {
     return ExporterIFCUtils.AddClippingsToBaseExtrusion(exporterIFC, wallElement, setterOffset, range, zSpan, baseBodyItemHnd, out cutPairOpenings);
 }
        private static HandleAndAnalyzer CreateExtrusionWithClippingAndOpening(ExporterIFC exporterIFC, Element element,
            ElementId catId, Solid solid, Plane plane, XYZ projDir, IFCRange range, out bool completelyClipped,
            out bool hasClippingResult, out bool hasBooleanResult, out ElementId materialId)
        {
            completelyClipped = false;
            materialId = ElementId.InvalidElementId;
            hasClippingResult = false;
            hasBooleanResult = false;
            HandleAndAnalyzer nullVal = new HandleAndAnalyzer();
            HandleAndAnalyzer retVal = new HandleAndAnalyzer();

            try
            {
                ExtrusionAnalyzer elementAnalyzer = ExtrusionAnalyzer.Create(solid, plane, projDir);
                retVal.Analyzer = elementAnalyzer;

                Document document = element.Document;
                XYZ planeOrig = plane.Origin;
                XYZ baseLoopOffset = null;

                if (!MathUtil.IsAlmostZero(elementAnalyzer.StartParameter))
                    baseLoopOffset = elementAnalyzer.StartParameter * projDir;

                Face extrusionBase = elementAnalyzer.GetExtrusionBase();

                IList<GeometryUtil.FaceBoundaryType> boundaryTypes;
                IList<CurveLoop> extrusionBoundaryLoops =
                    GeometryUtil.GetFaceBoundaries(extrusionBase, baseLoopOffset, out boundaryTypes);

                // Return if we get any CurveLoops that are complex, as we don't want to export an approximation of the boundary here.
                foreach (GeometryUtil.FaceBoundaryType boundaryType in boundaryTypes)
                {
                    if (boundaryType == GeometryUtil.FaceBoundaryType.Complex)
                        return nullVal;
                }

                // Move base plane to start parameter location.
                Plane extrusionBasePlane = null;
                try
                {
                    extrusionBasePlane = extrusionBoundaryLoops[0].GetPlane();
                }
                catch
                {
                    return nullVal;
                }

                double extrusionLength = elementAnalyzer.EndParameter - elementAnalyzer.StartParameter;
                double baseOffset = extrusionBasePlane.Origin.DotProduct(projDir);
                IFCRange extrusionRange = new IFCRange(baseOffset, extrusionLength + baseOffset);

                double startParam = planeOrig.DotProduct(projDir);
                double endParam = planeOrig.DotProduct(projDir) + extrusionLength;
                if ((range != null) && (startParam >= range.End || endParam <= range.Start))
                {
                    completelyClipped = true;
                    return nullVal;
                }

                double scaledExtrusionDepth = UnitUtil.ScaleLength(extrusionLength);

                string profileName = null;
                if (element != null)
                {
                    ElementType type = element.Document.GetElement(element.GetTypeId()) as ElementType;
                    if (type != null)
                        profileName = type.Name;
                }

                // We use a sub-transaction here in case we are able to generate the base body but not the clippings.
                IFCFile file = exporterIFC.GetFile();
                IFCAnyHandle finalExtrusionBodyItemHnd = null;
                using (IFCTransaction tr = new IFCTransaction(file))
                {
                    // For creating the actual extrusion, we want to use the calculated extrusion plane, not the input plane.
                    IFCAnyHandle extrusionBodyItemHnd = ExtrusionExporter.CreateExtrudedSolidFromCurveLoop(exporterIFC, profileName,
                        extrusionBoundaryLoops, extrusionBasePlane, projDir, scaledExtrusionDepth);
                    if (!IFCAnyHandleUtil.IsNullOrHasNoValue(extrusionBodyItemHnd))
                    {
                        retVal.BaseExtrusions.Add(extrusionBodyItemHnd);

                        finalExtrusionBodyItemHnd = extrusionBodyItemHnd;
                        IDictionary<ElementId, ICollection<ICollection<Face>>> elementCutouts =
                            GeometryUtil.GetCuttingElementFaces(element, elementAnalyzer);
                        foreach (KeyValuePair<ElementId, ICollection<ICollection<Face>>> elementCutoutsForElement in elementCutouts)
                        {
                            // process clippings first, then openings
                            ICollection<ICollection<Face>> unhandledElementCutoutsForElement = new List<ICollection<Face>>();
                            Element cuttingElement = document.GetElement(elementCutoutsForElement.Key);
                            foreach (ICollection<Face> elementCutout in elementCutoutsForElement.Value)
                            {
                                ICollection<Face> skippedFaces = null;
                                bool unhandledClipping = false;
                                try
                                {
                                    // The skippedFaces may represent openings that will be dealt with below.
                                    finalExtrusionBodyItemHnd = GeometryUtil.CreateClippingFromFaces(exporterIFC, cuttingElement,
                                        extrusionBasePlane, projDir,
                                        elementCutout, extrusionRange, finalExtrusionBodyItemHnd, out skippedFaces);
                                }
                                catch
                                {
                                    skippedFaces = null;
                                    unhandledClipping = true;
                                }

                                if (finalExtrusionBodyItemHnd == null || unhandledClipping)
                                {
                                    unhandledElementCutoutsForElement.Add(elementCutout);
                                }
                                else
                                {
                                    if (finalExtrusionBodyItemHnd != extrusionBodyItemHnd)
                                        hasClippingResult = true;

                                    // Even if we created a clipping, we may have faces to further process as openings.  
                                    if (skippedFaces != null && skippedFaces.Count != 0)
                                        unhandledElementCutoutsForElement.Add(skippedFaces);
                                }
                            }

                            IFCAnyHandle finalExtrusionClippingBodyItemHnd = finalExtrusionBodyItemHnd;
                            foreach (ICollection<Face> elementCutout in unhandledElementCutoutsForElement)
                            {
                                bool unhandledOpening = false;
                                try
                                {
                                    finalExtrusionBodyItemHnd = GeometryUtil.CreateOpeningFromFaces(exporterIFC, cuttingElement,
                                        extrusionBasePlane, projDir,
                                        elementCutout, extrusionRange, finalExtrusionBodyItemHnd);
                                }
                                catch
                                {
                                    unhandledOpening = true;
                                }

                                if (finalExtrusionBodyItemHnd == null || unhandledOpening)
                                {
                                    // Item is completely clipped.  We use this only when we are certain:
                                    // 1. finalExtrusionBodyItemHnd is null.
                                    // 2. range is not null (i.e., we expect the possibility of clipping)
                                    // 3. unhandledOpening is not true (i.e., we didn't abort the operation).
                                    // If completelyClipped is true, we won't export the item, so we want to make sure
                                    // that we don't actually want to try a backup method instead.
                                    completelyClipped = (finalExtrusionBodyItemHnd == null) && (range != null) && (!unhandledOpening);
                                    tr.RollBack();
                                    return nullVal;
                                }
                                else if (finalExtrusionBodyItemHnd != finalExtrusionClippingBodyItemHnd)
                                {
                                    hasBooleanResult = true;
                                }
                            }
                        }

                        materialId = BodyExporter.GetBestMaterialIdFromGeometryOrParameter(solid, exporterIFC, element);
                        BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, document, extrusionBodyItemHnd, materialId);
                    }
                    tr.Commit();
                }

                retVal.Handle = finalExtrusionBodyItemHnd;
                return retVal;
            }
            catch
            {
                return nullVal;
            }
        }
Example #19
0
        private static IFCAnyHandle FallbackTryToCreateAsExtrusion(ExporterIFC exporterIFC, Wall wallElement, SolidMeshGeometryInfo smCapsule,
            ElementId catId, Curve curve, Plane plane, double depth, IFCRange zSpan, IFCRange range, IFCPlacementSetter setter, 
            out IList<IFCExtrusionData> cutPairOpenings, out bool isCompletelyClipped)
        {
            cutPairOpenings = new List<IFCExtrusionData>();

            IFCAnyHandle bodyRep;
            isCompletelyClipped = false;

            XYZ localOrig = plane.Origin;

            bool hasExtrusion = HasElevationProfile(wallElement);
            if (hasExtrusion)
            {
                IList<CurveLoop> loops = GetElevationProfile(wallElement);
                if (loops.Count == 0)
                    hasExtrusion = false;
                else
                {
                    IList<IList<CurveLoop>> sortedLoops = ExporterIFCUtils.SortCurveLoops(loops);
                    if (sortedLoops.Count == 0)
                        return null;

                    // Current limitation: can't handle wall split into multiple disjointed pieces.
                    int numSortedLoops = sortedLoops.Count;
                    if (numSortedLoops > 1)
                        return null;

                    bool ignoreExtrusion = true;
                    bool cantHandle = false;
                    bool hasGeometry = false;
                    for (int ii = 0; (ii < numSortedLoops) && !cantHandle; ii++)
                    {
                        int sortedLoopSize = sortedLoops[ii].Count;
                        if (sortedLoopSize == 0)
                            continue;
                        if (!ExporterIFCUtils.IsCurveLoopConvexWithOpenings(sortedLoops[ii][0], wallElement, range, out ignoreExtrusion))
                        {
                            if (ignoreExtrusion)
                            {
                                // we need more information.  Is there something to export?  If so, we'll
                                // ignore the extrusion.  Otherwise, we will fail.

                                if (smCapsule.SolidsCount() == 0 && smCapsule.MeshesCount() == 0)
                                {
                                    continue;
                                }
                            }
                            else
                            {
                                cantHandle = true;
                            }
                            hasGeometry = true;
                        }
                        else
                        {
                            hasGeometry = true;
                        }
                    }

                    if (!hasGeometry)
                    {
                        isCompletelyClipped = true;
                        return null;
                    }

                    if (cantHandle)
                        return null;
                }
            }

            if (!CanExportWallGeometryAsExtrusion(wallElement, range))
                return null;

            // extrusion direction.
            XYZ extrusionDir = GetWallHeightDirection(wallElement);

            // create extrusion boundary.
            IList<CurveLoop> boundaryLoops = new List<CurveLoop>();

            bool alwaysThickenCurve = IsWallBaseRectangular(wallElement, curve);

            if (!alwaysThickenCurve)
            {
                boundaryLoops = GetLoopsFromTopBottomFace(wallElement, exporterIFC);
                if (boundaryLoops.Count == 0)
                    return null;
            }
            else
            {
                CurveLoop newLoop = CurveLoop.CreateViaThicken(curve, wallElement.Width, XYZ.BasisZ);
                if (newLoop == null)
                    return null;

                if (!newLoop.IsCounterclockwise(XYZ.BasisZ))
                    newLoop = GeometryUtil.ReverseOrientation(newLoop);
                boundaryLoops.Add(newLoop);
            }

            // origin gets scaled later.
            XYZ setterOffset = new XYZ(0, 0, setter.Offset + (localOrig[2] - setter.BaseOffset));

            IFCAnyHandle baseBodyItemHnd = ExtrusionExporter.CreateExtrudedSolidFromCurveLoop(exporterIFC, null, boundaryLoops, plane,
                extrusionDir, depth);
            if (IFCAnyHandleUtil.IsNullOrHasNoValue(baseBodyItemHnd))
                return null;

            IFCAnyHandle bodyItemHnd = AddClippingsToBaseExtrusion(exporterIFC, wallElement,
               setterOffset, range, zSpan, baseBodyItemHnd, out cutPairOpenings);
            if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyItemHnd))
                return null;

            IFCAnyHandle styledItemHnd = BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, wallElement.Document,
                baseBodyItemHnd, ElementId.InvalidElementId);

            HashSet<IFCAnyHandle> bodyItems = new HashSet<IFCAnyHandle>();
            bodyItems.Add(bodyItemHnd);

            IFCAnyHandle contextOfItemsBody = exporterIFC.Get3DContextHandle("Body");
            if (baseBodyItemHnd.Id == bodyItemHnd.Id)
            {
                bodyRep = RepresentationUtil.CreateSweptSolidRep(exporterIFC, wallElement, catId, contextOfItemsBody, bodyItems, null);
            }
            else
            {
                bodyRep = RepresentationUtil.CreateClippingRep(exporterIFC, wallElement, catId, contextOfItemsBody, bodyItems);
            }

            return bodyRep;
        }
        /// <summary>
        /// This method takes the solidsList and clips all of its solids between the given range.
        /// </summary>
        /// <param name="elem">
        /// The Element from which we obtain our BoundingBoxXYZ.
        /// </param>
        /// <param name="geomElem">
        /// The top-level GeometryElement from which to gather X and Y coordinates for the intersecting solid.
        /// </param>
        /// <param name="range">
        /// The IFCRange whose Z values we use to create an intersecting solid to clip the solids in this class's internal solidsList.
        /// If range boundaries are equal, method returns, performing no clippings.
        /// </param>
        public void ClipSolidsList(GeometryElement geomElem, IFCRange range)
        {
            if (geomElem == null)
            {
                throw new ArgumentNullException("geomElemToUse");
            }
            if (MathUtil.IsAlmostEqual(range.Start, range.End) || solidsList.Count == 0)
            {
                return;
            }

            double bottomZ;
            double boundDifference;
            if (range.Start < range.End)
            {
                bottomZ = range.Start;
                boundDifference = range.End - range.Start;
            }
            else
            {
                bottomZ = range.End;
                boundDifference = range.Start - range.End;
            }

            // create a new solid using the X and Y of the bounding box on the top level GeometryElement and the Z of the IFCRange
            BoundingBoxXYZ elemBoundingBox = geomElem.GetBoundingBox();
            XYZ pointA = new XYZ(elemBoundingBox.Min.X, elemBoundingBox.Min.Y, bottomZ);
            XYZ pointB = new XYZ(elemBoundingBox.Max.X, elemBoundingBox.Min.Y, bottomZ);
            XYZ pointC = new XYZ(elemBoundingBox.Max.X, elemBoundingBox.Max.Y, bottomZ);
            XYZ pointD = new XYZ(elemBoundingBox.Min.X, elemBoundingBox.Max.Y, bottomZ);

            List<Curve> perimeter = new List<Curve>();
            perimeter.Add(Line.CreateBound(pointA, pointB));
            perimeter.Add(Line.CreateBound(pointB, pointC));
            perimeter.Add(Line.CreateBound(pointC, pointD));
            perimeter.Add(Line.CreateBound(pointD, pointA));

            List<CurveLoop> boxPerimeterList = new List<CurveLoop>();
            boxPerimeterList.Add(CurveLoop.Create(perimeter));
            Solid intersectionSolid = GeometryCreationUtilities.CreateExtrusionGeometry(boxPerimeterList, XYZ.BasisZ, boundDifference);

            // cycle through the elements in solidsList and intersect them against intersectionSolid to create a new list
            List<Solid> clippedSolidsList = new List<Solid>();
            Solid currSolid;
            foreach (Solid solid in solidsList)
            {
                try
                {
                    // ExecuteBooleanOperation can throw if it fails.  In this case, just ignore the clipping.
                    currSolid = BooleanOperationsUtils.ExecuteBooleanOperation(solid, intersectionSolid, BooleanOperationsType.Intersect);
                    if (currSolid != null && currSolid.Volume != 0)
                    {
                        clippedSolidsList.Add(currSolid);
                    }
                }
                catch
                {
                }
            }
            solidsList = clippedSolidsList;
        }
Example #21
0
        /// <summary>
        /// This method takes the solidsList and clips all of its solids between the given range.
        /// </summary>
        /// <param name="elem">
        /// The Element from which we obtain our BoundingBoxXYZ.
        /// </param>
        /// <param name="geomElem">
        /// The top-level GeometryElement from which to gather X and Y coordinates for the intersecting solid.
        /// </param>
        /// <param name="range">
        /// The IFCRange whose Z values we use to create an intersecting solid to clip the solids in this class's internal solidsList.
        /// If range boundaries are equal, method returns, performing no clippings.
        /// </param>
        public void ClipSolidsList(GeometryElement geomElem, IFCRange range)
        {
            if (geomElem == null)
            {
                throw new ArgumentNullException("geomElemToUse");
            }
            if (MathUtil.IsAlmostEqual(range.Start, range.End) || solidsList.Count == 0)
            {
                return;
            }

            double bottomZ;
            double boundDifference;

            if (range.Start < range.End)
            {
                bottomZ         = range.Start;
                boundDifference = range.End - range.Start;
            }
            else
            {
                bottomZ         = range.End;
                boundDifference = range.Start - range.End;
            }

            // create a new solid using the X and Y of the bounding box on the top level GeometryElement and the Z of the IFCRange
            BoundingBoxXYZ elemBoundingBox = geomElem.GetBoundingBox();
            XYZ            pointA          = new XYZ(elemBoundingBox.Min.X, elemBoundingBox.Min.Y, bottomZ);
            XYZ            pointB          = new XYZ(elemBoundingBox.Max.X, elemBoundingBox.Min.Y, bottomZ);
            XYZ            pointC          = new XYZ(elemBoundingBox.Max.X, elemBoundingBox.Max.Y, bottomZ);
            XYZ            pointD          = new XYZ(elemBoundingBox.Min.X, elemBoundingBox.Max.Y, bottomZ);

            List <Curve> perimeter = new List <Curve>();

            perimeter.Add(Line.CreateBound(pointA, pointB));
            perimeter.Add(Line.CreateBound(pointB, pointC));
            perimeter.Add(Line.CreateBound(pointC, pointD));
            perimeter.Add(Line.CreateBound(pointD, pointA));

            List <CurveLoop> boxPerimeterList = new List <CurveLoop>();

            boxPerimeterList.Add(CurveLoop.Create(perimeter));
            Solid intersectionSolid = GeometryCreationUtilities.CreateExtrusionGeometry(boxPerimeterList, XYZ.BasisZ, boundDifference);

            // cycle through the elements in solidsList and intersect them against intersectionSolid to create a new list
            List <Solid> clippedSolidsList = new List <Solid>();
            Solid        currSolid;

            foreach (Solid solid in solidsList)
            {
                try
                {
                    // ExecuteBooleanOperation can throw if it fails.  In this case, just ignore the clipping.
                    currSolid = BooleanOperationsUtils.ExecuteBooleanOperation(solid, intersectionSolid, BooleanOperationsType.Intersect);
                    if (currSolid != null && currSolid.Volume != 0)
                    {
                        clippedSolidsList.Add(currSolid);
                    }
                }
                catch
                {
                }
            }
            solidsList = clippedSolidsList;
        }
        /// <summary>
        /// Attempts to create a clipping, recess, or opening from a collection of faces.
        /// </summary>
        /// <param name="exporterIFC">The exporter.</param>
        /// <param name="cuttingElement">The cutting element.  This will help determine whether to use a clipping or opening in boundary cases.</param>
        /// <param name="extrusionBasePlane">The plane of the extrusion base.</param>
        /// <param name="extrusionDirection">The extrusion direction.</param>
        /// <param name="faces">The collection of faces.</param>
        /// <param name="range">The valid range of the extrusion.</param>
        /// <param name="origBodyRepHnd">The original body representation.</param>
        /// <returns>The new body representation.  If the clipping completely clips the extrusion, this will be null.  Otherwise, this
        /// will be the clipped representation if a clipping was done, or the original representation if not.</returns>
        public static IFCAnyHandle CreateClippingFromFaces(ExporterIFC exporterIFC, Element cuttingElement, Plane extrusionBasePlane,
            XYZ extrusionDirection, ICollection<Face> faces, IFCRange range, IFCAnyHandle origBodyRepHnd)
        {
            if (IFCAnyHandleUtil.IsNullOrHasNoValue(origBodyRepHnd))
                return null;

            bool polygonalOnly = ExporterCacheManager.ExportOptionsCache.ExportAs2x2;

            IList<CurveLoop> outerCurveLoops = new List<CurveLoop>();
            IList<Plane> outerCurveLoopPlanes = new List<Plane>();
            IList<bool> boundaryIsPolygonal = new List<bool>();

            bool allPlanes = true;
            UV faceOriginUV = new UV(0, 0);
            foreach (Face face in faces)
            {
                FaceBoundaryType faceBoundaryType;
                CurveLoop curveLoop = GetOuterFaceBoundary(face, null, polygonalOnly, out faceBoundaryType);
                outerCurveLoops.Add(curveLoop);
                boundaryIsPolygonal.Add(faceBoundaryType == FaceBoundaryType.Polygonal);

                if (face is PlanarFace)
                {
                    PlanarFace planarFace = face as PlanarFace;
                    XYZ faceOrigin = planarFace.Origin;
                    XYZ faceNormal = planarFace.ComputeNormal(faceOriginUV);

                    Plane plane = new Plane(faceNormal, faceOrigin);
                    outerCurveLoopPlanes.Add(plane);

                    if (!curveLoop.IsCounterclockwise(faceNormal))
                        curveLoop.Flip();
                }
                else
                {
                    outerCurveLoopPlanes.Add(null);
                    allPlanes = false;
                }
            }

            if (allPlanes)
            {
                int numFaces = faces.Count;
                    
                // Special case: one face is a clip plane.
                if (numFaces == 1)
                {
                    return ProcessClippingFace(exporterIFC, outerCurveLoops[0], outerCurveLoopPlanes[0], extrusionBasePlane,
                        extrusionDirection, range, false, origBodyRepHnd);
                }

                KeyValuePair<bool, bool> clipsExtrusionEnds = CollectionClipsExtrusionEnds(outerCurveLoops, extrusionDirection, range);
                if (clipsExtrusionEnds.Key == true || clipsExtrusionEnds.Value == true)
                {
                    // Don't clip for a door, window or opening.
                    if (CreateOpeningForCategory(cuttingElement))
                        throw new Exception("Unhandled opening.");

                    ICollection<int> facesToSkip = new HashSet<int>();
                    bool clipStart = (clipsExtrusionEnds.Key == true);
                    bool clipBoth = (clipsExtrusionEnds.Key == true && clipsExtrusionEnds.Value == true);
                    if (!clipBoth)
                    {
                        for (int ii = 0; ii < numFaces; ii++)
                        {
                            double slant = outerCurveLoopPlanes[ii].Normal.DotProduct(extrusionDirection);
                            if (!MathUtil.IsAlmostZero(slant))
                            {
                                if (clipStart && (slant > 0.0))
                                    throw new Exception("Unhandled clip plane direction.");
                                if (!clipStart && (slant < 0.0))
                                    throw new Exception("Unhandled clip plane direction.");
                            }
                            else
                            {
                                facesToSkip.Add(ii);
                            }
                        }
                    }
                    else       
                    {
                        // If we are clipping both the start and end of the extrusion, we have to make sure all of the clipping
                        // planes have the same a non-negative dot product relative to one another.
                        int clipOrientation = 0;
                        for (int ii = 0; ii < numFaces; ii++)
                        {
                            double slant = outerCurveLoopPlanes[ii].Normal.DotProduct(extrusionDirection);
                            if (!MathUtil.IsAlmostZero(slant))
                            {
                                if (slant > 0.0)
                                {
                                    if (clipOrientation < 0)
                                        throw new Exception("Unhandled clipping orientations.");
                                    clipOrientation = 1;
                                }
                                else
                                {
                                    if (clipOrientation > 0)
                                        throw new Exception("Unhandled clipping orientations.");
                                    clipOrientation = -1;
                                }
                            }
                            else
                            {
                                facesToSkip.Add(ii);
                            }
                        }
                    }

                    IFCAnyHandle newBodyRepHnd = origBodyRepHnd;
                    for (int ii = 0; ii < numFaces; ii++)
                    {
                        if (facesToSkip.Contains(ii))
                            continue;

                        newBodyRepHnd = ProcessClippingFace(exporterIFC, outerCurveLoops[ii], outerCurveLoopPlanes[ii], 
                            extrusionBasePlane, extrusionDirection, range, true, newBodyRepHnd);
                        if (newBodyRepHnd == null)
                            return null;
                    }
                    return newBodyRepHnd;
                }
            }

            //not handled
            throw new Exception("Unhandled clipping.");
        }
 /// <summary>
 /// Creates an extrusion with potential clipping from a list of solids corresponding to an element.
 /// </summary>
 /// <param name="exporterIFC">The ExporterIFC class.</param>
 /// <param name="element">The element.</param>
 /// <param name="catId">The category of the element and/or the solid geometry.</param>
 /// <param name="solids">The list of solid geometries.</param>
 /// <param name="plane">The extrusion base plane.</param>
 /// <param name="projDir">The projection direction.</param>
 /// <param name="range">The upper and lower limits of the extrusion, in the projection direction.</param>
 /// <param name="completelyClipped">Returns true if the extrusion is completely outside the range.</param>
 /// <param name="materialIds">The material ids of the solid geometry.</param>
 /// <returns>The extrusion handle.</returns>
 public static IFCAnyHandle CreateExtrusionWithClipping(ExporterIFC exporterIFC, Element element, ElementId catId,
     IList<Solid> solids, Plane plane, XYZ projDir, IFCRange range, out bool completelyClipped, out HashSet<ElementId> materialIds)
 {
     HandleAndAnalyzer handleAndAnalyzer = CreateExtrusionWithClippingBase(exporterIFC, element, catId,
         solids, plane, projDir, range, out completelyClipped, out materialIds);
     return handleAndAnalyzer.Handle;
 }
Example #24
0
        /// <summary>
        /// Attempts to create a clipping, recess, or opening from a collection of faces.
        /// </summary>
        /// <param name="exporterIFC">The exporter.</param>
        /// <param name="cuttingElement">The cutting element.  This will help determine whether to use a clipping or opening in boundary cases.</param>
        /// <param name="extrusionBasePlane">The plane of the extrusion base.</param>
        /// <param name="extrusionDirection">The extrusion direction.</param>
        /// <param name="faces">The collection of faces.</param>
        /// <param name="range">The valid range of the extrusion.</param>
        /// <param name="origBodyRepHnd">The original body representation.</param>
        /// <returns>The new body representation.  If the clipping completely clips the extrusion, this will be null.  Otherwise, this
        /// will be the clipped representation if a clipping was done, or the original representation if not.</returns>
        public static IFCAnyHandle ProcessFaceCollection(ExporterIFC exporterIFC, Element cuttingElement, Plane extrusionBasePlane,
                                                         XYZ extrusionDirection, ICollection <Face> faces, IFCRange range, IFCAnyHandle origBodyRepHnd)
        {
            if (IFCAnyHandleUtil.IsNullOrHasNoValue(origBodyRepHnd))
            {
                return(null);
            }

            bool polygonalOnly = ExporterCacheManager.ExportOptionsCache.ExportAs2x2;

            IList <CurveLoop> outerCurveLoops      = new List <CurveLoop>();
            IList <Plane>     outerCurveLoopPlanes = new List <Plane>();
            IList <bool>      boundaryIsPolygonal  = new List <bool>();

            bool allPlanes    = true;
            UV   faceOriginUV = new UV(0, 0);

            foreach (Face face in faces)
            {
                FaceBoundaryType faceBoundaryType;
                CurveLoop        curveLoop = GetOuterFaceBoundary(face, null, polygonalOnly, out faceBoundaryType);
                outerCurveLoops.Add(curveLoop);
                boundaryIsPolygonal.Add(faceBoundaryType == FaceBoundaryType.Polygonal);

                if (face is PlanarFace)
                {
                    PlanarFace planarFace = face as PlanarFace;
                    XYZ        faceOrigin = planarFace.Origin;
                    XYZ        faceNormal = planarFace.ComputeNormal(faceOriginUV);

                    Plane plane = new Plane(faceNormal, faceOrigin);
                    outerCurveLoopPlanes.Add(plane);

                    if (!curveLoop.IsCounterclockwise(faceNormal))
                    {
                        curveLoop.Flip();
                    }
                }
                else
                {
                    outerCurveLoopPlanes.Add(null);
                    allPlanes = false;
                }
            }

            if (allPlanes)
            {
                int numFaces = faces.Count;

                // Special case: one face is a clip plane.
                if (numFaces == 1)
                {
                    return(ProcessClippingFace(exporterIFC, outerCurveLoops[0], outerCurveLoopPlanes[0], extrusionBasePlane,
                                               extrusionDirection, range, false, origBodyRepHnd));
                }

                KeyValuePair <bool, bool> clipsExtrusionEnds = CollectionClipsExtrusionEnds(outerCurveLoops, extrusionDirection, range);
                if (clipsExtrusionEnds.Key == true || clipsExtrusionEnds.Value == true)
                {
                    // Don't clip for a door, window or opening.
                    if (CreateOpeningForCategory(cuttingElement))
                    {
                        throw new Exception("Unhandled opening.");
                    }

                    ICollection <int> facesToSkip = new HashSet <int>();
                    bool clipStart = (clipsExtrusionEnds.Key == true);
                    bool clipBoth  = (clipsExtrusionEnds.Key == true && clipsExtrusionEnds.Value == true);
                    if (!clipBoth)
                    {
                        for (int ii = 0; ii < numFaces; ii++)
                        {
                            double slant = outerCurveLoopPlanes[ii].Normal.DotProduct(extrusionDirection);
                            if (!MathUtil.IsAlmostZero(slant))
                            {
                                if (clipStart && (slant > 0.0))
                                {
                                    throw new Exception("Unhandled clip plane direction.");
                                }
                                if (!clipStart && (slant < 0.0))
                                {
                                    throw new Exception("Unhandled clip plane direction.");
                                }
                            }
                            else
                            {
                                facesToSkip.Add(ii);
                            }
                        }
                    }
                    else
                    {
                        // If we are clipping both the start and end of the extrusion, we have to make sure all of the clipping
                        // planes have the same a non-negative dot product relative to one another.
                        int clipOrientation = 0;
                        for (int ii = 0; ii < numFaces; ii++)
                        {
                            double slant = outerCurveLoopPlanes[ii].Normal.DotProduct(extrusionDirection);
                            if (!MathUtil.IsAlmostZero(slant))
                            {
                                if (slant > 0.0)
                                {
                                    if (clipOrientation < 0)
                                    {
                                        throw new Exception("Unhandled clipping orientations.");
                                    }
                                    clipOrientation = 1;
                                }
                                else
                                {
                                    if (clipOrientation > 0)
                                    {
                                        throw new Exception("Unhandled clipping orientations.");
                                    }
                                    clipOrientation = -1;
                                }
                            }
                            else
                            {
                                facesToSkip.Add(ii);
                            }
                        }
                    }

                    IFCAnyHandle newBodyRepHnd = origBodyRepHnd;
                    for (int ii = 0; ii < numFaces; ii++)
                    {
                        if (facesToSkip.Contains(ii))
                        {
                            continue;
                        }

                        newBodyRepHnd = ProcessClippingFace(exporterIFC, outerCurveLoops[ii], outerCurveLoopPlanes[ii],
                                                            extrusionBasePlane, extrusionDirection, range, true, newBodyRepHnd);
                        if (newBodyRepHnd == null)
                        {
                            return(null);
                        }
                    }
                    return(newBodyRepHnd);
                }
            }

            bool unhandledCases = true;

            if (unhandledCases)
            {
                throw new Exception("Unhandled opening or clipping.");
            }

            // We will attempt to "sew" the faces, and see what we have left over.  Depending on what we have, we have an opening, recess, or clipping.
            IList <Edge> boundaryEdges = new List <Edge>();

            foreach (Face face in faces)
            {
                EdgeArrayArray faceBoundaries = face.EdgeLoops;
                // We only know how to deal with the outer loop; we'll throw if we have multiple boundaries.
                if (faceBoundaries.Size != 1)
                {
                    throw new Exception("Can't process faces with inner boundaries.");
                }

                EdgeArray faceBoundary = faceBoundaries.get_Item(0);
                foreach (Edge edge in faceBoundary)
                {
                    if (edge.get_Face(0) == null || edge.get_Face(1) == null)
                    {
                        boundaryEdges.Add(edge);
                    }
                }
            }

            return(origBodyRepHnd);
        }
        /// <summary>
        /// Creates an extrusion with potential clipping from a solid corresponding to an element, and supplies ExtrusionCreationData for the result.
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC class.</param>
        /// <param name="element">The element.</param>
        /// <param name="catId">The category of the element and/or the solid geometry.</param>
        /// <param name="solid">The solid geometry.</param>
        /// <param name="plane">The extrusion base plane.</param>
        /// <param name="projDir">The projection direction.</param>
        /// <param name="range">The upper and lower limits of the extrusion, in the projection direction.</param>
        /// <param name="completelyClipped">Returns true if the extrusion is completely outside the range.</param>
        /// <returns>The extrusion handle.</returns>
        public static HandleAndData CreateExtrusionWithClippingAndProperties(ExporterIFC exporterIFC,
            Element element, ElementId catId, Solid solid, Plane plane, XYZ projDir, IFCRange range, out bool completelyClipped)
        {
            IList<Solid> solids = new List<Solid>();
            solids.Add(solid);

            HashSet<ElementId> materialIds = null;
            HandleAndAnalyzer handleAndAnalyzer = CreateExtrusionWithClippingBase(exporterIFC, element, catId,
                solids, plane, projDir, range, out completelyClipped, out materialIds);

            HandleAndData ret = new HandleAndData();
            ret.Handle = handleAndAnalyzer.Handle;
            ret.BaseExtrusions = handleAndAnalyzer.BaseExtrusions;
            ret.ShapeRepresentationType = handleAndAnalyzer.ShapeRepresentationType;
            ret.MaterialIds = materialIds;
            if (handleAndAnalyzer.Analyzer != null)
                ret.Data = GetExtrusionCreationDataFromAnalyzer(exporterIFC, projDir, handleAndAnalyzer.Analyzer);

            return ret;
        }
Example #26
0
        /// <summary>
        /// Export the individual part (IfcBuildingElementPart).
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="partElement">The part element to export.</param>
        /// <param name="geometryElement">The geometry of part.</param>
        /// <param name="productWrapper">The IFCProductWrapper object.</param>
        public static void ExportPart(ExporterIFC exporterIFC, Element partElement, IFCProductWrapper productWrapper,
            IFCPlacementSetter placementSetter, IFCAnyHandle originalPlacement, IFCRange range, IFCExtrusionAxes ifcExtrusionAxes,
            Element hostElement, ElementId overrideLevelId, bool asBuildingElement)
        {
            if (!ElementFilteringUtil.IsElementVisible(ExporterCacheManager.ExportOptionsCache.FilterViewForExport, partElement))
                return;

            Part part = partElement as Part;
            if (part == null)
                return;

            IFCPlacementSetter standalonePlacementSetter = null;
            bool standaloneExport = hostElement == null && !asBuildingElement;

            ElementId partExportLevel = null;
            if (standaloneExport || asBuildingElement)
            {
                if (partElement.Level != null)
                    partExportLevel = partElement.Level.Id;
            }
            else
            {
                if (part.OriginalCategoryId != hostElement.Category.Id)
                    return;
                partExportLevel = hostElement.Level.Id;
            }
            if (overrideLevelId != null)
                partExportLevel = overrideLevelId;

            if (ExporterCacheManager.PartExportedCache.HasExported(partElement.Id, partExportLevel))
                return;

            Options options = GeometryUtil.GetIFCExportGeometryOptions();
            View ownerView = partElement.Document.GetElement(partElement.OwnerViewId) as View;
            if (ownerView != null)
                options.View = ownerView;

            GeometryElement geometryElement = partElement.get_Geometry(options);
            if (geometryElement == null)
                return;

            try
            {
                IFCFile file = exporterIFC.GetFile();
                using (IFCTransaction transaction = new IFCTransaction(file))
                {
                    IFCAnyHandle partPlacement = null;
                    if (standaloneExport || asBuildingElement)
                    {
                        Transform orientationTrf = Transform.Identity;
                        standalonePlacementSetter = IFCPlacementSetter.Create(exporterIFC, partElement, null, orientationTrf, partExportLevel);
                        partPlacement = standalonePlacementSetter.GetPlacement();
                    }
                    else
                        partPlacement = ExporterUtil.CopyLocalPlacement(file, originalPlacement);

                    bool validRange = (range != null && !MathUtil.IsAlmostZero(range.Start - range.End));

                    SolidMeshGeometryInfo solidMeshInfo;
                    if (validRange)
                    {
                        solidMeshInfo = GeometryUtil.GetClippedSolidMeshGeometry(geometryElement, range);
                        if (solidMeshInfo.GetSolids().Count == 0 && solidMeshInfo.GetMeshes().Count == 0)
                            return;
                    }
                    else
                    {
                        solidMeshInfo = GeometryUtil.GetSolidMeshGeometry(geometryElement, Transform.Identity);
                    }

                    using (IFCExtrusionCreationData extrusionCreationData = new IFCExtrusionCreationData())
                    {
                        extrusionCreationData.SetLocalPlacement(partPlacement);
                        extrusionCreationData.ReuseLocalPlacement = false;
                        extrusionCreationData.PossibleExtrusionAxes = ifcExtrusionAxes;

                        IList<Solid> solids = solidMeshInfo.GetSolids();
                        IList<Mesh> meshes = solidMeshInfo.GetMeshes();

                        ElementId catId = CategoryUtil.GetSafeCategoryId(partElement);

                        BodyData bodyData = null;
                        BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true);
                        if (solids.Count > 0 || meshes.Count > 0)
                        {
                            bodyData = BodyExporter.ExportBody(partElement.Document.Application, exporterIFC, partElement, catId, solids, meshes,
                                bodyExporterOptions, extrusionCreationData);
                        }
                        else
                        {
                            IList<GeometryObject> geomlist = new List<GeometryObject>();
                            geomlist.Add(geometryElement);
                            bodyData = BodyExporter.ExportBody(partElement.Document.Application, exporterIFC, partElement, catId, geomlist,
                                bodyExporterOptions, extrusionCreationData);
                        }

                        IFCAnyHandle bodyRep = bodyData.RepresentationHnd;
                        if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep))
                        {
                            extrusionCreationData.ClearOpenings();
                            return;
                        }

                        IList<IFCAnyHandle> representations = new List<IFCAnyHandle>();
                        representations.Add(bodyRep);

                        IFCAnyHandle prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations);

                        IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle();

                        string partGUID = ExporterIFCUtils.CreateGUID(partElement);
                        string origPartName = NamingUtil.CreateIFCName(exporterIFC, -1);
                        string partName = NamingUtil.GetNameOverride(partElement, origPartName);
                        string partDescription = NamingUtil.GetDescriptionOverride(partElement, null);
                        string partObjectType = NamingUtil.GetObjectTypeOverride(partElement, NamingUtil.CreateIFCObjectName(exporterIFC, partElement));
                        string partElemId = NamingUtil.CreateIFCElementId(partElement);

                        IFCAnyHandle ifcPart = null;
                        if (!asBuildingElement)
                        {
                            ifcPart = IFCInstanceExporter.CreateBuildingElementPart(file, partGUID, ownerHistory, partName, partDescription, 
                                partObjectType, extrusionCreationData.GetLocalPlacement(), prodRep, partElemId);
                        }
                        else
                        {
                            string ifcEnumType;
                            IFCExportType exportType = ExporterUtil.GetExportType(exporterIFC, hostElement, out ifcEnumType);
                            switch (exportType)
                            {
                                case IFCExportType.ExportColumnType:
                                    ifcPart = IFCInstanceExporter.CreateColumn(file, partGUID, ownerHistory, partName, partDescription, partObjectType, 
                                        extrusionCreationData.GetLocalPlacement(), prodRep, partElemId);
                                    break;
                                case IFCExportType.ExportCovering:
                                    IFCCoveringType coveringType = CeilingExporter.GetIFCCoveringType(hostElement, ifcEnumType);
                                    ifcPart = IFCInstanceExporter.CreateCovering(file, partGUID, ownerHistory, partName, partDescription, partObjectType, 
                                        extrusionCreationData.GetLocalPlacement(), prodRep, partElemId, coveringType);
                                    break;
                                case IFCExportType.ExportFooting:
                                    IFCFootingType footingType = FootingExporter.GetIFCFootingType(hostElement, ifcEnumType);
                                    ifcPart = IFCInstanceExporter.CreateFooting(file, partGUID, ownerHistory, partName, partDescription, partObjectType, 
                                        extrusionCreationData.GetLocalPlacement(), prodRep, partElemId, footingType);
                                    break;
                                case IFCExportType.ExportRoof:
                                    IFCRoofType roofType = RoofExporter.GetIFCRoofType(ifcEnumType);
                                    ifcPart = IFCInstanceExporter.CreateRoof(file, partGUID, ownerHistory, partName, partDescription, partObjectType, 
                                        extrusionCreationData.GetLocalPlacement(), prodRep, partElemId, roofType);
                                    break;
                                case IFCExportType.ExportSlab:
                                    IFCSlabType slabType = FloorExporter.GetIFCSlabType(ifcEnumType);
                                    ifcPart = IFCInstanceExporter.CreateSlab(file, partGUID, ownerHistory, partName, partDescription, partObjectType, 
                                        extrusionCreationData.GetLocalPlacement(), prodRep, partElemId, slabType);
                                    break;
                                case IFCExportType.ExportWall:
                                    ifcPart = IFCInstanceExporter.CreateWallStandardCase(file, partGUID, ownerHistory, partName, partDescription, 
                                        partObjectType, extrusionCreationData.GetLocalPlacement(), prodRep, partElemId);
                                    break;
                                default:
                                    ifcPart = IFCInstanceExporter.CreateBuildingElementProxy(file, partGUID, ownerHistory, partName, partDescription, 
                                        partObjectType, extrusionCreationData.GetLocalPlacement(), prodRep, partElemId, IFCElementComposition.Element);
                                    break;
                            }
                        }

                        productWrapper.AddElement(ifcPart, standaloneExport || asBuildingElement ? standalonePlacementSetter : placementSetter, extrusionCreationData, standaloneExport || asBuildingElement);

                        //Add the exported part to exported cache.
                        TraceExportedParts(partElement, partExportLevel, standaloneExport || asBuildingElement ? ElementId.InvalidElementId : hostElement.Id);

                        CategoryUtil.CreateMaterialAssociations(partElement.Document, exporterIFC, ifcPart, bodyData.MaterialIds);

                        transaction.Commit();
                    }
                }
            }
            finally
            {
                if (standalonePlacementSetter != null)
                    standalonePlacementSetter.Dispose();
            }
        }
        public static IFCAnyHandle CreateOpeningFromFaces(ExporterIFC exporterIFC, Element cuttingElement, Plane extrusionBasePlane,
            XYZ extrusionDirection, ICollection<Face> faces, IFCRange range, IFCAnyHandle origBodyRepHnd)
        {
            // We will attempt to "sew" the faces, and see what we have left over.  Depending on what we have, we have an opening, recess, or clipping.

            // top and bottom profile curves to create extrusion
            IDictionary<Face, IList<Curve>> boundaryCurves = new Dictionary<Face, IList<Curve>>();
            // curves on same side face to check if they are valid for extrusion
            IDictionary<Face, IList<Curve>> boundaryCurvesInSameExistingFace = new Dictionary<Face, IList<Curve>>();

            foreach (Face face in faces)
            {
                EdgeArrayArray faceBoundaries = face.EdgeLoops;
                // We only know how to deal with the outer loop; we'll throw if we have multiple boundaries.
                if (faceBoundaries.Size != 1)
                    throw new Exception("Can't process faces with inner boundaries.");

                EdgeArray faceBoundary = faceBoundaries.get_Item(0);
                foreach (Edge edge in faceBoundary)
                {
                    Face face1 = edge.get_Face(0);
                    Face face2 = edge.get_Face(1);
                    Face missingFace = null;
                    Face existingFace = null;
                    if (!faces.Contains(face1))
                    {
                        missingFace = face1;
                        existingFace = face2;
                    }
                    else if (!faces.Contains(face2))
                    {
                        missingFace = face2;
                        existingFace = face1;
                    }

                    if (missingFace != null)
                    {
                        Curve curve = edge.AsCurve();
                        if (!boundaryCurves.ContainsKey(missingFace))
                            boundaryCurves[missingFace] = new List<Curve>();
                        boundaryCurves[missingFace].Add(curve);
                        if (!boundaryCurvesInSameExistingFace.ContainsKey(existingFace))
                            boundaryCurvesInSameExistingFace[existingFace] = new List<Curve>();
                        boundaryCurvesInSameExistingFace[existingFace].Add(curve);
                    }
                }
            }

            //might be recess
            if (boundaryCurves.Count == 1)
            {
                // boundaryCurves contains one curve loop of top profile of an extrusion
                // try to find bottom profile
                IList<Curve> curves1 = boundaryCurves.Values.ElementAt(0);
                CurveLoop curveloop = CurveLoop.Create(curves1);

                // find the parallel face
                XYZ normal = curveloop.GetPlane().Normal;

                PlanarFace recessFace = null;
                foreach (Face face in faces)
                {
                    PlanarFace planarFace = face as PlanarFace;
                    if (planarFace != null && MathUtil.VectorsAreParallel(planarFace.Normal, normal))
                    {
                        if (recessFace == null)
                            recessFace = planarFace;
                        else
                            throw new Exception("Can't handle.");
                    }
                }

                if (recessFace != null)
                {
                    EdgeArrayArray edgeLoops = recessFace.EdgeLoops;
                    if (edgeLoops.Size != 1)
                        throw new Exception("Can't handle.");

                    EdgeArray edges = edgeLoops.get_Item(0);

                    IList<Edge> recessFaceEdges = new List<Edge>();
                    foreach (Edge edge in edges)
                    {
                        Face sideFace = edge.get_Face(0);
                        if (sideFace == recessFace)
                            sideFace = edge.get_Face(1);

                        // there should be already one exist during above processing
                        if (!boundaryCurvesInSameExistingFace.ContainsKey(sideFace))
                            throw new Exception("Can't handle.");
                        boundaryCurvesInSameExistingFace[sideFace].Add(edge.AsCurve());
                    }
                }
            }
            else if (boundaryCurves.Count == 2)
            {
                // might be an internal opening, process them later
                // do nothing now
            }
            else if (boundaryCurves.Count == 3) //might be an opening on an edge
            {
                IList<Curve> curves1 = boundaryCurves.Values.ElementAt(0);
                IList<Curve> curves2 = boundaryCurves.Values.ElementAt(1);
                IList<Curve> curves3 = boundaryCurves.Values.ElementAt(2);

                IList<Curve> firstValidCurves = null;
                IList<Curve> secondValidCurves = null;

                PlanarFace face1 = boundaryCurves.Keys.ElementAt(0) as PlanarFace;
                PlanarFace face2 = boundaryCurves.Keys.ElementAt(1) as PlanarFace;
                PlanarFace face3 = boundaryCurves.Keys.ElementAt(2) as PlanarFace;

                if (face1 == null || face2 == null || face3 == null)
                {
                    //Error
                    throw new Exception("Can't handle.");
                }

                Face removedFace = null;

                // find two parallel faces
                if (MathUtil.VectorsAreParallel(face1.Normal, face2.Normal))
                {
                    firstValidCurves = curves1;
                    secondValidCurves = curves2;
                    removedFace = face3;
                }
                else if (MathUtil.VectorsAreParallel(face1.Normal, face3.Normal))
                {
                    firstValidCurves = curves1;
                    secondValidCurves = curves3;
                    removedFace = face2;
                }
                else if (MathUtil.VectorsAreParallel(face2.Normal, face3.Normal))
                {
                    firstValidCurves = curves2;
                    secondValidCurves = curves3;
                    removedFace = face1;
                }

                // remove the third one and its edge curves
                if (removedFace != null)
                {
                    foreach (Curve curve in boundaryCurves[removedFace])
                    {
                        foreach (KeyValuePair<Face, IList<Curve>> faceEdgePair in boundaryCurvesInSameExistingFace)
                        {
                            if (faceEdgePair.Value.Contains(curve))
                                boundaryCurvesInSameExistingFace[faceEdgePair.Key].Remove(curve);
                        }
                    }
                    boundaryCurves.Remove(removedFace);
                }

                // sew, “closing” them with a simple line
                IList<IList<Curve>> curvesCollection = new List<IList<Curve>>();
                curvesCollection.Add(firstValidCurves);
                curvesCollection.Add(secondValidCurves);

                foreach (IList<Curve> curves in curvesCollection)
                {
                    if (curves.Count < 2) //not valid
                        throw new Exception("Can't handle.");

                    XYZ end0 = curves[0].get_EndPoint(0);
                    XYZ end1 = curves[0].get_EndPoint(1);

                    IList<Curve> processedCurves = new List<Curve>();
                    processedCurves.Add(curves[0]);
                    curves.Remove(curves[0]);

                    Curve nextCurve = null;
                    Curve preCurve = null;

                    // find the end points on the edges not connected
                    while (curves.Count > 0)
                    {
                        foreach (Curve curve in curves)
                        {
                            XYZ curveEnd0 = curve.get_EndPoint(0);
                            XYZ curveEnd1 = curve.get_EndPoint(1);
                            if (end1.IsAlmostEqualTo(curveEnd0))
                            {
                                nextCurve = curve;
                                end1 = curveEnd1;
                                break;
                            }
                            else if (end0.IsAlmostEqualTo(curveEnd1))
                            {
                                preCurve = curve;
                                end0 = curveEnd0;
                                break;
                            }
                        }

                        if (nextCurve != null)
                        {
                            processedCurves.Add(nextCurve);
                            curves.Remove(nextCurve);
                            nextCurve = null;
                        }
                        else if (preCurve != null)
                        {
                            processedCurves.Insert(0, preCurve);
                            curves.Remove(preCurve);
                            preCurve = null;
                        }
                        else
                            throw new Exception("Can't process edges.");
                    }

                    // connect them with a simple line
                    Curve newCurve = Line.get_Bound(end1, end0);
                    processedCurves.Add(newCurve);
                    if (!boundaryCurvesInSameExistingFace.ContainsKey(removedFace))
                        boundaryCurvesInSameExistingFace[removedFace] = new List<Curve>();
                    boundaryCurvesInSameExistingFace[removedFace].Add(newCurve);
                    foreach (Curve curve in processedCurves)
                    {
                        curves.Add(curve);
                    }
                }
            }
            else
                throw new Exception("Can't handle.");

            // now we should have 2 boundary curve loops
            IList<Curve> firstCurves = boundaryCurves.Values.ElementAt(0);
            IList<Curve> secondCurves = boundaryCurves.Values.ElementAt(1);
            PlanarFace firstFace = boundaryCurves.Keys.ElementAt(0) as PlanarFace;
            PlanarFace secondFace = boundaryCurves.Keys.ElementAt(1) as PlanarFace;

            if (firstFace == null || secondFace == null)
            {
                //Error, can't handle this
                throw new Exception("Can't handle.");
            }

            if (firstCurves.Count != secondCurves.Count)
            {
                //Error, can't handle this
                throw new Exception("Can't handle.");
            }

            CurveLoop curveLoop1 = null;
            CurveLoop curveLoop2 = null;

            SortCurves(firstCurves);
            curveLoop1 = CurveLoop.Create(firstCurves);
            SortCurves(secondCurves);
            curveLoop2 = CurveLoop.Create(secondCurves);

            if (curveLoop1.IsOpen() || curveLoop2.IsOpen() || !curveLoop1.HasPlane() || !curveLoop2.HasPlane())
            {
                //Error, can't handle this
                throw new Exception("Can't handle.");
            }

            Plane plane1 = curveLoop1.GetPlane();
            Plane plane2 = curveLoop2.GetPlane();

            if (!curveLoop1.IsCounterclockwise(plane1.Normal))
            {
                curveLoop1.Flip();
            }

            if (!curveLoop2.IsCounterclockwise(plane2.Normal))
            {
                curveLoop2.Flip();
            }

            // check planar and parallel and orthogonal to the main extrusion dir

            if (!MathUtil.VectorsAreParallel(plane1.Normal, plane2.Normal))
            {
                //Error, can't handle this
                throw new Exception("Can't handle.");
            }

            if (!MathUtil.VectorsAreOrthogonal(plane1.Normal, extrusionDirection)
                || !MathUtil.VectorsAreOrthogonal(plane2.Normal, extrusionDirection))
            {
                //Error, can't handle this
                throw new Exception("Can't handle.");
            }

            //get the distance
            XYZ origDistance = plane1.Origin - plane2.Origin;
            double planesDistance = Math.Abs(origDistance.DotProduct(plane1.Normal));

            // check the curves on top and bottom profiles are “identical”
            foreach (KeyValuePair<Face, IList<Curve>> faceEdgeCurvePair in boundaryCurvesInSameExistingFace)
            {
                IList<Curve> curves = faceEdgeCurvePair.Value;
                if (curves.Count != 2)
                {
                    //Error, can't handle this
                    throw new Exception("Can't handle.");
                }

                Curve edgeCurve1 = curves[0];
                Curve edgeCurve2 = curves[1];
                Face sideFace = faceEdgeCurvePair.Key;

                if (!MathUtil.IsAlmostEqual(edgeCurve1.get_EndPoint(0).DistanceTo(edgeCurve2.get_EndPoint(1)), planesDistance)
                  || !MathUtil.IsAlmostEqual(edgeCurve1.get_EndPoint(1).DistanceTo(edgeCurve2.get_EndPoint(0)), planesDistance))
                {
                    //Error, can't handle this
                    throw new Exception("Can't handle.");
                }

                if (edgeCurve1 is Line)
                {
                    if (!(edgeCurve2 is Line) || !(sideFace is PlanarFace))
                    {
                        //Error, can't handle this
                        throw new Exception("Can't handle.");
                    }
                }
                else if (edgeCurve1 is Arc)
                {
                    if (!(edgeCurve2 is Arc) || !(sideFace is CylindricalFace))
                    {
                        //Error, can't handle this
                        throw new Exception("Can't handle.");
                    }

                    Arc arc1 = edgeCurve1 as Arc;
                    Arc arc2 = edgeCurve2 as Arc;

                    if (!MathUtil.IsAlmostEqual(arc1.Center.DistanceTo(arc2.Center), planesDistance))
                    {
                        //Error, can't handle this
                        throw new Exception("Can't handle.");
                    }

                    XYZ sideFaceAxis = (sideFace as CylindricalFace).Axis;
                    if (!MathUtil.VectorsAreOrthogonal(sideFaceAxis, extrusionDirection))
                    {
                        throw new Exception("Can't handle.");
                    }
                }
                else if (edgeCurve1 is Ellipse)
                {
                    if (!(edgeCurve2 is Ellipse) || !(sideFace is RuledFace))
                    {
                        //Error, can't handle this
                        throw new Exception("Can't handle.");
                    }

                    Ellipse ellipse1 = edgeCurve1 as Ellipse;
                    Ellipse ellipse2 = edgeCurve2 as Ellipse;

                    if (!MathUtil.IsAlmostEqual(ellipse1.Center.DistanceTo(ellipse2.Center), planesDistance)
                        || !MathUtil.IsAlmostEqual(ellipse1.RadiusX, ellipse2.RadiusX) || !MathUtil.IsAlmostEqual(ellipse1.RadiusY, ellipse2.RadiusY))
                    {
                        //Error, can't handle this
                        throw new Exception("Can't handle.");
                    }
                }
                else if (edgeCurve1 is HermiteSpline)
                {
                    if (!(edgeCurve2 is HermiteSpline) || !(sideFace is RuledFace))
                    {
                        //Error, can't handle this
                        throw new Exception("Can't handle.");
                    }

                    HermiteSpline hermiteSpline1 = edgeCurve1 as HermiteSpline;
                    HermiteSpline hermiteSpline2 = edgeCurve2 as HermiteSpline;

                    IList<XYZ> controlPoints1 = hermiteSpline1.ControlPoints;
                    IList<XYZ> controlPoints2 = hermiteSpline2.ControlPoints;

                    int controlPointCount = controlPoints1.Count;
                    if (controlPointCount != controlPoints2.Count)
                    {
                        //Error, can't handle this
                        throw new Exception("Can't handle.");
                    }

                    for (int i = 0; i < controlPointCount; i++)
                    {
                        if (!MathUtil.IsAlmostEqual(controlPoints1[i].DistanceTo(controlPoints2[controlPointCount - i - 1]), planesDistance))
                        {
                            //Error, can't handle this
                            throw new Exception("Can't handle.");
                        }
                    }

                    DoubleArray parameters1 = hermiteSpline1.Parameters;
                    DoubleArray parameters2 = hermiteSpline1.Parameters;

                    int parametersCount = parameters1.Size;
                    if (parametersCount != parameters2.Size)
                    {
                        //Error, can't handle this
                        throw new Exception("Can't handle.");
                    }

                    for (int i = 0; i < parametersCount; i++)
                    {
                        if (!MathUtil.IsAlmostEqual(parameters1.get_Item(i), parameters2.get_Item(i)))
                        {
                            //Error, can't handle this
                            throw new Exception("Can't handle.");
                        }
                    }
                }
                else if (edgeCurve1 is NurbSpline)
                {
                    if (!(edgeCurve2 is NurbSpline) || !(sideFace is RuledFace))
                    {
                        //Error, can't handle this
                        throw new Exception("Can't handle.");
                    }

                    NurbSpline nurbSpline1 = edgeCurve1 as NurbSpline;
                    NurbSpline nurbSpline2 = edgeCurve2 as NurbSpline;

                    IList<XYZ> controlPoints1 = nurbSpline1.CtrlPoints;
                    IList<XYZ> controlPoints2 = nurbSpline2.CtrlPoints;

                    int controlPointCount = controlPoints1.Count;
                    if (controlPointCount != controlPoints2.Count)
                    {
                        //Error, can't handle this
                        throw new Exception("Can't handle.");
                    }

                    for (int i = 0; i < controlPointCount; i++)
                    {
                        if (!MathUtil.IsAlmostEqual(controlPoints1[i].DistanceTo(controlPoints2[controlPointCount - i - 1]), planesDistance))
                        {
                            //Error, can't handle this
                            throw new Exception("Can't handle.");
                        }
                    }

                    DoubleArray weights1 = nurbSpline1.Weights;
                    DoubleArray weights2 = nurbSpline2.Weights;

                    int weightsCount = weights1.Size;
                    if (weightsCount != weights2.Size)
                    {
                        //Error, can't handle this
                        throw new Exception("Can't handle.");
                    }

                    for (int i = 0; i < weightsCount; i++)
                    {
                        if (!MathUtil.IsAlmostEqual(weights1.get_Item(i), weights2.get_Item(i)))
                        {
                            //Error, can't handle this
                            throw new Exception("Can't handle.");
                        }
                    }

                    DoubleArray knots1 = nurbSpline1.Knots;
                    DoubleArray knots2 = nurbSpline2.Knots;

                    int knotsCount = knots1.Size;
                    if (knotsCount != knots2.Size)
                    {
                        //Error, can't handle this
                        throw new Exception("Can't handle.");
                    }

                    for (int i = 0; i < knotsCount; i++)
                    {
                        if (!MathUtil.IsAlmostEqual(knots1.get_Item(i), knots2.get_Item(i)))
                        {
                            //Error, can't handle this
                            throw new Exception("Can't handle.");
                        }
                    }
                }
                else
                {
                    //Error, can't handle this
                    throw new Exception("Can't handle.");
                }
            }

            XYZ extDir = plane2.Origin - plane1.Origin;
            XYZ plane1Normal = plane1.Normal;
            int vecParallel = MathUtil.VectorsAreParallel2(extDir, plane1Normal);
            if (vecParallel == 1)
            {
                extDir = plane1Normal;
            }
            else if (vecParallel == -1)
            {
                extDir = -plane1Normal;
            }
            else
                throw new Exception("Can't handle.");

            IList<CurveLoop> origCurveLoops = new List<CurveLoop>();
            origCurveLoops.Add(curveLoop1);
            IFCAnyHandle extrusionHandle = ExtrusionExporter.CreateExtrudedSolidFromCurveLoop(exporterIFC, null, origCurveLoops, plane1, extDir, planesDistance * exporterIFC.LinearScale);

            IFCAnyHandle booleanBodyItemHnd = IFCInstanceExporter.CreateBooleanResult(exporterIFC.GetFile(), IFCBooleanOperator.Difference,
                origBodyRepHnd, extrusionHandle);

            return booleanBodyItemHnd;
        }
Example #28
0
        /// <summary>
        /// Split associated parts when host element is split by level.
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="hostElement">The host element havign associtaed parts.</param>
        /// <param name="associatedPartsList">The list of associtated parts.</param>
        private static void SplitParts(ExporterIFC exporterIFC, Element hostElement, List<ElementId> associatedPartsList)
        {
            string ifcEnumType;
            IFCExportType exportType = ExporterUtil.GetExportType(exporterIFC, hostElement, out ifcEnumType);

            // Split the host to find the orphan parts.
            IList<ElementId> orphanLevels = new List<ElementId>();
            IList<ElementId> hostLevels = new List<ElementId>();
            IList<IFCRange> hostRanges = new List<IFCRange>();
            LevelUtil.CreateSplitLevelRangesForElement(exporterIFC, exportType, hostElement, out hostLevels, out hostRanges);
            orphanLevels = hostLevels;

            // Split each Parts
            IList<ElementId> levels = new List<ElementId>();
            IList<IFCRange> ranges = new List<IFCRange>();
            // Dictionary to storage the level and its parts.
            Dictionary<ElementId, List<KeyValuePair<Part, IFCRange>>> levelParts = new Dictionary<ElementId, List<KeyValuePair<Part, IFCRange>>>();

            foreach (ElementId partId in associatedPartsList)
            {
                Part part = hostElement.Document.GetElement(partId) as Part;
                LevelUtil.CreateSplitLevelRangesForElement(exporterIFC, exportType, part, out levels, out ranges);

                // if the parts are above top level, associate them with nearest bottom level.
                if (ranges.Count == 0)
                {
                    ElementId bottomLevelId = FindPartSplitLevel(exporterIFC, part);

                    if (bottomLevelId == ElementId.InvalidElementId && part.Level != null)
                        bottomLevelId = part.Level.Id;

                    if (!levelParts.ContainsKey(bottomLevelId))
                        levelParts.Add(bottomLevelId, new List<KeyValuePair<Part, IFCRange>>());

                    KeyValuePair<Part, IFCRange> splitPartRange = new KeyValuePair<Part, IFCRange>(part, null);
                    levelParts[bottomLevelId].Add(splitPartRange);

                    continue;
                }

                // The parts split by levels are stored in dictionary.
                for (int ii = 0; ii < ranges.Count; ii++)
                {
                    if (!levelParts.ContainsKey(levels[ii]))
                        levelParts.Add(levels[ii], new List<KeyValuePair<Part, IFCRange>>());

                    KeyValuePair<Part, IFCRange> splitPartRange = new KeyValuePair<Part, IFCRange>(part, ranges[ii]);
                    levelParts[levels[ii]].Add(splitPartRange);
                }
             
                if (levels.Count > hostLevels.Count)
                {
                    orphanLevels = orphanLevels.Union<ElementId>(levels).ToList();
                }
            }      

            ExporterCacheManager.HostPartsCache.Register(hostElement.Id, levelParts);

            // The levels of orphan part.
            orphanLevels = orphanLevels.Where(number => !hostLevels.Contains(number)).ToList();
            List<KeyValuePair<ElementId, IFCRange>> levelRangePairList = new List<KeyValuePair<ElementId, IFCRange>>();
            foreach (ElementId orphanLevelId in orphanLevels)
            {
                IFCLevelInfo levelInfo = ExporterCacheManager.LevelInfoCache.GetLevelInfo(exporterIFC, orphanLevelId);
                if (levelInfo == null)
                    continue;
                double levelHeight = ExporterCacheManager.LevelInfoCache.FindHeight(orphanLevelId);
                IFCRange levelRange = new IFCRange(levelInfo.Elevation, levelInfo.Elevation + levelHeight);

                List<KeyValuePair<Part, IFCRange>> splitPartRangeList = new List<KeyValuePair<Part, IFCRange>>();
                splitPartRangeList = ExporterCacheManager.HostPartsCache.Find(hostElement.Id, orphanLevelId);
                IFCRange highestRange = levelRange;
                foreach (KeyValuePair<Part, IFCRange> partRange in splitPartRangeList)
                {
                    if (partRange.Value.End > highestRange.End)
                    {
                        highestRange = partRange.Value;
                    }
                }
                levelRangePairList.Add(new KeyValuePair<ElementId, IFCRange>(orphanLevelId, highestRange));
            }
            if (levelRangePairList.Count > 0)
            {
                ExporterCacheManager.DummyHostCache.Register(hostElement.Id, levelRangePairList);
            }
        }
 /// <summary>
 /// Collects all meshes within a GeometryElement and all solids clipped between a given IFCRange.
 /// </summary>
 /// <remarks>
 /// Added in 2013 to replace the temporary API method ExporterIFCUtils.GetClippedSolidMeshGeometry.
 /// </remarks>
 /// <param name="elem">
 /// The Element from which we can obtain a bounding box. Not handled directly in this method, it is used in an internal helper method.
 /// </param>
 /// <param name="geomElemToUse">
 /// The GeometryElement.
 /// </param>
 /// <param name="range">
 /// The upper and lower levels which act as the clipping boundaries.
 /// </param>
 /// <returns>The collection of solids and meshes.</returns>
 public static SolidMeshGeometryInfo GetClippedSolidMeshGeometry(GeometryElement geomElemToUse, IFCRange range)
 {
     SolidMeshGeometryInfo geometryInfo = GetSolidMeshGeometry(geomElemToUse, Transform.Identity);
     geometryInfo.ClipSolidsList(geomElemToUse, range);
     return geometryInfo;
 }
Example #30
0
        /// <summary>
        /// Gets the best material id for the geometry.
        /// </summary>
        /// <param name="geometryElement">The geometry object to get the best material id.</param>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="range">The range to get the clipped geometry.</param>
        /// <returns>The material id.</returns>
        public static ElementId GetBestMaterialIdForGeometry(GeometryElement geometryElement,
           ExporterIFC exporterIFC, IFCRange range)
        {
            SolidMeshGeometryInfo solidMeshCapsule = null;

            if (range == null)
            {
                solidMeshCapsule = GeometryUtil.GetSolidMeshGeometry(geometryElement, Transform.Identity);
            }
            else
            {
                solidMeshCapsule = GeometryUtil.GetClippedSolidMeshGeometry(geometryElement, range);
            }

            IList<Solid> solids = solidMeshCapsule.GetSolids();
            IList<Mesh> polyMeshes = solidMeshCapsule.GetMeshes();

            ElementId id = GetBestMaterialIdForGeometry(solids, polyMeshes);

            return id;
        }
 private static IFCRange GetExtrusionRangeOfCurveLoop(CurveLoop loop, XYZ extrusionDirection)
 {
     IFCRange range = new IFCRange();
     bool init = false;
     foreach (Curve curve in loop)
     {
         if (!init)
         {
             if (curve.IsBound)
             {
                 IList<XYZ> coords = curve.Tessellate();
                 foreach (XYZ coord in coords)
                 {
                     double val = coord.DotProduct(extrusionDirection);
                     if (!init)
                     {
                         range.Start = val;
                         range.End = val;
                         init = true;
                     }
                     else
                     {
                         range.Start = Math.Min(range.Start, val);
                         range.End = Math.Max(range.End, val);
                     }
                 }
             }
             else
             {
                 double val = curve.get_EndPoint(0).DotProduct(extrusionDirection);
                 range.Start = val;
                 range.End = val;
                 init = true;
             }
         }
         else
         {
             double val = curve.get_EndPoint(0).DotProduct(extrusionDirection);
             range.Start = Math.Min(range.Start, val);
             range.End = Math.Max(range.End, val);
         }
     }
     return range;
 }
Example #32
0
        /// <summary>
        /// Creates a list of ranges to split an element.
        /// </summary>
        /// <remarks>
        /// We may need to split an element (e.g. column) into parts by level.
        /// </remarks>
        /// <param name="exporterIFC">
        /// The ExporterIFC object.
        /// </param>
        /// <param name="exportType">
        /// The export type.
        /// </param>
        /// <param name="element">
        /// The element.
        /// </param>
        /// <param name="levels">
        /// The levels to split the element.
        /// </param>
        /// <param name="ranges">
        /// The ranges to split the element.
        /// </param>
        public static void CreateSplitLevelRangesForElement(ExporterIFC exporterIFC, IFCExportType exportType, Element element,
                                                            out IList <ElementId> levels, out IList <IFCRange> ranges)
        {
            levels = new List <ElementId>();
            ranges = new List <IFCRange>();
            double extension = GetLevelExtension();

            if ((exportType == IFCExportType.ExportColumnType || exportType == IFCExportType.ExportWall) && (ExporterCacheManager.ExportOptionsCache.WallAndColumnSplitting))
            {
                BoundingBoxXYZ boundingBox = element.get_BoundingBox(null);
                {
                    IFCRange zSpan = new IFCRange(boundingBox.Min.Z, boundingBox.Max.Z);
                    if (zSpan.Start < zSpan.End)
                    {
                        bool      firstLevel      = true;
                        ElementId skipToNextLevel = ElementId.InvalidElementId;

                        // If the base level of the element is set, we will start "looking" at that level.  Anything below the base level will be included with the base level.
                        // We will only do this if the base level is a building story.
                        ElementId firstLevelId    = GetBaseLevelIdForElement(element);
                        bool      foundFirstLevel = (firstLevelId == ElementId.InvalidElementId);

                        List <ElementId> levelIds = ExporterCacheManager.LevelInfoCache.LevelsByElevation;
                        foreach (ElementId levelId in levelIds)
                        {
                            if (!foundFirstLevel)
                            {
                                if (levelId != firstLevelId)
                                {
                                    continue;
                                }
                                else
                                {
                                    foundFirstLevel = true;
                                }
                            }

                            if (skipToNextLevel != ElementId.InvalidElementId && levelId != skipToNextLevel)
                            {
                                continue;
                            }

                            IFCLevelInfo levelInfo = ExporterCacheManager.LevelInfoCache.GetLevelInfo(exporterIFC, levelId);
                            if (levelInfo == null)
                            {
                                continue;
                            }

                            // endBelowLevel
                            if (zSpan.End < levelInfo.Elevation + extension)
                            {
                                continue;
                            }

                            // To calculate the distance to the next level, we check to see if the Level UpToLevel built-in parameter
                            // is set.  If so, we calculate the distance by getting the elevation of the UpToLevel level minus the
                            // current elevation, and use it if it is greater than 0.  If it is not greater than 0, or the built-in
                            // parameter is not set, we use DistanceToNextLevel.
                            double levelHeight = ExporterCacheManager.LevelInfoCache.FindHeight(levelId);
                            if (levelHeight < 0.0)
                            {
                                levelHeight = calculateDistanceToNextLevel(element.Document, levelId, levelInfo);
                            }
                            skipToNextLevel = ExporterCacheManager.LevelInfoCache.FindNextLevel(levelId);

                            // startAboveLevel
                            if ((!MathUtil.IsAlmostZero(levelHeight)) &&
                                (zSpan.Start > levelInfo.Elevation + levelHeight - extension))
                            {
                                continue;
                            }

                            bool startBelowLevel = !firstLevel && (zSpan.Start < levelInfo.Elevation - extension);
                            bool endAboveLevel   = ((!MathUtil.IsAlmostZero(levelHeight)) &&
                                                    (zSpan.End > levelInfo.Elevation + levelHeight + extension));
                            if (!startBelowLevel && !endAboveLevel)
                            {
                                break;
                            }

                            IFCRange currentSpan = new IFCRange(
                                startBelowLevel ? levelInfo.Elevation : zSpan.Start,
                                endAboveLevel ? (levelInfo.Elevation + levelHeight) : zSpan.End);
                            ranges.Add(currentSpan);
                            levels.Add(levelId);

                            firstLevel = false;
                        }
                    }
                }
            }
        }
        // return null if parent should be completely clipped.
        // TODO: determine whether or not to use face boundary.
        private static IFCAnyHandle ProcessClippingFace(ExporterIFC exporterIFC, CurveLoop outerBoundary, Plane boundaryPlane, 
            Plane extrusionBasePlane, XYZ extrusionDirection, IFCRange range, bool useFaceBoundary, IFCAnyHandle bodyItemHnd)
        {
            if (outerBoundary == null || boundaryPlane == null)
                throw new Exception("Invalid face boundary.");

            double clippingSlant = boundaryPlane.Normal.DotProduct(extrusionDirection);
            if (useFaceBoundary)
            {
                if (MathUtil.IsAlmostZero(clippingSlant))
                    return bodyItemHnd;
            }

            bool clipCompletely;
            if (!IsInRange(range, outerBoundary, boundaryPlane, extrusionDirection, out clipCompletely))
                return clipCompletely ? null : bodyItemHnd;

            if (MathUtil.IsAlmostZero(clippingSlant))
                throw new Exception("Can't create clipping perpendicular to extrusion.");

            IFCFile file = exporterIFC.GetFile();

            XYZ scaledOrig = ExporterIFCUtils.TransformAndScalePoint(exporterIFC, boundaryPlane.Origin);
            XYZ scaledNorm = ExporterIFCUtils.TransformAndScaleVector(exporterIFC, boundaryPlane.Normal);
            XYZ scaledXDir = ExporterIFCUtils.TransformAndScaleVector(exporterIFC, boundaryPlane.XVec);

            IFCAnyHandle planeAxisHnd = ExporterUtil.CreateAxis(file, scaledOrig, scaledNorm, scaledXDir);
            IFCAnyHandle surfHnd = IFCInstanceExporter.CreatePlane(file, planeAxisHnd);

            IFCAnyHandle clippedBodyItemHnd = null;
            IFCAnyHandle halfSpaceHnd = null;

            if (useFaceBoundary)
            {
                IFCAnyHandle boundedCurveHnd;
                if (boundaryPlane != null)
                {
                    XYZ projScaledOrigin = ExporterIFCUtils.TransformAndScalePoint(exporterIFC, extrusionBasePlane.Origin);
                    XYZ projScaledX = ExporterIFCUtils.TransformAndScaleVector(exporterIFC, extrusionBasePlane.XVec);
                    XYZ projScaledY= ExporterIFCUtils.TransformAndScaleVector(exporterIFC, extrusionBasePlane.YVec);
                    XYZ projScaledNorm = projScaledX.CrossProduct(projScaledY);
                    
                    Plane projScaledPlane = new Plane(projScaledX, projScaledY, projScaledOrigin);

                    IList<UV> polylinePts = TransformAndProjectCurveLoopToPlane(exporterIFC, outerBoundary, projScaledPlane);
                    polylinePts.Add(polylinePts[0]);
                    boundedCurveHnd = ExporterUtil.CreatePolyline(file, polylinePts);

                    IFCAnyHandle boundedAxisHnd = ExporterUtil.CreateAxis(file, projScaledOrigin, projScaledNorm, projScaledX);

                    halfSpaceHnd = IFCInstanceExporter.CreatePolygonalBoundedHalfSpace(file, boundedAxisHnd, boundedCurveHnd, surfHnd, false);
                }
                else
                {
                    throw new Exception("Can't create non-polygonal face boundary.");
                }
            }
            else
            {
                halfSpaceHnd = IFCInstanceExporter.CreateHalfSpaceSolid(file, surfHnd, false);
            }

            if (halfSpaceHnd == null)
                throw new Exception("Can't create clipping.");

            clippedBodyItemHnd = IFCInstanceExporter.CreateBooleanClippingResult(file, IFCBooleanOperator.Difference,
                bodyItemHnd, halfSpaceHnd);
            return clippedBodyItemHnd;
        }
        /// <summary>
        /// Export the dummy wall to host an orphan part. It usually happens in the cases of associated parts are higher than split sub-wall.
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="element">The wall element.</param>
        /// <param name="geometryElement">The geometry of wall.</param>
        /// <param name="origWrapper">The ProductWrapper.</param>
        /// <param name="overrideLevelId">The ElementId that will crate the dummy wall.</param>
        /// <param name="range">The IFCRange corresponding to the dummy wall.</param>
        /// <returns>The handle of dummy wall.</returns>
        public static IFCAnyHandle ExportDummyWall(ExporterIFC exporterIFC, Element element, GeometryElement geometryElement,
           ProductWrapper origWrapper, ElementId overrideLevelId, IFCRange range)
        {
            using (ProductWrapper localWrapper = ProductWrapper.Create(origWrapper))
            {
                ElementId catId = CategoryUtil.GetSafeCategoryId(element);

                Wall wallElement = element as Wall;
                if (wallElement == null)
                    return null;

                if (wallElement != null && IsWallCompletelyClipped(wallElement, exporterIFC, range))
                    return null;

                // get global values.
                Document doc = element.Document;
                
                IFCFile file = exporterIFC.GetFile();
                IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle();

                bool validRange = (range != null && !MathUtil.IsAlmostZero(range.Start - range.End));

                bool exportParts = PartExporter.CanExportParts(wallElement);
                if (exportParts && !PartExporter.CanExportElementInPartExport(wallElement, validRange ? overrideLevelId : wallElement.LevelId, validRange))
                    return null;

                string objectType = NamingUtil.CreateIFCObjectName(exporterIFC, element);
                IFCAnyHandle wallHnd = null;

                string elemGUID = null;
                int subElementIndex = ExporterStateManager.GetCurrentRangeIndex();
                if (subElementIndex == 0)
                    elemGUID = GUIDUtil.CreateGUID(element);
                else if (subElementIndex <= ExporterStateManager.RangeIndexSetter.GetMaxStableGUIDs())
                    elemGUID = GUIDUtil.CreateSubElementGUID(element, subElementIndex + (int)IFCGenericSubElements.SplitInstanceStart - 1);
                else
                    elemGUID = GUIDUtil.CreateGUID();

                string elemName = NamingUtil.GetNameOverride(element, NamingUtil.GetIFCName(element));
                string elemDesc = NamingUtil.GetDescriptionOverride(element, null);
                string elemObjectType = NamingUtil.GetObjectTypeOverride(element, objectType);
                string elemTag = NamingUtil.GetTagOverride(element, NamingUtil.CreateIFCElementId(element));

                Transform orientationTrf = Transform.Identity;

                using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, element, null, orientationTrf, overrideLevelId))
                {
                    IFCAnyHandle localPlacement = setter.LocalPlacement;
                    wallHnd = IFCInstanceExporter.CreateWall(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                        localPlacement, null, elemTag, "NOTDEFINED");

                    if (exportParts)
                        PartExporter.ExportHostPart(exporterIFC, element, wallHnd, localWrapper, setter, localPlacement, overrideLevelId);

                    IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData();
                    extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ;   // only allow vertical extrusions!
                    extraParams.AreInnerRegionsOpenings = true;
                    localWrapper.AddElement(element, wallHnd, setter, extraParams, true);

                    ElementId wallLevelId = (validRange) ? setter.LevelId : ElementId.InvalidElementId;
                    SpaceBoundingElementUtil.RegisterSpaceBoundingElementHandle(exporterIFC, wallHnd, element.Id, wallLevelId);
                }

                return wallHnd;
            }
        }
Example #35
0
        /// <summary>
        /// Creates a list of ranges to split an element.
        /// </summary>
        /// <remarks>
        /// We may need to split an element (e.g. column) into parts by level.
        /// </remarks>
        /// <param name="exporterIFC">The ExporterIFC object. </param>
        /// <param name="exportType">The export type. </param>
        /// <param name="element">The element. </param>
        /// <param name="levels">The levels to split the element.</param>
        /// <param name="ranges">The ranges to split the element. These will be non-overlapping.</param>
        public static void CreateSplitLevelRangesForElement(ExporterIFC exporterIFC, IFCExportType exportType, Element element,
                                                            out IList <ElementId> levels, out IList <IFCRange> ranges)
        {
            levels = new List <ElementId>();
            ranges = new List <IFCRange>();

            if (!ExporterCacheManager.ExportOptionsCache.WallAndColumnSplitting)
            {
                return;
            }

            double extension = GetLevelExtension();

            bool splitByLevel = (exportType == IFCExportType.IfcColumnType || exportType == IFCExportType.IfcWall) || (exportType == IFCExportType.IfcDuctSegmentType);

            if (!splitByLevel)
            {
                return;
            }

            BoundingBoxXYZ boundingBox = element.get_BoundingBox(null);

            if (boundingBox == null)
            {
                return;
            }

            {
                IFCRange zSpan = new IFCRange(boundingBox.Min.Z, boundingBox.Max.Z);
                if (zSpan.Start < zSpan.End)
                {
                    bool      firstLevel      = true;
                    ElementId skipToNextLevel = ElementId.InvalidElementId;

                    // If the base level of the element is set, we will start "looking" at that level.  Anything below the base level will be included with the base level.
                    // We will only do this if the base level is a building story.
                    ElementId firstLevelId    = GetBaseLevelIdForElement(element);
                    bool      foundFirstLevel = (firstLevelId == ElementId.InvalidElementId);

                    IList <ElementId> levelIds = ExporterCacheManager.LevelInfoCache.BuildingStoreysByElevation;
                    foreach (ElementId levelId in levelIds)
                    {
                        if (!foundFirstLevel)
                        {
                            if (levelId != firstLevelId)
                            {
                                continue;
                            }
                            else
                            {
                                foundFirstLevel = true;
                            }
                        }

                        if (skipToNextLevel != ElementId.InvalidElementId && levelId != skipToNextLevel)
                        {
                            continue;
                        }

                        IFCLevelInfo levelInfo = ExporterCacheManager.LevelInfoCache.GetLevelInfo(exporterIFC, levelId);
                        if (levelInfo == null)
                        {
                            continue;
                        }

                        // endBelowLevel
                        if (zSpan.End < levelInfo.Elevation + extension)
                        {
                            continue;
                        }

                        // To calculate the distance to the next level, we check to see if the Level UpToLevel built-in parameter
                        // is set.  If so, we calculate the distance by getting the elevation of the UpToLevel level minus the
                        // current elevation, and use it if it is greater than 0.  If it is not greater than 0, or the built-in
                        // parameter is not set, we use DistanceToNextLevel.
                        double levelHeight = ExporterCacheManager.LevelInfoCache.FindHeight(levelId);
                        if (levelHeight < 0.0)
                        {
                            levelHeight = CalculateDistanceToNextLevel(element.Document, levelId, levelInfo);
                        }
                        skipToNextLevel = ExporterCacheManager.LevelInfoCache.FindNextLevel(levelId);

                        // startAboveLevel
                        if ((!MathUtil.IsAlmostZero(levelHeight)) &&
                            (zSpan.Start > levelInfo.Elevation + levelHeight - extension))
                        {
                            continue;
                        }

                        bool startBelowLevel = !firstLevel && (zSpan.Start < levelInfo.Elevation - extension);
                        bool endAboveLevel   = ((!MathUtil.IsAlmostZero(levelHeight)) &&
                                                (zSpan.End > levelInfo.Elevation + levelHeight + extension));
                        if (!startBelowLevel && !endAboveLevel)
                        {
                            break;
                        }

                        IFCRange currentSpan = new IFCRange(
                            startBelowLevel ? levelInfo.Elevation : zSpan.Start,
                            endAboveLevel ? (levelInfo.Elevation + levelHeight) : zSpan.End);

                        // We want our ranges to be non-overlapping.  As such, we'll modify the start parameter
                        // to be at least as large as the previous end parameter (if any).  If this makes the
                        // range invalid, we won't add it.
                        if (ranges.Count > 0)
                        {
                            IFCRange lastSpan = ranges.Last();
                            if (lastSpan.End > currentSpan.End - MathUtil.Eps())
                            {
                                continue;
                            }

                            currentSpan.Start = Math.Max(currentSpan.Start, lastSpan.End);
                        }

                        ranges.Add(currentSpan);
                        levels.Add(levelId);

                        firstLevel = false;
                    }
                }
            }
        }
        private static bool WallHasGeometryToExport(Wall wallElement,
            IList<Solid> solids,
            IList<Mesh> meshes,
            IFCRange range,
            out bool isCompletelyClipped)
        {
            isCompletelyClipped = false;
            
            bool hasExtrusion = HasElevationProfile(wallElement);
            if (hasExtrusion)
            {
                IList<CurveLoop> loops = GetElevationProfile(wallElement);
                if (loops.Count == 0)
                    hasExtrusion = false;
                else
                {
                    IList<IList<CurveLoop>> sortedLoops = ExporterIFCUtils.SortCurveLoops(loops);
                    if (sortedLoops.Count == 0)
                        return false;

                    // Current limitation: can't handle wall split into multiple disjointed pieces.
                    int numSortedLoops = sortedLoops.Count;
                    if (numSortedLoops > 1)
                        return false;

                    bool ignoreExtrusion = true;
                    bool cantHandle = false;
                    bool hasGeometry = false;
                    for (int ii = 0; (ii < numSortedLoops) && !cantHandle; ii++)
                    {
                        int sortedLoopSize = sortedLoops[ii].Count;
                        if (sortedLoopSize == 0)
                            continue;
                        if (!ExporterIFCUtils.IsCurveLoopConvexWithOpenings(sortedLoops[ii][0], wallElement, range, out ignoreExtrusion))
                        {
                            if (ignoreExtrusion)
                            {
                                // we need more information.  Is there something to export?  If so, we'll
                                // ignore the extrusion.  Otherwise, we will fail.

                                if (solids.Count == 0 && meshes.Count == 0)
                                    continue;
                            }
                            else
                            {
                                cantHandle = true;
                            }
                            hasGeometry = true;
                        }
                        else
                        {
                            hasGeometry = true;
                        }
                    }

                    if (!hasGeometry)
                    {
                        isCompletelyClipped = true;
                        return false;
                    }

                    if (cantHandle)
                        return false;
                }
            }

            return true;
        }
Example #37
0
        /// <summary>
        /// Main implementation to export walls.
        /// </summary>
        /// <param name="exporterIFC">
        /// The ExporterIFC object.
        /// </param>
        /// <param name="element">
        /// The element.
        /// </param>
        /// <param name="geometryElement">
        /// The geometry element.
        /// </param>
        /// <param name="origWrapper">
        /// The IFCProductWrapper.
        /// </param>
        /// <param name="overrideLevelId">
        /// The level id.
        /// </param>
        /// <param name="range">
        /// The range to be exported for the element.
        /// </param>
        /// <returns>
        /// The exported wall handle.
        /// </returns>
        public static IFCAnyHandle ExportWallBase(ExporterIFC exporterIFC, Element element, GeometryElement geometryElement,
           IFCProductWrapper origWrapper, ElementId overrideLevelId, IFCRange range)
        {
            using (IFCProductWrapper localWrapper = IFCProductWrapper.Create(origWrapper))
            {
                ElementId catId = CategoryUtil.GetSafeCategoryId(element);

                Wall wallElement = element as Wall;
                FamilyInstance famInstWallElem = element as FamilyInstance;

                if (wallElement == null && famInstWallElem == null)
                    return null;

                if (wallElement != null && IsWallCompletelyClipped(wallElement, exporterIFC, range))
                    return null;

                // get global values.
                Document doc = element.Document;
                double scale = exporterIFC.LinearScale;

                IFCFile file = exporterIFC.GetFile();
                IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle();
                IFCAnyHandle contextOfItemsAxis = exporterIFC.Get3DContextHandle("Axis");
                IFCAnyHandle contextOfItemsBody = exporterIFC.Get3DContextHandle("Body");
              
                IFCRange zSpan = new IFCRange();
                double depth = 0.0;
                bool validRange = (range != null && !MathUtil.IsAlmostZero(range.Start - range.End));

                bool exportParts = PartExporter.CanExportParts(wallElement);
                if (exportParts && !PartExporter.CanExportElementInPartExport(wallElement, validRange? overrideLevelId : wallElement.Level.Id, validRange))
                    return null;

                // get bounding box height so that we can subtract out pieces properly.
                // only for Wall, not FamilyInstance.
                if (wallElement != null && geometryElement != null)
                {
                    BoundingBoxXYZ boundingBox = element.get_BoundingBox(null);
                    if (boundingBox == null)
                        return null;
                    zSpan = new IFCRange(boundingBox.Min.Z, boundingBox.Max.Z);

                    // if we have a top clipping plane, modify depth accordingly.
                    double bottomHeight = validRange ? Math.Max(zSpan.Start, range.Start) : zSpan.Start;
                    double topHeight = validRange ? Math.Min(zSpan.End, range.End) : zSpan.End;
                    depth = topHeight - bottomHeight;
                    if (MathUtil.IsAlmostZero(depth))
                        return null;
                    depth *= scale;
                }

                IFCAnyHandle axisRep = null;
                IFCAnyHandle bodyRep = null;

                bool exportingAxis = false;
                Curve curve = null;

                bool exportedAsWallWithAxis = false;
                bool exportedBodyDirectly = false;
                bool exportingInplaceOpenings = false;

                Curve centerCurve = GetWallAxis(wallElement);

                XYZ localXDir = new XYZ(1, 0, 0);
                XYZ localYDir = new XYZ(0, 1, 0);
                XYZ localZDir = new XYZ(0, 0, 1);
                XYZ localOrig = new XYZ(0, 0, 0);
                double eps = MathUtil.Eps();

                if (centerCurve != null)
                {
                    Curve baseCurve = GetWallAxisAtBaseHeight(wallElement);
                    curve = GetWallTrimmedCurve(wallElement, baseCurve);

                    IFCRange curveBounds;
                    XYZ oldOrig;
                    GeometryUtil.GetAxisAndRangeFromCurve(curve, out curveBounds, out localXDir, out oldOrig);

                    localOrig = oldOrig;
                    if (baseCurve != null)
                    {
                        if (!validRange || (MathUtil.IsAlmostEqual(range.Start, zSpan.Start)))
                        {
                            XYZ newOrig = baseCurve.Evaluate(curveBounds.Start, false);
                            if (!validRange && (zSpan.Start < newOrig[2] - eps))
                                localOrig = new XYZ(localOrig.X, localOrig.Y, zSpan.Start);
                            else
                                localOrig = new XYZ(localOrig.X, localOrig.Y, newOrig[2]);
                        }
                        else
                        {
                            localOrig = new XYZ(localOrig.X, localOrig.Y, range.Start);
                        }
                    }

                    double dist = localOrig[2] - oldOrig[2];
                    if (!MathUtil.IsAlmostZero(dist))
                    {
                        XYZ moveVec = new XYZ(0, 0, dist);
                        curve = GeometryUtil.MoveCurve(curve, moveVec);
                    }
                    localYDir = localZDir.CrossProduct(localXDir);

                    // ensure that X and Z axes are orthogonal.
                    double xzDot = localZDir.DotProduct(localXDir);
                    if (!MathUtil.IsAlmostZero(xzDot))
                        localXDir = localYDir.CrossProduct(localZDir);
                }

                Transform orientationTrf = Transform.Identity;
                orientationTrf.BasisX = localXDir;
                orientationTrf.BasisY = localYDir;
                orientationTrf.BasisZ = localZDir;
                orientationTrf.Origin = localOrig;

                using (IFCPlacementSetter setter = IFCPlacementSetter.Create(exporterIFC, element, null, orientationTrf, overrideLevelId))
                {
                    IFCAnyHandle localPlacement = setter.GetPlacement();

                    Plane plane = new Plane(localXDir, localYDir, localOrig);  // project curve to XY plane.
                    XYZ projDir = XYZ.BasisZ;

                    // two representations: axis, body.         
                    {
                        if ((centerCurve != null) && (GeometryUtil.CurveIsLineOrArc(centerCurve)))
                        {
                            exportingAxis = true;

                            string identifierOpt = "Axis";	// IFC2x2 convention
                            string representationTypeOpt = "Curve2D";  // IFC2x2 convention

                            IFCGeometryInfo info = IFCGeometryInfo.CreateCurveGeometryInfo(exporterIFC, plane, projDir, false);
                            ExporterIFCUtils.CollectGeometryInfo(exporterIFC, info, curve, XYZ.Zero, true);
                            IList<IFCAnyHandle> axisItems = info.GetCurves();

                            if (axisItems.Count == 0)
                            {
                                exportingAxis = false;
                            }
                            else
                            {
                                HashSet<IFCAnyHandle> axisItemSet = new HashSet<IFCAnyHandle>();
                                foreach (IFCAnyHandle axisItem in axisItems)
                                    axisItemSet.Add(axisItem);

                                axisRep = RepresentationUtil.CreateShapeRepresentation(exporterIFC, element, catId, contextOfItemsAxis,
                                   identifierOpt, representationTypeOpt, axisItemSet);
                            }
                        }
                    }

                    IList<IFCExtrusionData> cutPairOpenings = new List<IFCExtrusionData>();
                    Document document = element.Document;

                    if (wallElement != null && exportingAxis && curve != null)
                    {
                        SolidMeshGeometryInfo solidMeshInfo = 
                            (range == null) ? GeometryUtil.GetSolidMeshGeometry(geometryElement, Transform.Identity) :
                                GeometryUtil.GetClippedSolidMeshGeometry(geometryElement, range);
                                
                        IList<Solid> solids = solidMeshInfo.GetSolids();
                        IList<Mesh> meshes = solidMeshInfo.GetMeshes();
                        if (solids.Count == 0 && meshes.Count == 0)
                            return null;

                        bool useNewCode = false;
                        if (useNewCode && solids.Count == 1 && meshes.Count == 0)
                        {
                            bool completelyClipped;
                            bodyRep = ExtrusionExporter.CreateExtrusionWithClipping(exporterIFC, wallElement, catId, solids[0], 
                                plane, projDir, range, out completelyClipped);

                            if (completelyClipped)
                                return null;

                            if (!IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep))
                            {
                                exportedAsWallWithAxis = true;
                                exportedBodyDirectly = true;
                            }
                            else
                            {
                                exportedAsWallWithAxis = false;
                                exportedBodyDirectly = false;
                            }
                        }
                            
                        if (!exportedAsWallWithAxis)
                        {
                            // Fallback - use native routines to try to export wall.
                            bool isCompletelyClipped;
                            bodyRep = FallbackTryToCreateAsExtrusion(exporterIFC, wallElement, solidMeshInfo,
                                catId, curve, plane, depth, zSpan, range, setter, 
                                out cutPairOpenings, out isCompletelyClipped);
                            if (isCompletelyClipped)
                                return null;
                            if (!IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep))
                                exportedAsWallWithAxis = true;
                        }
                    }
                
                    using (IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData())
                    {
                        ElementId matId = ElementId.InvalidElementId;

                        if (!exportedAsWallWithAxis)
                        {
                            SolidMeshGeometryInfo solidMeshCapsule = null;

                            if (wallElement != null)
                            {
                                if (validRange)
                                {
                                    solidMeshCapsule = GeometryUtil.GetClippedSolidMeshGeometry(geometryElement, range);
                                }
                                else
                                {
                                    solidMeshCapsule = GeometryUtil.GetSplitSolidMeshGeometry(geometryElement);
                                }
                                if (solidMeshCapsule.SolidsCount() == 0 && solidMeshCapsule.MeshesCount() == 0)
                                {
                                    return null;
                                }
                            }
                            else
                            {
                                GeometryElement geomElemToUse = GetGeometryFromInplaceWall(famInstWallElem);
                                if (geomElemToUse != null)
                                {
                                    exportingInplaceOpenings = true;
                                }
                                else
                                {
                                    exportingInplaceOpenings = false;
                                    geomElemToUse = geometryElement;
                                }
                                Transform trf = Transform.Identity;
                                if (geomElemToUse != geometryElement)
                                    trf = famInstWallElem.GetTransform();
                                solidMeshCapsule = GeometryUtil.GetSolidMeshGeometry(geomElemToUse, trf);
                            }

                            IList<Solid> solids = solidMeshCapsule.GetSolids();
                            IList<Mesh> meshes = solidMeshCapsule.GetMeshes();

                            extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ;   // only allow vertical extrusions!
                            extraParams.AreInnerRegionsOpenings = true;

                            BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true);
                            if ((solids.Count > 0) || (meshes.Count > 0))
                            {
                                matId = BodyExporter.GetBestMaterialIdForGeometry(solids, meshes);
                                bodyRep = BodyExporter.ExportBody(element.Document.Application, exporterIFC, element, catId,
                                    solids, meshes, bodyExporterOptions, extraParams).RepresentationHnd;
                            }
                            else
                            {
                                IList<GeometryObject> geomElemList = new List<GeometryObject>();
                                geomElemList.Add(geometryElement);
                                BodyData bodyData = BodyExporter.ExportBody(element.Document.Application, exporterIFC, element, catId,
                                    geomElemList, bodyExporterOptions, extraParams);
                                bodyRep = bodyData.RepresentationHnd;
                            }

                            if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep))
                            {
                                extraParams.ClearOpenings();
                                return null;
                            }

                            // We will be able to export as a IfcWallStandardCase as long as we have an axis curve.
                            XYZ extrDirUsed = XYZ.Zero;
                            if (extraParams.HasExtrusionDirection)
                            {
                                extrDirUsed = extraParams.ExtrusionDirection;
                                if (MathUtil.IsAlmostEqual(Math.Abs(extrDirUsed[2]), 1.0))
                                {
                                    if ((solids.Count == 1) && (meshes.Count == 0))
                                        exportedAsWallWithAxis = exportingAxis;
                                    exportedBodyDirectly = true;
                                }
                            }
                        }

                        IFCAnyHandle prodRep = null;
                        IList<IFCAnyHandle> representations = new List<IFCAnyHandle>();
                        if (exportingAxis)
                            representations.Add(axisRep);

                        representations.Add(bodyRep);
                        prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations);

                        string objectType = NamingUtil.CreateIFCObjectName(exporterIFC, element);
                        IFCAnyHandle wallHnd = null;

                        string elemGUID = (validRange) ? ExporterIFCUtils.CreateGUID() : ExporterIFCUtils.CreateGUID(element);
                        string elemName = NamingUtil.GetNameOverride(element, exporterIFC.GetName());
                        string elemDesc = NamingUtil.GetDescriptionOverride(element, null);
                        string elemObjectType = NamingUtil.GetObjectTypeOverride(element, objectType);
                        string elemId = NamingUtil.CreateIFCElementId(element);

                        if (exportedAsWallWithAxis)
                        {
                            wallHnd = IFCInstanceExporter.CreateWallStandardCase(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                localPlacement, exportParts ? null : prodRep, elemId);

                            if (exportParts)
                                PartExporter.ExportHostPart(exporterIFC, wallElement, wallHnd, localWrapper, setter, localPlacement, overrideLevelId);

                            localWrapper.AddElement(wallHnd, setter, extraParams, true);

                            OpeningUtil.CreateOpeningsIfNecessary(wallHnd, element, cutPairOpenings, exporterIFC, localPlacement, setter, localWrapper);
                            if (exportedBodyDirectly)
                            {
                                OpeningUtil.CreateOpeningsIfNecessary(wallHnd, element, extraParams, exporterIFC, localPlacement, setter, localWrapper);
                            }
                            else
                            {
                                double scaledWidth = wallElement.Width * scale;
                                ExporterIFCUtils.AddOpeningsToElement(exporterIFC, wallHnd, wallElement, scaledWidth, range, setter, localPlacement, localWrapper);
                            }

                            // export Base Quantities
                            if (ExporterCacheManager.ExportOptionsCache.ExportBaseQuantities)
                            {
                                CreateWallBaseQuantities(exporterIFC, wallElement, wallHnd, depth);
                            }
                        }
                        else
                        {
                            wallHnd = IFCInstanceExporter.CreateWall(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                localPlacement, exportParts ? null : prodRep, elemId);

                            if (exportParts)
                                PartExporter.ExportHostPart(exporterIFC, wallElement, wallHnd, localWrapper, setter, localPlacement, overrideLevelId);

                            localWrapper.AddElement(wallHnd, setter, extraParams, true);

                            // Only export one material for 2x2; for future versions, export the whole list.
                            if (exporterIFC.ExportAs2x2 && (matId != ElementId.InvalidElementId) && !exportParts)
                            {
                                CategoryUtil.CreateMaterialAssociation(doc, exporterIFC, wallHnd, matId);
                            }

                            if (exportingInplaceOpenings)
                            {
                                ExporterIFCUtils.AddOpeningsToElement(exporterIFC, wallHnd, famInstWallElem, 0.0, range, setter, localPlacement, localWrapper);
                            }

                            if (exportedBodyDirectly)
                                OpeningUtil.CreateOpeningsIfNecessary(wallHnd, element, extraParams, exporterIFC, localPlacement, setter, localWrapper);
                        }

                        PropertyUtil.CreateInternalRevitPropertySets(exporterIFC, element, localWrapper);

                        ElementId wallLevelId = (validRange) ? setter.LevelId : ElementId.InvalidElementId;

                        if (wallElement != null && !exportParts)
                        {
                            if (!exporterIFC.ExportAs2x2 || exportedAsWallWithAxis) //will move this check into ExportHostObject
                                HostObjectExporter.ExportHostObjectMaterials(exporterIFC, wallElement, localWrapper.GetAnElement(),
                                    geometryElement, localWrapper, wallLevelId, Toolkit.IFCLayerSetDirection.Axis2);
                        }

                        exporterIFC.RegisterSpaceBoundingElementHandle(wallHnd, element.Id, wallLevelId);
                        return wallHnd;
                    }
                }
            }
        }
        private static IFCAnyHandle TryToCreateAsExtrusion(ExporterIFC exporterIFC, 
            Wall wallElement, 
            IList<IList<IFCConnectedWallData>> connectedWalls,
            IList<Solid> solids,
            IList<Mesh> meshes,
            double baseWallElevation, 
            ElementId catId, 
            Curve baseCurve, 
            Curve trimmedCurve,
            Plane wallLCS, 
            double scaledDepth, 
            IFCRange zSpan, 
            IFCRange range, 
            PlacementSetter setter,
            out IList<IFCExtrusionData> cutPairOpenings, 
            out bool isCompletelyClipped, 
            out double scaledFootprintArea, 
            out double scaledLength)
        {
            cutPairOpenings = new List<IFCExtrusionData>();

            IFCAnyHandle bodyRep;
            scaledFootprintArea = 0;

            double unscaledLength = trimmedCurve != null ? trimmedCurve.Length : 0;
            scaledLength = UnitUtil.ScaleLength(unscaledLength);

            XYZ localOrig = wallLCS.Origin;

            // Check to see if the wall has geometry given the specified range.
            if (!WallHasGeometryToExport(wallElement, solids, meshes, range, out isCompletelyClipped))
                return null;

            // This is our major check here that goes into internal code.  If we have enough information to faithfully reproduce
            // the wall as an extrusion with clippings and openings, we will continue.  Otherwise, export it as a BRep.
            if (!CanExportWallGeometryAsExtrusion(wallElement, range))
                return null;

            // extrusion direction.
            XYZ extrusionDir = GetWallHeightDirection(wallElement);

            // create extrusion boundary.
            bool alwaysThickenCurve = IsWallBaseRectangular(wallElement, trimmedCurve);
            
            double unscaledWidth = wallElement.Width;
            IList<CurveLoop> boundaryLoops = GetBoundaryLoopsFromWall(exporterIFC, wallElement, alwaysThickenCurve, trimmedCurve, unscaledWidth);
            if (boundaryLoops == null || boundaryLoops.Count == 0)
                    return null;

            double fullUnscaledLength = baseCurve.Length;
            double unscaledFootprintArea = ExporterIFCUtils.ComputeAreaOfCurveLoops(boundaryLoops);
            scaledFootprintArea = UnitUtil.ScaleArea(unscaledFootprintArea);
            // We are going to do a little sanity check here.  If the scaledFootprintArea is significantly less than the 
            // width * length of the wall footprint, we probably calculated the area wrong, and will abort.
            // This could occur because of a door or window that cuts a corner of the wall (i.e., has no wall material on one side).
            // We want the scaledFootprintArea to be at least (95% of approximateBaseArea - 2 * side wall area).  
            // The "side wall area" is an approximate value that takes into account potential wall joins.  
            // This prevents us from doing extra work for many small walls because of joins.  We'll allow 1' (~30 cm) per side for this.
            double approximateUnscaledBaseArea = unscaledWidth * fullUnscaledLength;
            if (unscaledFootprintArea < (approximateUnscaledBaseArea * .95 - 2 * unscaledWidth))
            {
                // Can't handle the case where we don't have a simple extrusion to begin with.
                if (!alwaysThickenCurve)
                    return null;

                boundaryLoops = GetBoundaryLoopsFromBaseCurve(wallElement, connectedWalls, baseCurve, trimmedCurve, unscaledWidth, scaledDepth);
                if (boundaryLoops == null || boundaryLoops.Count == 0)
                return null;
            }

            // origin gets scaled later.
            double baseWallZOffset = localOrig[2] - ((range == null) ? baseWallElevation : Math.Min(range.Start, baseWallElevation));
            XYZ modifiedSetterOffset = new XYZ(0, 0, setter.Offset + baseWallZOffset);

            IFCAnyHandle baseBodyItemHnd = ExtrusionExporter.CreateExtrudedSolidFromCurveLoop(exporterIFC, null, boundaryLoops, wallLCS,
                extrusionDir, scaledDepth);
            if (IFCAnyHandleUtil.IsNullOrHasNoValue(baseBodyItemHnd))
                return null;

            IFCAnyHandle bodyItemHnd = AddClippingsToBaseExtrusion(exporterIFC, wallElement,
               modifiedSetterOffset, range, zSpan, baseBodyItemHnd, out cutPairOpenings);
            if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyItemHnd))
                return null;
            bool hasClipping = bodyItemHnd.Id != baseBodyItemHnd.Id;

            ElementId matId = HostObjectExporter.GetFirstLayerMaterialId(wallElement);
            IFCAnyHandle styledItemHnd = BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, wallElement.Document,
                baseBodyItemHnd, matId);

            HashSet<IFCAnyHandle> bodyItems = new HashSet<IFCAnyHandle>();
            bodyItems.Add(bodyItemHnd);

            // Check whether wall has opening. If it has, exporting it in the Reference View will need to be in a tessellated geometry that includes the opening cut
            IList<IFCOpeningData> openingDataList = ExporterIFCUtils.GetOpeningData(exporterIFC, wallElement, wallLCS, range);
            bool wallHasOpening = openingDataList.Count > 0;
            BodyExporterOptions options = new BodyExporterOptions(true);

            IFCAnyHandle contextOfItemsBody = exporterIFC.Get3DContextHandle("Body");
            if (!hasClipping)
            {
                // Check whether wall has opening. If it has, exporting it in Reference View will need to be in a tesselated geometry that includes the opening cut
                if (ExporterUtil.IsReferenceView() && wallHasOpening)
                {
                    List<GeometryObject> geomList = new List<GeometryObject>();
                    bodyItems.Clear();       // Since we will change the geometry, clear existing extrusion data first
                    if (solids.Count > 0)
                        foreach (GeometryObject solid in solids)
                            geomList.Add(solid);
                    if (meshes.Count > 0)
                        foreach (GeometryObject mesh in meshes)
                            geomList.Add(mesh);
                    foreach (GeometryObject geom in geomList)
                    {
                        IFCAnyHandle triangulatedBodyItem = BodyExporter.ExportBodyAsTriangulatedFaceSet(exporterIFC, wallElement, options, geom);
                        if (!IFCAnyHandleUtil.IsNullOrHasNoValue(triangulatedBodyItem)) 
                            bodyItems.Add(triangulatedBodyItem);
                    }
                    bodyRep = RepresentationUtil.CreateTessellatedRep(exporterIFC, wallElement, catId, contextOfItemsBody, bodyItems, null);
                }
                else
                    bodyRep = RepresentationUtil.CreateSweptSolidRep(exporterIFC, wallElement, catId, contextOfItemsBody, bodyItems, null);
            }
            else
            {
                // Create TessellatedRep geometry if it is Reference View.
                if (ExporterUtil.IsReferenceView())
                {
                    List<GeometryObject> geomList = new List<GeometryObject>();
                    // The native function AddClippingsToBaseExtrusion will create the IfcBooleanClippingResult entity and therefore here we need to delete it
                    foreach (IFCAnyHandle item in bodyItems)
                    {
                        item.Dispose();     //Still DOES NOT work, the IfcBooleanClippingResult is still orphaned in the IFC file!
                    }
                    bodyItems.Clear();       // Since we will change the geometry, clear existing extrusion data first

                    if (solids.Count > 0)
                        foreach (GeometryObject solid in solids)
                            geomList.Add(solid);
                    if (meshes.Count > 0)
                        foreach (GeometryObject mesh in meshes)
                            geomList.Add(mesh);
                    foreach (GeometryObject geom in geomList)
                    {
                        IFCAnyHandle triangulatedBodyItem = BodyExporter.ExportBodyAsTriangulatedFaceSet(exporterIFC, wallElement, options, geom);
                        if (!IFCAnyHandleUtil.IsNullOrHasNoValue(triangulatedBodyItem)) 
                            bodyItems.Add(triangulatedBodyItem);
                    }
                    bodyRep = RepresentationUtil.CreateTessellatedRep(exporterIFC, wallElement, catId, contextOfItemsBody, bodyItems, null);
                }
                else
                    bodyRep = RepresentationUtil.CreateClippingRep(exporterIFC, wallElement, catId, contextOfItemsBody, bodyItems);
            }

            return bodyRep;
        }
Example #39
0
        /// <summary>
        /// Export the dummy wall to host an orphan part. It usually happens in the cases of associated parts are higher than split sub-wall.
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="element">The wall element.</param>
        /// <param name="geometryElement">The geometry of wall.</param>
        /// <param name="origWrapper">The IFCProductWrapper.</param>
        /// <param name="overrideLevelId">The ElementId that will crate the dummy wall.</param>
        /// <param name="range">The IFCRange corresponding to the dummy wall.</param>
        /// <returns>The handle of dummy wall.</returns>
        public static IFCAnyHandle ExportDummyWall(ExporterIFC exporterIFC, Element element, GeometryElement geometryElement,
           IFCProductWrapper origWrapper, ElementId overrideLevelId, IFCRange range)
        {
            using (IFCProductWrapper localWrapper = IFCProductWrapper.Create(origWrapper))
            {
                ElementId catId = CategoryUtil.GetSafeCategoryId(element);

                Wall wallElement = element as Wall;
                if (wallElement == null)
                    return null;

                if (wallElement != null && IsWallCompletelyClipped(wallElement, exporterIFC, range))
                    return null;

                // get global values.
                Document doc = element.Document;
                double scale = exporterIFC.LinearScale;

                IFCFile file = exporterIFC.GetFile();
                IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle();

                bool validRange = (range != null && !MathUtil.IsAlmostZero(range.Start - range.End));

                bool exportParts = PartExporter.CanExportParts(wallElement);
                if (exportParts && !PartExporter.CanExportElementInPartExport(wallElement, validRange ? overrideLevelId : wallElement.Level.Id, validRange))
                    return null;

                string objectType = NamingUtil.CreateIFCObjectName(exporterIFC, element);
                IFCAnyHandle wallHnd = null;

                string elemGUID = (validRange) ? ExporterIFCUtils.CreateGUID() : ExporterIFCUtils.CreateGUID(element);
                string elemName = NamingUtil.GetNameOverride(element, exporterIFC.GetName());
                string elemDesc = NamingUtil.GetDescriptionOverride(element, null);
                string elemObjectType = NamingUtil.GetObjectTypeOverride(element, objectType);
                string elemId = NamingUtil.CreateIFCElementId(element);

                Transform orientationTrf = Transform.Identity;

                using (IFCPlacementSetter setter = IFCPlacementSetter.Create(exporterIFC, element, null, orientationTrf, overrideLevelId))
                {
                    IFCAnyHandle localPlacement = setter.GetPlacement();
                    wallHnd = IFCInstanceExporter.CreateWall(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                    localPlacement, null, elemId);

                    if (exportParts)
                        PartExporter.ExportHostPart(exporterIFC, wallElement, wallHnd, localWrapper, setter, localPlacement, overrideLevelId);

                    IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData();
                    extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ;   // only allow vertical extrusions!
                    extraParams.AreInnerRegionsOpenings = true;
                    localWrapper.AddElement(wallHnd, setter, extraParams, true);

                    PropertyUtil.CreateInternalRevitPropertySets(exporterIFC, element, localWrapper);

                    ElementId wallLevelId = (validRange) ? setter.LevelId : ElementId.InvalidElementId;
                    exporterIFC.RegisterSpaceBoundingElementHandle(wallHnd, element.Id, wallLevelId);
                }
                
                return wallHnd;
            }
        }
        // Get a list of solids and meshes, but only if we haven't already done so.
        private static void GetSolidsAndMeshes(GeometryElement geometryElement, IFCRange range, ref IList<Solid> solids, ref IList<Mesh> meshes)
        {
            if (solids.Count > 0 || meshes.Count > 0)
                return;

            SolidMeshGeometryInfo solidMeshInfo =
                (range == null) ? GeometryUtil.GetSplitSolidMeshGeometry(geometryElement) :
                    GeometryUtil.GetSplitClippedSolidMeshGeometry(geometryElement, range);

            solids = solidMeshInfo.GetSolids();
            meshes = solidMeshInfo.GetMeshes();
        }
Example #41
0
 /// <summary>
 /// Identifies if the base geometry of the wall can be represented as an extrusion.
 /// </summary>
 /// <param name="element">
 /// The wall element.
 /// </param>
 /// <param name="range">
 /// The range. This consists of two double values representing the height in Z at the start and the end
 /// of the range.  If the values are identical the entire wall is used.
 /// </param>
 /// <returns>
 /// True if the wall export can be made in the form of an extrusion, false if the
 /// geometry cannot be assigned to an extrusion.
 /// </returns>
 static bool CanExportWallGeometryAsExtrusion(Element element, IFCRange range)
 {
     return ExporterIFCUtils.CanExportWallGeometryAsExtrusion(element, range);
 }
        /// <summary>
        /// Main implementation to export walls.
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="element">The element.</param>
        /// <param name="connectedWalls">Information about walls joined to this wall.</param>
        /// <param name="geometryElement">The geometry element.</param>
        /// <param name="origWrapper">The ProductWrapper.</param>
        /// <param name="overrideLevelId">The level id.</param>
        /// <param name="range">The range to be exported for the element.</param>
        /// <returns>The exported wall handle.</returns>
        public static IFCAnyHandle ExportWallBase(ExporterIFC exporterIFC, Element element, IList<IList<IFCConnectedWallData>> connectedWalls,
            GeometryElement geometryElement, ProductWrapper origWrapper, ElementId overrideLevelId, IFCRange range)
        {
            // Check cases where we choose not to export early.
            ElementId catId = CategoryUtil.GetSafeCategoryId(element);

            Wall wallElement = element as Wall;
            FamilyInstance famInstWallElem = element as FamilyInstance;
            FaceWall faceWall = element as FaceWall;

            bool exportingWallElement = (wallElement != null);
            bool exportingFamilyInstance = (famInstWallElem != null);
            bool exportingFaceWall = (faceWall != null);

            if (!exportingWallElement && !exportingFamilyInstance && !exportingFaceWall)
                return null;

            if (exportingWallElement && IsWallCompletelyClipped(wallElement, exporterIFC, range))
                return null;

            IFCRange zSpan = null;
            double depth = 0.0;
            bool validRange = (range != null && !MathUtil.IsAlmostZero(range.Start - range.End));

            bool exportParts = PartExporter.CanExportParts(element);
            if (exportParts && !PartExporter.CanExportElementInPartExport(element, validRange ? overrideLevelId : element.LevelId, validRange))
                return null;

            IList<Solid> solids = new List<Solid>();
            IList<Mesh> meshes = new List<Mesh>();
            bool exportingInplaceOpenings = false;

            if (!exportParts)
            {
                if (exportingWallElement || exportingFaceWall)
                {
                    GetSolidsAndMeshes(geometryElement, range, ref solids, ref meshes);
                    if (solids.Count == 0 && meshes.Count == 0)
                        return null;
                }
                else
                {
                    GeometryElement geomElemToUse = GetGeometryFromInplaceWall(famInstWallElem);
                    if (geomElemToUse != null)
                    {
                        exportingInplaceOpenings = true;
                    }
                    else
                    {
                        exportingInplaceOpenings = false;
                        geomElemToUse = geometryElement;
                    }
                    Transform trf = Transform.Identity;
                    if (geomElemToUse != geometryElement)
                        trf = famInstWallElem.GetTransform();

                    SolidMeshGeometryInfo solidMeshCapsule = GeometryUtil.GetSplitSolidMeshGeometry(geomElemToUse, trf);
                    solids = solidMeshCapsule.GetSolids();
                    meshes = solidMeshCapsule.GetMeshes();
                }
            }

            IFCFile file = exporterIFC.GetFile();
            using (IFCTransaction tr = new IFCTransaction(file))
            {
                using (ProductWrapper localWrapper = ProductWrapper.Create(origWrapper))
                {
                    // get bounding box height so that we can subtract out pieces properly.
                    // only for Wall, not FamilyInstance.
                    if (exportingWallElement && geometryElement != null)
                    {
                        // There is a problem in the API where some walls with vertical structures are overreporting their height,
                        // making it appear as if there are clipping problems on export.  We will work around this by getting the
                        // height directly from the solid(s).
                        if (solids.Count > 0 && meshes.Count == 0)
                        {
                            zSpan = GetBoundingBoxOfSolids(solids);
                        }
                        else
                        {
                            BoundingBoxXYZ boundingBox = wallElement.get_BoundingBox(null);
                            if (boundingBox != null)
                                zSpan = GetBoundingBoxZRange(boundingBox);
                        }

                        if (zSpan == null)
                            return null;

                        // if we have a top clipping plane, modify depth accordingly.
                        double bottomHeight = validRange ? Math.Max(zSpan.Start, range.Start) : zSpan.Start;
                        double topHeight = validRange ? Math.Min(zSpan.End, range.End) : zSpan.End;
                        depth = topHeight - bottomHeight;
                        if (MathUtil.IsAlmostZero(depth))
                            return null;
                        depth = UnitUtil.ScaleLength(depth);
                    }
                    else
                    {
                        zSpan = new IFCRange();
                    }

                    Document doc = element.Document;

                    double baseWallElevation = 0.0;
                    ElementId baseLevelId = PlacementSetter.GetBaseLevelIdForElement(element);
                    if (baseLevelId != ElementId.InvalidElementId)
                    {
                        Element baseLevel = doc.GetElement(baseLevelId);
                        if (baseLevel is Level)
                            baseWallElevation = (baseLevel as Level).Elevation;
                    }

                    IFCAnyHandle axisRep = null;
                    IFCAnyHandle bodyRep = null;

                    bool exportingAxis = false;
                    Curve trimmedCurve = null;

                    bool exportedAsWallWithAxis = false;
                    bool exportedBodyDirectly = false;

                    Curve centerCurve = GetWallAxis(wallElement);

                    XYZ localXDir = new XYZ(1, 0, 0);
                    XYZ localYDir = new XYZ(0, 1, 0);
                    XYZ localZDir = new XYZ(0, 0, 1);
                    XYZ localOrig = new XYZ(0, 0, 0);
                    double eps = MathUtil.Eps();

                    if (centerCurve != null)
                    {
                        Curve baseCurve = GetWallAxisAtBaseHeight(wallElement);
                        trimmedCurve = GetWallTrimmedCurve(wallElement, baseCurve);

                        IFCRange curveBounds;
                        XYZ oldOrig;
                        GeometryUtil.GetAxisAndRangeFromCurve(trimmedCurve, out curveBounds, out localXDir, out oldOrig);

                        // Move the curve to the bottom of the geometry or the bottom of the range, which is higher.
                        if (baseCurve != null)
                            localOrig = new XYZ(oldOrig.X, oldOrig.Y, validRange ? Math.Max(range.Start, zSpan.Start) : zSpan.Start);
                        else
                            localOrig = oldOrig;

                        double dist = localOrig[2] - oldOrig[2];
                        if (!MathUtil.IsAlmostZero(dist))
                        {
                            XYZ moveVec = new XYZ(0, 0, dist);
                            trimmedCurve = GeometryUtil.MoveCurve(trimmedCurve, moveVec);
                        }
                        localYDir = localZDir.CrossProduct(localXDir);

                        // ensure that X and Z axes are orthogonal.
                        double xzDot = localZDir.DotProduct(localXDir);
                        if (!MathUtil.IsAlmostZero(xzDot))
                            localXDir = localYDir.CrossProduct(localZDir);
                    }
                    else
                    {
                        BoundingBoxXYZ boundingBox = element.get_BoundingBox(null);
                        if (boundingBox != null)
                        {
                            XYZ bBoxMin = boundingBox.Min;
                            XYZ bBoxMax = boundingBox.Max;
                            if (validRange)
                                localOrig = new XYZ(bBoxMin.X, bBoxMin.Y, range.Start);
                            else
                                localOrig = boundingBox.Min;

                            XYZ localXDirMax = null;
                            Transform bTrf = boundingBox.Transform;
                            XYZ localXDirMax1 = new XYZ(bBoxMax.X, localOrig.Y, localOrig.Z);
                            localXDirMax1 = bTrf.OfPoint(localXDirMax1);
                            XYZ localXDirMax2 = new XYZ(localOrig.X, bBoxMax.Y, localOrig.Z);
                            localXDirMax2 = bTrf.OfPoint(localXDirMax2);
                            if (localXDirMax1.DistanceTo(localOrig) >= localXDirMax2.DistanceTo(localOrig))
                                localXDirMax = localXDirMax1;
                            else
                                localXDirMax = localXDirMax2;
                            localXDir = localXDirMax.Subtract(localOrig);
                            localXDir = localXDir.Normalize();
                            localYDir = localZDir.CrossProduct(localXDir);

                            // ensure that X and Z axes are orthogonal.
                            double xzDot = localZDir.DotProduct(localXDir);
                            if (!MathUtil.IsAlmostZero(xzDot))
                                localXDir = localYDir.CrossProduct(localZDir);
                        }
                    }

                    IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle();

                    Transform orientationTrf = Transform.Identity;
                    orientationTrf.BasisX = localXDir;
                    orientationTrf.BasisY = localYDir;
                    orientationTrf.BasisZ = localZDir;
                    orientationTrf.Origin = localOrig;

                    double scaledFootprintArea = 0;
                    double scaledLength = 0;

                    using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, element, null, orientationTrf, overrideLevelId))
                    {
                        IFCAnyHandle localPlacement = setter.LocalPlacement;

                        // The local coordinate system of the wall as defined by IFC for IfcWallStandardCase.
                        Plane wallLCS = new Plane(localXDir, localYDir, localOrig);  // project curve to XY plane.
                        XYZ projDir = XYZ.BasisZ;

                        // two representations: axis, body.         
                        {
                            if (!exportParts && (centerCurve != null) && (GeometryUtil.CurveIsLineOrArc(centerCurve)))
                            {
                                exportingAxis = true;

                                string identifierOpt = "Axis";	// IFC2x2 convention
                                string representationTypeOpt = "Curve2D";  // IFC2x2 convention

                                IFCGeometryInfo info = IFCGeometryInfo.CreateCurveGeometryInfo(exporterIFC, wallLCS, projDir, false);
                                ExporterIFCUtils.CollectGeometryInfo(exporterIFC, info, trimmedCurve, XYZ.Zero, true);
                                IList<IFCAnyHandle> axisItems = info.GetCurves();

                                if (axisItems.Count == 0)
                                {
                                    exportingAxis = false;
                                }
                                else
                                {
                                    HashSet<IFCAnyHandle> axisItemSet = new HashSet<IFCAnyHandle>();
                                    foreach (IFCAnyHandle axisItem in axisItems)
                                        axisItemSet.Add(axisItem);

                                    IFCAnyHandle contextOfItemsAxis = exporterIFC.Get3DContextHandle("Axis");
                                    axisRep = RepresentationUtil.CreateShapeRepresentation(exporterIFC, element, catId, contextOfItemsAxis,
                                       identifierOpt, representationTypeOpt, axisItemSet);
                                }
                            }
                        }

                        IList<IFCExtrusionData> cutPairOpenings = new List<IFCExtrusionData>();

                        if (!exportParts && exportingWallElement && exportingAxis && trimmedCurve != null)
                        {
                                    bool isCompletelyClipped;
                            bodyRep = TryToCreateAsExtrusion(exporterIFC, wallElement, connectedWalls, solids, meshes, baseWallElevation,
                                catId, centerCurve, trimmedCurve, wallLCS, depth, zSpan, range, setter,
                                        out cutPairOpenings, out isCompletelyClipped, out scaledFootprintArea, out scaledLength);
                                    if (isCompletelyClipped)
                                        return null;
                                    if (!IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep))
                                        exportedAsWallWithAxis = true;
                                }

                        using (IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData())
                        {
                            BodyData bodyData = null;

                            if (!exportedAsWallWithAxis)
                            {
                                extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ;   // only allow vertical extrusions!
                                extraParams.AreInnerRegionsOpenings = true;

                                BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true);
                                
                                // Swept solids are not natively exported as part of CV2.0.  
                                // We have removed the UI toggle for this, so that it is by default false, but keep for possible future use.
                                if (ExporterCacheManager.ExportOptionsCache.ExportAdvancedSweptSolids)
                                    bodyExporterOptions.TryToExportAsSweptSolid = true;

                                ElementId overrideMaterialId = ElementId.InvalidElementId;
                                if (exportingWallElement)
                                    overrideMaterialId = HostObjectExporter.GetFirstLayerMaterialId(wallElement);

                                if (!exportParts)
                                {
                                    if ((solids.Count > 0) || (meshes.Count > 0))
                                    {
                                        bodyRep = BodyExporter.ExportBody(exporterIFC, element, catId, overrideMaterialId,
                                            solids, meshes, bodyExporterOptions, extraParams).RepresentationHnd;
                                    }
                                    else
                                    {
                                        IList<GeometryObject> geomElemList = new List<GeometryObject>();
                                        geomElemList.Add(geometryElement);
                                        bodyData = BodyExporter.ExportBody(exporterIFC, element, catId, overrideMaterialId,
                                            geomElemList, bodyExporterOptions, extraParams);
                                        bodyRep = bodyData.RepresentationHnd;
                                    }

                                    if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep))
                                    {
                                        extraParams.ClearOpenings();
                                        return null;
                                    }
                                }

                                // We will be able to export as a IfcWallStandardCase as long as we have an axis curve.
                                XYZ extrDirUsed = XYZ.Zero;
                                if (extraParams.HasExtrusionDirection)
                                {
                                    extrDirUsed = extraParams.ExtrusionDirection;
                                    if (MathUtil.IsAlmostEqual(Math.Abs(extrDirUsed[2]), 1.0))
                                    {
                                        if ((solids.Count == 1) && (meshes.Count == 0))
                                            exportedAsWallWithAxis = exportingAxis;
                                        exportedBodyDirectly = true;
                                    }
                                }
                            }

                            IFCAnyHandle prodRep = null;
                            if (!exportParts)
                            {
                                IList<IFCAnyHandle> representations = new List<IFCAnyHandle>();
                                if (exportingAxis)
                                    representations.Add(axisRep);

                                representations.Add(bodyRep);

                                IFCAnyHandle boundingBoxRep = null;
                                if ((solids.Count > 0) || (meshes.Count > 0))
                                    boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, solids, meshes, Transform.Identity);
                                else
                                    boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geometryElement, Transform.Identity);

                                if (boundingBoxRep != null)
                                    representations.Add(boundingBoxRep);

                                prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations);
                            }

                            ElementId matId = ElementId.InvalidElementId;
                            string objectType = NamingUtil.CreateIFCObjectName(exporterIFC, element);
                            IFCAnyHandle wallHnd = null;

                            string elemGUID = null;
                            int subElementIndex = ExporterStateManager.GetCurrentRangeIndex();
                            if (subElementIndex == 0)
                                elemGUID = GUIDUtil.CreateGUID(element);
                            else if (subElementIndex <= ExporterStateManager.RangeIndexSetter.GetMaxStableGUIDs())
                                elemGUID = GUIDUtil.CreateSubElementGUID(element, subElementIndex + (int)IFCGenericSubElements.SplitInstanceStart - 1);
                            else
                                elemGUID = GUIDUtil.CreateGUID();
                            
                            string elemName = NamingUtil.GetNameOverride(element, NamingUtil.GetIFCName(element));
                            string elemDesc = NamingUtil.GetDescriptionOverride(element, null);
                            string elemObjectType = NamingUtil.GetObjectTypeOverride(element, objectType);
                            string elemTag = NamingUtil.GetTagOverride(element, NamingUtil.CreateIFCElementId(element));

                            string ifcType = IFCValidateEntry.GetValidIFCType(element, null);

                            // For Foundation and Retaining walls, allow exporting as IfcFooting instead.
                            bool exportAsFooting = false;
                            if (exportingWallElement)
                            {
                                WallType wallType = wallElement.WallType;

                                if (wallType != null)
                                {
                                    int wallFunction;
                                    if (ParameterUtil.GetIntValueFromElement(wallType, BuiltInParameter.FUNCTION_PARAM, out wallFunction) != null)
                                    {
                                        if (wallFunction == (int)WallFunction.Retaining || wallFunction == (int)WallFunction.Foundation)
                                        {
                                            // In this case, allow potential to export foundation and retaining walls as footing.
                                            string enumTypeValue = null;
                                            IFCExportType exportType = ExporterUtil.GetExportType(exporterIFC, wallElement, out enumTypeValue);
                                            if (exportType == IFCExportType.IfcFooting)
                                                exportAsFooting = true;
                                        }
                                    }
                                }
                            }

                            if (exportedAsWallWithAxis)
                            {
                                if (exportAsFooting)
                                {
                                    wallHnd = IFCInstanceExporter.CreateFooting(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                        localPlacement, exportParts ? null : prodRep, elemTag, ifcType);
                                }
                                else
                                {
                                    bool exportAsWall = exportParts;
                                    if (!exportAsWall)
                                    {
                                        // (For Reference View export) If the representation returned earlier is of type Tessellation, create IfcWall instead.
                                        foreach (IFCAnyHandle pRep in IFCAnyHandleUtil.GetRepresentations(prodRep))
                                        {
                                            if (String.Compare(IFCAnyHandleUtil.GetRepresentationType(pRep), "Tessellation") == 0)
                                            {
                                                exportAsWall = true;
                                                break;
                                            }
                                        }
                                    }

                                    if (exportAsWall)
                                    {
                                        wallHnd = IFCInstanceExporter.CreateWall(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                                localPlacement, null, elemTag, ifcType);
                                    }
                                    else
                                    {
                                        wallHnd = IFCInstanceExporter.CreateWallStandardCase(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                            localPlacement, prodRep, elemTag, ifcType);
                                    }
                                }

                                if (exportParts)
                                    PartExporter.ExportHostPart(exporterIFC, element, wallHnd, localWrapper, setter, localPlacement, overrideLevelId);

                                localWrapper.AddElement(element, wallHnd, setter, extraParams, true);

                                if (!exportParts)
                                {
                                    OpeningUtil.CreateOpeningsIfNecessary(wallHnd, element, cutPairOpenings, null,
                                        exporterIFC, localPlacement, setter, localWrapper);
                                    if (exportedBodyDirectly)
                                    {
                                        Transform offsetTransform = (bodyData != null) ? bodyData.OffsetTransform : Transform.Identity;
                                        OpeningUtil.CreateOpeningsIfNecessary(wallHnd, element, extraParams, offsetTransform,
                                            exporterIFC, localPlacement, setter, localWrapper);
                                    }
                                    else
                                    {
                                        double scaledWidth = UnitUtil.ScaleLength(wallElement.Width);
                                        OpeningUtil.AddOpeningsToElement(exporterIFC, wallHnd, wallElement, null, scaledWidth, range, setter, localPlacement, localWrapper);
                                    }
                                }

                                // export Base Quantities
                                if (ExporterCacheManager.ExportOptionsCache.ExportBaseQuantities)
                                {
                                    scaledFootprintArea = MathUtil.AreaIsAlmostZero(scaledFootprintArea) ? extraParams.ScaledArea : scaledFootprintArea;
                                    scaledLength = MathUtil.IsAlmostZero(scaledLength) ? extraParams.ScaledLength : scaledLength;
                                    PropertyUtil.CreateWallBaseQuantities(exporterIFC, wallElement, solids, meshes, wallHnd, scaledLength, depth, scaledFootprintArea);
                                }
                            }
                            else
                            {
                                if (exportAsFooting)
                                {
                                    wallHnd = IFCInstanceExporter.CreateFooting(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                        localPlacement, exportParts ? null : prodRep, elemTag, ifcType);
                                }
                                else
                                {
                                    wallHnd = IFCInstanceExporter.CreateWall(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                        localPlacement, exportParts ? null : prodRep, elemTag, ifcType);
                                }

                                if (exportParts)
                                    PartExporter.ExportHostPart(exporterIFC, element, wallHnd, localWrapper, setter, localPlacement, overrideLevelId);

                                localWrapper.AddElement(element, wallHnd, setter, extraParams, true);

                                if (!exportParts)
                                {
                                    // Only export one material for 2x2; for future versions, export the whole list.
                                    if (ExporterCacheManager.ExportOptionsCache.ExportAs2x2 || exportingFamilyInstance)
                                    {
                                        matId = BodyExporter.GetBestMaterialIdFromGeometryOrParameter(solids, meshes, element);
                                        if (matId != ElementId.InvalidElementId)
                                            CategoryUtil.CreateMaterialAssociation(exporterIFC, wallHnd, matId);
                                    }

                                    if (exportingInplaceOpenings)
                                    {
                                        OpeningUtil.AddOpeningsToElement(exporterIFC, wallHnd, famInstWallElem, null, 0.0, range, setter, localPlacement, localWrapper);
                                    }

                                    if (exportedBodyDirectly)
                                    {
                                        Transform offsetTransform = (bodyData != null) ? bodyData.OffsetTransform : Transform.Identity;
                                        OpeningUtil.CreateOpeningsIfNecessary(wallHnd, element, extraParams, offsetTransform,
                                            exporterIFC, localPlacement, setter, localWrapper);
                                    }
                                }
                            }

                            ElementId wallLevelId = (validRange) ? setter.LevelId : ElementId.InvalidElementId;

                            if ((exportingWallElement || exportingFaceWall) && !exportParts)
                            {
                                HostObject hostObject = null;
                                if (exportingWallElement)
                                    hostObject = wallElement;
                                else
                                    hostObject = faceWall;
                                if (!ExporterCacheManager.ExportOptionsCache.ExportAs2x2 || exportedAsWallWithAxis)
                                    HostObjectExporter.ExportHostObjectMaterials(exporterIFC, hostObject, localWrapper.GetAnElement(),
                                        geometryElement, localWrapper, wallLevelId, Toolkit.IFCLayerSetDirection.Axis2, !exportedAsWallWithAxis);
                            }

                            ExportWallType(exporterIFC, localWrapper, wallHnd, element, matId, exportedAsWallWithAxis, exportAsFooting);

                            SpaceBoundingElementUtil.RegisterSpaceBoundingElementHandle(exporterIFC, wallHnd, element.Id, wallLevelId);

                            tr.Commit();
                            return wallHnd;
                        }
                    }
                }
            }
        }
Example #43
0
        /// <summary>
        /// Export the individual part (IfcBuildingElementPart).
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="partElement">The part element to export.</param>
        /// <param name="geometryElement">The geometry of part.</param>
        /// <param name="productWrapper">The ProductWrapper object.</param>
        public static void ExportPart(ExporterIFC exporterIFC, Element partElement, ProductWrapper productWrapper,
                                      PlacementSetter placementSetter, IFCAnyHandle originalPlacement, IFCRange range, IFCExtrusionAxes ifcExtrusionAxes,
                                      Element hostElement, ElementId overrideLevelId, bool asBuildingElement)
        {
            if (!ElementFilteringUtil.IsElementVisible(partElement))
            {
                return;
            }

            Part part = partElement as Part;

            if (part == null)
            {
                return;
            }

            if (!asBuildingElement)
            {
                // 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>("IfcBuildingElementPart", out elementClassTypeEnum))
                {
                    if (ExporterCacheManager.ExportOptionsCache.IsElementInExcludeList(elementClassTypeEnum))
                    {
                        return;
                    }
                }
            }
            else
            {
                string        ifcEnumType = null;
                IFCExportType exportType  = ExporterUtil.GetExportType(exporterIFC, hostElement, out ifcEnumType);

                // 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>(exportType.ToString(), out elementClassTypeEnum))
                {
                    if (ExporterCacheManager.ExportOptionsCache.IsElementInExcludeList(elementClassTypeEnum))
                    {
                        return;
                    }
                }
            }

            PlacementSetter standalonePlacementSetter = null;
            bool            standaloneExport          = hostElement == null && !asBuildingElement;

            ElementId partExportLevel = null;

            if (standaloneExport || asBuildingElement)
            {
                partExportLevel = partElement.LevelId;
            }
            else
            {
                if (part.OriginalCategoryId != hostElement.Category.Id)
                {
                    return;
                }
                partExportLevel = hostElement.LevelId;
            }
            if (overrideLevelId != null)
            {
                partExportLevel = overrideLevelId;
            }

            if (ExporterCacheManager.PartExportedCache.HasExported(partElement.Id, partExportLevel))
            {
                return;
            }

            Options options   = GeometryUtil.GetIFCExportGeometryOptions();
            View    ownerView = partElement.Document.GetElement(partElement.OwnerViewId) as View;

            if (ownerView != null)
            {
                options.View = ownerView;
            }

            GeometryElement geometryElement = partElement.get_Geometry(options);

            if (geometryElement == null)
            {
                return;
            }

            try
            {
                IFCFile file = exporterIFC.GetFile();
                using (IFCTransaction transaction = new IFCTransaction(file))
                {
                    IFCAnyHandle partPlacement = null;
                    if (standaloneExport || asBuildingElement)
                    {
                        Transform orientationTrf = Transform.Identity;
                        standalonePlacementSetter = PlacementSetter.Create(exporterIFC, partElement, null, orientationTrf, partExportLevel);
                        partPlacement             = standalonePlacementSetter.LocalPlacement;
                    }
                    else
                    {
                        partPlacement = ExporterUtil.CreateLocalPlacement(file, originalPlacement, null);
                    }

                    bool validRange = (range != null && !MathUtil.IsAlmostZero(range.Start - range.End));

                    SolidMeshGeometryInfo solidMeshInfo;
                    if (validRange)
                    {
                        solidMeshInfo = GeometryUtil.GetSplitClippedSolidMeshGeometry(geometryElement, range);
                        if (solidMeshInfo.GetSolids().Count == 0 && solidMeshInfo.GetMeshes().Count == 0)
                        {
                            return;
                        }
                    }
                    else
                    {
                        solidMeshInfo = GeometryUtil.GetSplitSolidMeshGeometry(geometryElement);
                    }

                    using (IFCExtrusionCreationData extrusionCreationData = new IFCExtrusionCreationData())
                    {
                        extrusionCreationData.SetLocalPlacement(partPlacement);
                        extrusionCreationData.ReuseLocalPlacement   = false;
                        extrusionCreationData.PossibleExtrusionAxes = ifcExtrusionAxes;

                        IList <Solid> solids = solidMeshInfo.GetSolids();
                        IList <Mesh>  meshes = solidMeshInfo.GetMeshes();

                        ElementId catId     = CategoryUtil.GetSafeCategoryId(partElement);
                        ElementId hostCatId = CategoryUtil.GetSafeCategoryId(hostElement);

                        BodyData            bodyData            = null;
                        BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true, ExportOptionsCache.ExportTessellationLevel.ExtraLow);
                        if (solids.Count > 0 || meshes.Count > 0)
                        {
                            bodyData = BodyExporter.ExportBody(exporterIFC, partElement, catId, ElementId.InvalidElementId, solids, meshes,
                                                               bodyExporterOptions, extrusionCreationData);
                        }
                        else
                        {
                            IList <GeometryObject> geomlist = new List <GeometryObject>();
                            geomlist.Add(geometryElement);
                            bodyData = BodyExporter.ExportBody(exporterIFC, partElement, catId, ElementId.InvalidElementId, geomlist,
                                                               bodyExporterOptions, extrusionCreationData);
                        }

                        IFCAnyHandle bodyRep = bodyData.RepresentationHnd;
                        if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep))
                        {
                            extrusionCreationData.ClearOpenings();
                            return;
                        }

                        IList <IFCAnyHandle> representations = new List <IFCAnyHandle>();
                        representations.Add(bodyRep);

                        IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geometryElement, Transform.Identity);
                        if (boundingBoxRep != null)
                        {
                            representations.Add(boundingBoxRep);
                        }

                        IFCAnyHandle prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations);

                        IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle;

                        string partGUID        = GUIDUtil.CreateGUID(partElement);
                        string partName        = NamingUtil.GetNameOverride(partElement, NamingUtil.GetIFCName(partElement));
                        string partDescription = NamingUtil.GetDescriptionOverride(partElement, null);
                        string partObjectType  = NamingUtil.GetObjectTypeOverride(partElement, NamingUtil.CreateIFCObjectName(exporterIFC, partElement));
                        string partTag         = NamingUtil.GetTagOverride(partElement, NamingUtil.CreateIFCElementId(partElement));

                        IFCAnyHandle ifcPart = null;
                        if (!asBuildingElement)
                        {
                            ifcPart = IFCInstanceExporter.CreateBuildingElementPart(file, partGUID, ownerHistory, partName, partDescription,
                                                                                    partObjectType, extrusionCreationData.GetLocalPlacement(), prodRep, partTag);
                        }
                        else
                        {
                            string        ifcEnumType = null;
                            IFCExportType exportType  = ExporterUtil.GetExportType(exporterIFC, hostElement, out ifcEnumType);

                            string defaultValue = null;
                            // This replicates old functionality before IFC4 addition, where the default for slab was "FLOOR".
                            // Really the export layer table should be fixed for this case.
                            if (string.IsNullOrWhiteSpace(ifcEnumType) && hostCatId == new ElementId(BuiltInCategory.OST_Floors))
                            {
                                ifcEnumType = "FLOOR";
                            }
                            ifcEnumType = IFCValidateEntry.GetValidIFCType(hostElement, ifcEnumType, defaultValue);

                            switch (exportType)
                            {
                            case IFCExportType.IfcColumnType:
                                ifcPart = IFCInstanceExporter.CreateColumn(file, partGUID, ownerHistory, partName, partDescription, partObjectType,
                                                                           extrusionCreationData.GetLocalPlacement(), prodRep, partTag, ifcEnumType);
                                break;

                            case IFCExportType.IfcCovering:
                                ifcPart = IFCInstanceExporter.CreateCovering(file, partGUID, ownerHistory, partName, partDescription, partObjectType,
                                                                             extrusionCreationData.GetLocalPlacement(), prodRep, partTag, ifcEnumType);
                                break;

                            case IFCExportType.IfcFooting:
                                ifcPart = IFCInstanceExporter.CreateFooting(file, partGUID, ownerHistory, partName, partDescription, partObjectType,
                                                                            extrusionCreationData.GetLocalPlacement(), prodRep, partTag, ifcEnumType);
                                break;

                            case IFCExportType.IfcPile:
                                ifcPart = IFCInstanceExporter.CreatePile(file, partGUID, ownerHistory, partName, partDescription, partObjectType,
                                                                         extrusionCreationData.GetLocalPlacement(), prodRep, partTag, ifcEnumType, null);
                                break;

                            case IFCExportType.IfcRoof:
                                ifcPart = IFCInstanceExporter.CreateRoof(file, partGUID, ownerHistory, partName, partDescription, partObjectType,
                                                                         extrusionCreationData.GetLocalPlacement(), prodRep, partTag, ifcEnumType);
                                break;

                            case IFCExportType.IfcSlab:
                                ifcPart = IFCInstanceExporter.CreateSlab(file, partGUID, ownerHistory, partName, partDescription, partObjectType,
                                                                         extrusionCreationData.GetLocalPlacement(), prodRep, partTag, ifcEnumType);
                                break;

                            case IFCExportType.IfcWall:
                                ifcPart = IFCInstanceExporter.CreateWall(file, partGUID, ownerHistory, partName, partDescription, partObjectType,
                                                                         extrusionCreationData.GetLocalPlacement(), prodRep, partTag, ifcEnumType);
                                break;

                            default:
                                ifcPart = IFCInstanceExporter.CreateBuildingElementProxy(file, partGUID, ownerHistory, partName, partDescription,
                                                                                         partObjectType, extrusionCreationData.GetLocalPlacement(), prodRep, partTag, null);
                                break;
                            }
                        }

                        bool            containedInLevel     = (standaloneExport || asBuildingElement);
                        PlacementSetter whichPlacementSetter = containedInLevel ? standalonePlacementSetter : placementSetter;
                        productWrapper.AddElement(partElement, ifcPart, whichPlacementSetter, extrusionCreationData, containedInLevel);

                        OpeningUtil.CreateOpeningsIfNecessary(ifcPart, partElement, extrusionCreationData, bodyData.OffsetTransform, exporterIFC,
                                                              extrusionCreationData.GetLocalPlacement(), whichPlacementSetter, productWrapper);

                        //Add the exported part to exported cache.
                        TraceExportedParts(partElement, partExportLevel, standaloneExport || asBuildingElement ? ElementId.InvalidElementId : hostElement.Id);

                        CategoryUtil.CreateMaterialAssociation(exporterIFC, ifcPart, bodyData.MaterialIds);

                        transaction.Commit();
                    }
                }
            }
            finally
            {
                if (standalonePlacementSetter != null)
                {
                    standalonePlacementSetter.Dispose();
                }
            }
        }
Example #44
0
        /// <summary>
        /// Adds openings to an element.
        /// </summary>
        /// <param name="exporterIFC">The exporter.</param>
        /// <param name="elementHandles">The parent handles.</param>
        /// <param name="curveLoops">The parent CurveLoops.</param>
        /// <param name="element">The element.</param>
        /// <param name="plane">The plane.</param>
        /// <param name="scaledWidth">The width.</param>
        /// <param name="range">The range.</param>
        /// <param name="setter">The placement setter.</param>
        /// <param name="localPlacement">The local placement.</param>
        /// <param name="localWrapper">The wrapper.</param>
        public static void AddOpeningsToElement(ExporterIFC exporterIFC, IList<IFCAnyHandle> elementHandles, IList<CurveLoop> curveLoops, Element element, Plane plane, double scaledWidth,
            IFCRange range, PlacementSetter setter, IFCAnyHandle localPlacement, ProductWrapper localWrapper)
        {
            IList<IFCOpeningData> openingDataList = ExporterIFCUtils.GetOpeningData(exporterIFC, element, plane, range);
            IFCFile file = exporterIFC.GetFile();
            IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle();
            foreach (IFCOpeningData openingData in openingDataList)
            {
                Element openingElem = element.Document.GetElement(openingData.OpeningElementId);
                if (openingElem == null)
                    openingElem = element;

                // Don't export the opening if WallSweep category has been turned off.
                // This is currently restricted to WallSweeps because the element responsible for the opening could be a variety of things, including a line as part of the elevation profile of the wall.
                // As such, we will restrict which element types we check for CanExportElement.
                if ((openingElem is WallSweep) && (!ElementFilteringUtil.CanExportElement(exporterIFC, openingElem, true)))
                    continue;

                IList<IFCExtrusionData> extrusionDataList = openingData.GetExtrusionData();
                IFCAnyHandle parentHandle = null;
                if (elementHandles.Count > 1 && extrusionDataList.Count > 0)
                {
                    parentHandle = FindParentHandle(elementHandles, curveLoops, extrusionDataList[0].GetLoops()[0]);
                }

                if (parentHandle == null)
                    parentHandle = elementHandles[0];

                bool isDoorOrWindowOpening = IsDoorOrWindowOpening(exporterIFC, openingElem, element);
                if (isDoorOrWindowOpening)
                {
                    DoorWindowDelayedOpeningCreator delayedCreator = 
                        DoorWindowDelayedOpeningCreator.Create(exporterIFC, openingData, scaledWidth, element.Id, parentHandle, setter.LevelId);
                    if (delayedCreator != null)
                    {
                        ExporterCacheManager.DoorWindowDelayedOpeningCreatorCache.Add(delayedCreator);
                        continue;
                    }
                }

                bool canUseElementGUID = !isDoorOrWindowOpening;

                IList<Solid> solids = openingData.GetOpeningSolids();
                foreach (Solid solid in solids)
                {
                    using (IFCExtrusionCreationData extrusionCreationData = new IFCExtrusionCreationData())
                    {
                        extrusionCreationData.SetLocalPlacement(ExporterUtil.CreateLocalPlacement(file, localPlacement, null));
                        extrusionCreationData.ReuseLocalPlacement = true;

                        string openingGUID = null;
                        if (canUseElementGUID)
                        {
                            openingGUID = GUIDUtil.CreateGUID(openingElem);
                            canUseElementGUID = false;
                        }
                        else
                            openingGUID = GUIDUtil.CreateGUID();
                        CreateOpening(exporterIFC, parentHandle, element, openingElem, openingGUID, solid, scaledWidth, openingData.IsRecess, extrusionCreationData, 
                            setter, localWrapper);
                    }
                }

                foreach (IFCExtrusionData extrusionData in extrusionDataList)
                {
                    if (extrusionData.ScaledExtrusionLength < MathUtil.Eps())
                        extrusionData.ScaledExtrusionLength = scaledWidth;

                    string openingGUID = null;
                    if (canUseElementGUID)
                    {
                        openingGUID = GUIDUtil.CreateGUID(element);
                        canUseElementGUID = false;
                    }
                    else
                        openingGUID = GUIDUtil.CreateGUID();
                    CreateOpening(exporterIFC, parentHandle, localPlacement, element, openingElem, openingGUID, extrusionData, plane, openingData.IsRecess, 
                        setter, localWrapper);
                }
            }
        }
        /// <summary>
        /// Exports a family instance as a mapped item.
        /// </summary>
        /// <param name="exporterIFC">
        /// The ExporterIFC object.
        /// </param>
        /// <param name="familyInstance">
        /// The family instance to be exported.
        /// </param>
        /// <param name="exportType">
        /// The export type.
        /// </param>
        /// <param name="ifcEnumType">
        /// The string value represents the IFC type.
        /// </param>
        /// <param name="wrapper">
        /// The ProductWrapper.
        /// </param>
        /// <param name="overrideLevelId">
        /// The level id.
        /// </param>
        /// <param name="range">
        /// The range of this family instance to be exported.
        /// </param>
        public static void ExportFamilyInstanceAsMappedItem(ExporterIFC exporterIFC,
            FamilyInstance familyInstance, IFCExportType exportType, string ifcEnumType,
            ProductWrapper wrapper, ElementId overrideLevelId, IFCRange range, IFCAnyHandle parentLocalPlacement)
        {
            bool exportParts = PartExporter.CanExportParts(familyInstance);
            bool isSplit = range != null;
            if (exportParts && !PartExporter.CanExportElementInPartExport(familyInstance, isSplit ? overrideLevelId : familyInstance.Level.Id, isSplit))
                return;

            Document doc = familyInstance.Document;
            IFCFile file = exporterIFC.GetFile();

            FamilySymbol familySymbol = ExporterIFCUtils.GetOriginalSymbol(familyInstance);
            if (familySymbol == null)
                return;

            ProductWrapper familyProductWrapper = ProductWrapper.Create(wrapper);
            double scale = exporterIFC.LinearScale;
            Options options = GeometryUtil.GetIFCExportGeometryOptions();

            IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle();

            HostObject hostElement = familyInstance.Host as HostObject; //hostElement could be null
            ElementId categoryId = CategoryUtil.GetSafeCategoryId(familySymbol);

            //string emptyString = "";
            string familyName = familySymbol.Name;
            string objectType = familyName;

            // A Family Instance can have its own copy of geometry, or use the symbol's copy with a transform.
            // The routine below tells us whether to use the Instance's copy or the Symbol's copy.
            bool useInstanceGeometry = ExporterIFCUtils.UsesInstanceGeometry(familyInstance);

            IList<IFCExtrusionData> cutPairOpeningsForColumns = new List<IFCExtrusionData>();
            using (IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData())
            {
                Transform trf = familyInstance.GetTransform();

                // Extra information if we are exporting a door or a window.
                IFCDoorWindowInfo doorWindowInfo = null;
                if (exportType == IFCExportType.ExportDoorType)
                    doorWindowInfo = IFCDoorWindowInfo.CreateDoorInfo(exporterIFC, familyInstance, familySymbol, hostElement, overrideLevelId, trf);
                else if (exportType == IFCExportType.ExportWindowType)
                    doorWindowInfo = IFCDoorWindowInfo.CreateWindowInfo(exporterIFC, familyInstance, familySymbol, hostElement, overrideLevelId, trf);

                FamilyTypeInfo typeInfo = new FamilyTypeInfo();
                XYZ extraOffset = XYZ.Zero;

                bool flipped = doorWindowInfo != null ? doorWindowInfo.IsSymbolFlipped : false;
                FamilyTypeInfo currentTypeInfo = ExporterCacheManager.TypeObjectsCache.Find(familySymbol.Id, flipped);
                bool found = currentTypeInfo.IsValid();

                Family family = familySymbol.Family;

                // TODO: this code to be removed by ExtrusionAnalyzer code.
                bool trySpecialColumnCreation = ((exportType == IFCExportType.ExportColumnType) && (!family.IsInPlace));
                IList<GeometryObject> geomObjects = new List<GeometryObject>();
                Transform brepOffsetTransform = null;

                Transform doorWindowTrf = Transform.Identity;
                // We will create a new mapped type if:
                // 1.  We are exporting part of a column or in-place wall (range != null), OR
                // 2.  We are using the instance's copy of the geometry (that it, it has unique geometry), OR
                // 3.  We haven't already created the type.
                bool creatingType = ((range != null) || useInstanceGeometry || !found);
                if (creatingType)
                {
                    IFCAnyHandle bodyRepresentation = null;
                    IFCAnyHandle planRepresentation = null;

                    // If we are using the instance geometry, ignore the transformation.
                    if (useInstanceGeometry)
                        trf = Transform.Identity;

                    // TODO: this code to be removed by ExtrusionAnalyzer code.
                    if (trySpecialColumnCreation)
                    {
                        XYZ rangeOffset = trf.Origin;
                        IFCFamilyInstanceExtrusionExportResults results;

                        results = ExporterIFCUtils.ExportFamilyInstanceAsExtrusion(exporterIFC, familyInstance, useInstanceGeometry, range, overrideLevelId, extraParams);

                        bodyRepresentation = results.GetExtrusionHandle();
                        extraOffset = results.ExtraOffset;
                        cutPairOpeningsForColumns = results.GetCutPairOpenings();

                        if (!IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRepresentation))
                        {
                            typeInfo.MaterialIds.Add(results.MaterialId);
                            // add in level for real columns, not in-place ones.
                            Element actualLevel =
                               (overrideLevelId == ElementId.InvalidElementId) ? familyInstance.Level : doc.GetElement(overrideLevelId);
                            if (actualLevel != null)
                            {
                                IFCLevelInfo levelInfo = exporterIFC.GetLevelInfo(actualLevel.Id);
                                double nonStoryLevelOffset = LevelUtil.GetNonStoryLevelOffsetIfAny(exporterIFC, actualLevel as Level);
                                if (range != null)
                                {
                                    rangeOffset = new XYZ(rangeOffset.X, rangeOffset.Y, levelInfo.Elevation + nonStoryLevelOffset);
                                }
                            }
                        }

                        rangeOffset += extraOffset;
                        trf.Origin = rangeOffset;
                    }

                    IFCAnyHandle dummyPlacement = null;
                    if (doorWindowInfo != null)
                    {
                        doorWindowTrf = ExporterIFCUtils.GetTransformForDoorOrWindow(familyInstance, familySymbol, doorWindowInfo);
                    }
                    else
                    {
                        dummyPlacement = IFCInstanceExporter.CreateLocalPlacement(file, null, ExporterUtil.CreateAxis2Placement3D(file));
                        extraParams.SetLocalPlacement(dummyPlacement);
                    }

                    bool needToCreate2d = ExporterCacheManager.ExportOptionsCache.ExportAnnotations;
                    bool needToCreate3d = IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRepresentation);

                    if (needToCreate2d || needToCreate3d)
                    {
                        using (IFCTransformSetter trfSetter = IFCTransformSetter.Create())
                        {
                            if (doorWindowInfo != null)
                            {
                                trfSetter.Initialize(exporterIFC, doorWindowTrf);
                            }

                            GeometryElement exportGeometry =
                               useInstanceGeometry ? familyInstance.get_Geometry(options) : familySymbol.get_Geometry(options);
                            if (exportGeometry == null)
                                return;

                            if (needToCreate3d)
                            {
                                SolidMeshGeometryInfo solidMeshCapsule = null;

                                if (range == null)
                                {
                                    solidMeshCapsule = GeometryUtil.GetSolidMeshGeometry(exportGeometry, Transform.Identity);
                                }
                                else
                                {
                                    solidMeshCapsule = GeometryUtil.GetClippedSolidMeshGeometry(exportGeometry, range);
                                }

                                IList<Solid> solids = solidMeshCapsule.GetSolids();
                                IList<Mesh> polyMeshes = solidMeshCapsule.GetMeshes();

                                if (range != null && (solids.Count == 0 && polyMeshes.Count == 0))
                                    return; // no proper split geometry

                                geomObjects = FamilyExporterUtil.RemoveSolidsAndMeshesSetToDontExport(doc, exporterIFC, solids, polyMeshes);
                                if (geomObjects.Count == 0 && (solids.Count > 0 || polyMeshes.Count > 0))
                                    return;

                                bool tryToExportAsExtrusion = (!exporterIFC.ExportAs2x2 || (exportType == IFCExportType.ExportColumnType));

                                if (exportType == IFCExportType.ExportColumnType)
                                {
                                    extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ;

                                    if (ExporterCacheManager.ExportOptionsCache.ExportAs2x3CoordinationView2 &&
                                        solids.Count > 0)
                                    {
                                        LocationPoint point = familyInstance.Location as LocationPoint;
                                        XYZ orig = XYZ.Zero;
                                        if (point != null)
                                            orig = point.Point;

                                        Plane plane = new Plane(XYZ.BasisX, XYZ.BasisY, orig);
                                        bool completelyClipped = false;
                                        HashSet<ElementId> materialIds = null;
                                        bodyRepresentation = ExtrusionExporter.CreateExtrusionWithClipping(exporterIFC, familyInstance,
                                            categoryId, solids, plane, XYZ.BasisZ, null, out completelyClipped, out materialIds);
                                        typeInfo.MaterialIds = materialIds;
                                    }
                                }
                                else
                                {
                                    extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryXYZ;
                                }

                                BodyData bodyData = null;
                                if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRepresentation))
                                {
                                    BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(tryToExportAsExtrusion);
                                    if (geomObjects.Count > 0)
                                    {
                                        bodyData = BodyExporter.ExportBody(familyInstance.Document.Application, exporterIFC, familyInstance, categoryId, ElementId.InvalidElementId,
                                            geomObjects, bodyExporterOptions, extraParams);
                                        typeInfo.MaterialIds = bodyData.MaterialIds;
                                    }
                                    else
                                    {
                                        IList<GeometryObject> exportedGeometries = new List<GeometryObject>();
                                        exportedGeometries.Add(exportGeometry);
                                        bodyData = BodyExporter.ExportBody(familyInstance.Document.Application, exporterIFC, familyInstance, categoryId, ElementId.InvalidElementId,
                                            exportedGeometries, bodyExporterOptions, extraParams);
                                    }
                                    bodyRepresentation = bodyData.RepresentationHnd;
                                    brepOffsetTransform = bodyData.BrepOffsetTransform;
                                }

                                if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRepresentation))
                                {
                                    extraParams.ClearOpenings();
                                    return;
                                }
                            }

                            // By default: if exporting IFC2x3 or later, export 2D plan rep of family, if it exists, unless we are exporting Coordination View V2.
                            // This default can be overridden in the export options.
                            if (needToCreate2d)
                            {
                                XYZ curveOffset = new XYZ(0, 0, 0);
                                if (brepOffsetTransform != null)
                                    curveOffset = -brepOffsetTransform.Origin / scale;

                                HashSet<IFCAnyHandle> curveSet = new HashSet<IFCAnyHandle>();
                                {
                                    Transform planeTrf = doorWindowTrf.Inverse;
                                    Plane plane = new Plane(planeTrf.get_Basis(0), planeTrf.get_Basis(1), planeTrf.Origin);
                                    XYZ projDir = new XYZ(0, 0, 1);

                                    IFCGeometryInfo IFCGeometryInfo = IFCGeometryInfo.CreateCurveGeometryInfo(exporterIFC, plane, projDir, true);
                                    ExporterIFCUtils.CollectGeometryInfo(exporterIFC, IFCGeometryInfo, exportGeometry, curveOffset, false);

                                    IList<IFCAnyHandle> curves = IFCGeometryInfo.GetCurves();
                                    foreach (IFCAnyHandle curve in curves)
                                        curveSet.Add(curve);

                                    if (curveSet.Count > 0)
                                    {
                                        IFCAnyHandle contextOfItems2d = exporterIFC.Get2DContextHandle();
                                        IFCAnyHandle curveRepresentationItem = IFCInstanceExporter.CreateGeometricSet(file, curveSet);
                                        HashSet<IFCAnyHandle> bodyItems = new HashSet<IFCAnyHandle>();
                                        bodyItems.Add(curveRepresentationItem);
                                        planRepresentation = RepresentationUtil.CreateGeometricSetRep(exporterIFC, familyInstance, categoryId, "Annotation",
                                           contextOfItems2d, bodyItems);
                                    }
                                }
                            }
                        }
                    }

                    if (doorWindowInfo != null)
                    {
                        typeInfo.StyleTransform = doorWindowTrf.Inverse;
                    }
                    else
                    {
                        if (!MathUtil.IsAlmostZero(extraOffset.DotProduct(extraOffset)))
                        {
                            Transform newTransform = typeInfo.StyleTransform;
                            XYZ newOrig = newTransform.Origin + extraOffset;
                            newTransform.Origin = newOrig;
                            typeInfo.StyleTransform = newTransform;
                        }
                        typeInfo.StyleTransform = ExporterIFCUtils.GetUnscaledTransform(exporterIFC, extraParams.GetLocalPlacement());
                    }

                    IFCAnyHandle origin = ExporterUtil.CreateAxis2Placement3D(file);
                    IFCAnyHandle repMap2dHnd = null;
                    IFCAnyHandle repMap3dHnd = IFCInstanceExporter.CreateRepresentationMap(file, origin, bodyRepresentation);

                    IList<IFCAnyHandle> repMapList = new List<IFCAnyHandle>();
                    repMapList.Add(repMap3dHnd);
                    if (!IFCAnyHandleUtil.IsNullOrHasNoValue(planRepresentation))
                    {
                        repMap2dHnd = IFCInstanceExporter.CreateRepresentationMap(file, origin, planRepresentation);
                        repMapList.Add(repMap2dHnd);
                    }

                    // for Door, Window
                    bool paramTakesPrecedence = false; // For Revit, this is currently always false.
                    bool sizeable = false;

                    // for many
                    HashSet<IFCAnyHandle> propertySets = new HashSet<IFCAnyHandle>();

                    string guid = GUIDUtil.CreateGUID(familySymbol);
                    string symId = NamingUtil.CreateIFCElementId(familySymbol);

                    // This covers many generic types.  If we can't find it in the list here, do custom exports.
                    IFCAnyHandle typeStyle = FamilyExporterUtil.ExportGenericType(file, exportType, ifcEnumType, guid,
                       ownerHistory, objectType, null, null, propertySets, repMapList, symId, objectType,
                       familyInstance, familySymbol);

                    // Cover special cases not covered above.
                    if (IFCAnyHandleUtil.IsNullOrHasNoValue(typeStyle))
                    {
                        switch (exportType)
                        {
                            case IFCExportType.ExportColumnType:
                                {
                                    // If we are using the instance GRep, then we have to create a generic GUID for the
                                    // column type, as they share the same ElementId.
                                    string colGUID = null;
                                    string colElemId = null;

                                    if (useInstanceGeometry)
                                        colGUID = GUIDUtil.CreateGUID();
                                    else
                                        colGUID = guid;
                                    colElemId = NamingUtil.CreateIFCElementId(familySymbol);

                                    string columnType = "Column";
                                    typeStyle = IFCInstanceExporter.CreateColumnType(file, colGUID, ownerHistory, objectType,
                                       null, null, propertySets, repMapList, colElemId,
                                       objectType, GetColumnType(familyInstance, columnType));

                                    break;
                                }
                            case IFCExportType.ExportDoorType:
                                {
                                    string constructionType = string.Empty;
                                    ParameterUtil.GetStringValueFromElementOrSymbol(familyInstance, "Construction", out constructionType);

                                    IFCAnyHandle doorLining = DoorWindowUtil.CreateDoorLiningProperties(exporterIFC, familyInstance);
                                    if (!IFCAnyHandleUtil.IsNullOrHasNoValue(doorLining))
                                        propertySets.Add(doorLining);

                                    IList<IFCAnyHandle> doorPanels = DoorWindowUtil.CreateDoorPanelProperties(exporterIFC, doorWindowInfo,
                                       familyInstance);
                                    propertySets.UnionWith(doorPanels);

                                    string doorStyleGUID = GUIDUtil.CreateGUID();
                                    string doorStyleElemId = NamingUtil.CreateIFCElementId(familySymbol);
                                    typeStyle = IFCInstanceExporter.CreateDoorStyle(file, doorStyleGUID, ownerHistory, objectType,
                                       null, null, propertySets, repMapList, doorStyleElemId,
                                       GetDoorStyleOperation(doorWindowInfo.DoorOperationType), GetDoorStyleConstruction(familyInstance, constructionType),
                                       paramTakesPrecedence, sizeable);
                                    break;
                                }
                            case IFCExportType.ExportSystemFurnitureElementType:
                                {
                                    string furnitureId = NamingUtil.CreateIFCElementId(familySymbol);
                                    typeStyle = IFCInstanceExporter.CreateSystemFurnitureElementType(file, guid, ownerHistory, objectType,
                                       null, null, propertySets, repMapList, furnitureId,
                                       objectType);
                                    break;
                                }
                            case IFCExportType.ExportWindowType:
                                {
                                    Toolkit.IFCWindowStyleOperation operationType = DoorWindowUtil.GetIFCWindowStyleOperation(familySymbol);
                                    IFCWindowStyleConstruction constructionType = DoorWindowUtil.GetIFCWindowStyleConstruction(familyInstance, "");

                                    IFCAnyHandle windowLining = DoorWindowUtil.CreateWindowLiningProperties(exporterIFC, familyInstance, null);
                                    if (!IFCAnyHandleUtil.IsNullOrHasNoValue(windowLining))
                                        propertySets.Add(windowLining);

                                    IList<IFCAnyHandle> windowPanels =
                                       DoorWindowUtil.CreateWindowPanelProperties(exporterIFC, familyInstance, null);
                                    propertySets.UnionWith(windowPanels);

                                    string windowStyleGUID = GUIDUtil.CreateGUID();
                                    string windowStyleElemId = NamingUtil.CreateIFCElementId(familySymbol);
                                    typeStyle = IFCInstanceExporter.CreateWindowStyle(file, windowStyleGUID, ownerHistory, objectType,
                                       null, null, propertySets, repMapList, windowStyleElemId,
                                       constructionType, operationType, paramTakesPrecedence, sizeable);
                                    break;
                                }
                            case IFCExportType.ExportBuildingElementProxy:
                            default:
                                {
                                    if (!IFCAnyHandleUtil.IsNullOrHasNoValue(repMap2dHnd))
                                        typeInfo.Map2DHandle = repMap2dHnd;
                                    if (!IFCAnyHandleUtil.IsNullOrHasNoValue(repMap3dHnd))
                                        typeInfo.Map3DHandle = repMap3dHnd;
                                    break;
                                }
                        }
                    }

                    if (!IFCAnyHandleUtil.IsNullOrHasNoValue(typeStyle))
                    {
                        CategoryUtil.CreateMaterialAssociations(doc, exporterIFC, typeStyle, typeInfo.MaterialIds);

                        typeInfo.Style = typeStyle;

                        if (((exportType == IFCExportType.ExportColumnType) && trySpecialColumnCreation) ||
                           (exportType == IFCExportType.ExportMemberType))
                        {
                            typeInfo.ScaledArea = extraParams.ScaledArea;
                            typeInfo.ScaledDepth = extraParams.ScaledLength;
                            typeInfo.ScaledInnerPerimeter = extraParams.ScaledInnerPerimeter;
                            typeInfo.ScaledOuterPerimeter = extraParams.ScaledOuterPerimeter;
                        }

                        ClassificationUtil.CreateUniformatClassification(exporterIFC, file, familySymbol, typeStyle);
                    }
                }
                else if (!creatingType && (trySpecialColumnCreation))
                {
                    // still need to modify instance trf for columns.
                    trf.Origin += GetLevelOffsetForExtrudedColumns(exporterIFC, familyInstance, overrideLevelId, extraParams);
                }

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

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

                // add to the map, as long as we are not using range, not using instance geometry, and don't have extra openings.
                if ((range == null) && !useInstanceGeometry && (extraParams.GetOpenings().Count == 0))
                    ExporterCacheManager.TypeObjectsCache.Register(familySymbol.Id, flipped, typeInfo);

                Transform oldTrf = new Transform(trf);
                XYZ scaledMapOrigin = XYZ.Zero;

                trf = trf.Multiply(typeInfo.StyleTransform);

                // create instance.
                IList<IFCAnyHandle> shapeReps = new List<IFCAnyHandle>();
                {
                    IFCAnyHandle contextOfItems2d = exporterIFC.Get2DContextHandle();
                    IFCAnyHandle contextOfItems3d = exporterIFC.Get3DContextHandle("Body");

                    // for proxies, we store the IfcRepresentationMap directly since there is no style.
                    IFCAnyHandle style = typeInfo.Style;
                    IList<IFCAnyHandle> repMapList = !IFCAnyHandleUtil.IsNullOrHasNoValue(style) ?
                        GeometryUtil.GetRepresentationMaps(style) : null;
                    int numReps = repMapList != null ? repMapList.Count : 0;

                    IFCAnyHandle repMap2dHnd = typeInfo.Map2DHandle;
                    IFCAnyHandle repMap3dHnd = typeInfo.Map3DHandle;
                    if (IFCAnyHandleUtil.IsNullOrHasNoValue(repMap3dHnd) && (numReps > 0))
                        repMap3dHnd = repMapList[0];
                    if (IFCAnyHandleUtil.IsNullOrHasNoValue(repMap2dHnd) && (numReps > 1))
                        repMap2dHnd = repMapList[1];

                    if (!IFCAnyHandleUtil.IsNullOrHasNoValue(repMap3dHnd))
                    {
                        IList<IFCAnyHandle> representations = new List<IFCAnyHandle>();
                        representations.Add(ExporterUtil.CreateDefaultMappedItem(file, repMap3dHnd, scaledMapOrigin));
                        IFCAnyHandle shapeRep = RepresentationUtil.CreateBodyMappedItemRep(exporterIFC, familyInstance, categoryId, contextOfItems3d,
                            representations);
                        if (IFCAnyHandleUtil.IsNullOrHasNoValue(shapeRep))
                            return;
                        shapeReps.Add(shapeRep);
                    }

                    if (!IFCAnyHandleUtil.IsNullOrHasNoValue(repMap2dHnd))
                    {
                        HashSet<IFCAnyHandle> representations = new HashSet<IFCAnyHandle>();
                        representations.Add(ExporterUtil.CreateDefaultMappedItem(file, repMap2dHnd, scaledMapOrigin));
                        IFCAnyHandle shapeRep = RepresentationUtil.CreatePlanMappedItemRep(exporterIFC, familyInstance, categoryId, contextOfItems2d,
                            representations);
                        if (IFCAnyHandleUtil.IsNullOrHasNoValue(shapeRep))
                            return;
                        shapeReps.Add(shapeRep);
                    }
                }

                IFCAnyHandle boundingBoxRep = null;
                Transform boundingBoxTrf = (brepOffsetTransform != null) ? brepOffsetTransform.Inverse : Transform.Identity;
                if (geomObjects.Count > 0)
                    boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geomObjects, boundingBoxTrf);
                else
                {
                    boundingBoxTrf = boundingBoxTrf.Multiply(trf.Inverse);
                    boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, familyInstance.get_Geometry(options), boundingBoxTrf);
                }

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

                IFCAnyHandle rep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, shapeReps);

                IFCAnyHandle instanceHandle = null;
                using (IFCPlacementSetter setter = IFCPlacementSetter.Create(exporterIFC, familyInstance, trf, null, overrideLevelId))
                {
                    string instanceGUID = GUIDUtil.CreateGUID(familyInstance);
                    string instanceName = NamingUtil.GetIFCName(familyInstance);
                    string instanceDescription = NamingUtil.GetDescriptionOverride(familyInstance, null);
                    string instanceObjectType = NamingUtil.GetObjectTypeOverride(familyInstance, objectType);
                    string instanceElemId = NamingUtil.CreateIFCElementId(familyInstance);

                    IFCAnyHandle localPlacement = setter.GetPlacement();
                    IFCAnyHandle overrideLocalPlacement = null;

                    if (parentLocalPlacement != null)
                    {
                        Transform relTrf = ExporterIFCUtils.GetRelativeLocalPlacementOffsetTransform(parentLocalPlacement, localPlacement);
                        Transform inverseTrf = relTrf.Inverse;

                        IFCAnyHandle relativePlacement = ExporterUtil.CreateAxis2Placement3D(file, inverseTrf.Origin, inverseTrf.BasisZ, inverseTrf.BasisX);
                        IFCAnyHandle plateLocalPlacement = IFCInstanceExporter.CreateLocalPlacement(file, parentLocalPlacement, relativePlacement);
                        overrideLocalPlacement = plateLocalPlacement;
                    }

                    instanceHandle = FamilyExporterUtil.ExportGenericInstance(exportType, exporterIFC, familyInstance,
                       wrapper, setter, extraParams, instanceGUID, ownerHistory, instanceName, instanceDescription, instanceObjectType,
                       exportParts ? null : rep, instanceElemId, overrideLocalPlacement);

                    if (exportParts)
                    {
                        PartExporter.ExportHostPart(exporterIFC, familyInstance, instanceHandle, familyProductWrapper, setter, setter.GetPlacement(), overrideLevelId);
                    }

                    if (ElementFilteringUtil.IsMEPType(exportType))
                        ExporterCacheManager.MEPCache.Register(familyInstance, instanceHandle);

                    switch (exportType)
                    {
                        case IFCExportType.ExportColumnType:
                            {
                                IFCAnyHandle placementToUse = localPlacement;
                                if (!useInstanceGeometry)
                                {
                                    bool needToCreateOpenings =
                                        (cutPairOpeningsForColumns.Count != 0) || OpeningUtil.NeedToCreateOpenings(instanceHandle, extraParams);
                                    if (needToCreateOpenings)
                                    {
                                        Transform openingTrf = new Transform(oldTrf);
                                        Transform extraRot = new Transform(oldTrf);
                                        extraRot.Origin = XYZ.Zero;
                                        openingTrf = openingTrf.Multiply(extraRot);
                                        openingTrf = openingTrf.Multiply(typeInfo.StyleTransform);

                                        IFCAnyHandle openingRelativePlacement = ExporterUtil.CreateAxis2Placement3D(file, openingTrf.Origin * scale,
                                           openingTrf.get_Basis(2), openingTrf.get_Basis(0));
                                        IFCAnyHandle openingPlacement = ExporterUtil.CopyLocalPlacement(file, localPlacement);
                                        GeometryUtil.SetRelativePlacement(openingPlacement, openingRelativePlacement);
                                        placementToUse = openingPlacement;
                                    }
                                }

                                OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, cutPairOpeningsForColumns,
                                   exporterIFC, placementToUse, setter, wrapper);
                                OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, extraParams, exporterIFC,
                                   placementToUse, setter, wrapper);

                                //export Base Quantities.
                                PropertyUtil.CreateBeamColumnBaseQuantities(exporterIFC, instanceHandle, familyInstance, typeInfo);

                                PropertyUtil.CreateInternalRevitPropertySets(exporterIFC, familyInstance, wrapper);
                                break;
                            }
                        case IFCExportType.ExportDoorType:
                        case IFCExportType.ExportWindowType:
                            {
                                double doorHeight = doorWindowInfo.OpeningHeight;
                                if (doorHeight < MathUtil.Eps())
                                    doorHeight = GetMinSymbolHeight(familySymbol);
                                double doorWidth = doorWindowInfo.OpeningWidth;
                                if (doorWidth < MathUtil.Eps())
                                    doorWidth = GetMinSymbolWidth(familySymbol);

                                double height = doorHeight * scale;
                                double width = doorWidth * scale;

                                if (IFCAnyHandleUtil.IsNullOrHasNoValue(doorWindowInfo.GetLocalPlacement()))
                                    doorWindowInfo.SetLocalPlacement(localPlacement);

                                IFCAnyHandle doorWindowOrigLocalPlacement = doorWindowInfo.GetLocalPlacement();
                                Transform relTrf = ExporterIFCUtils.GetRelativeLocalPlacementOffsetTransform(localPlacement, doorWindowOrigLocalPlacement);

                                IFCAnyHandle doorWindowRelativePlacement = ExporterUtil.CreateAxis2Placement3D(file, relTrf.Origin, relTrf.BasisZ, relTrf.BasisX);
                                IFCAnyHandle doorWindowLocalPlacement =
                                   IFCInstanceExporter.CreateLocalPlacement(file, doorWindowOrigLocalPlacement, doorWindowRelativePlacement);
                                if (exportType == IFCExportType.ExportDoorType)
                                    instanceHandle = IFCInstanceExporter.CreateDoor(file, instanceGUID, ownerHistory,
                                       instanceName, instanceDescription, instanceObjectType, doorWindowLocalPlacement,
                                       rep, instanceElemId, height, width);
                                else if (exportType == IFCExportType.ExportWindowType)
                                    instanceHandle = IFCInstanceExporter.CreateWindow(file, instanceGUID, ownerHistory,
                                       instanceName, instanceDescription, instanceObjectType, doorWindowLocalPlacement,
                                       rep, instanceElemId, height, width);
                                wrapper.AddElement(instanceHandle, setter, extraParams, true);

                                exporterIFC.RegisterSpaceBoundingElementHandle(instanceHandle, familyInstance.Id, setter.LevelId);

                                IFCAnyHandle placementToUse = doorWindowLocalPlacement;
                                if (!useInstanceGeometry)
                                {
                                    // correct the placement to the symbol space
                                    bool needToCreateOpenings = OpeningUtil.NeedToCreateOpenings(instanceHandle, extraParams);
                                    if (needToCreateOpenings)
                                    {
                                        Transform openingTrf = Transform.Identity;
                                        openingTrf.Origin = new XYZ(0, 0, setter.Offset);
                                        openingTrf = openingTrf.Multiply(doorWindowTrf);
                                        XYZ scaledOrigin = openingTrf.Origin * exporterIFC.LinearScale;
                                        IFCAnyHandle openingRelativePlacement = ExporterUtil.CreateAxis2Placement3D(file, scaledOrigin, openingTrf.BasisZ, openingTrf.BasisX);
                                        IFCAnyHandle openingLocalPlacement =
                                           IFCInstanceExporter.CreateLocalPlacement(file, doorWindowLocalPlacement, openingRelativePlacement);
                                        placementToUse = openingLocalPlacement;
                                    }
                                }
                                // only necessary when exporting as possible breps.
                                OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, extraParams, exporterIFC,
                                   placementToUse, setter, wrapper);
                                if (ExporterCacheManager.ExportOptionsCache.ExportBaseQuantities)
                                    ExporterIFCUtils.CreateDoorWindowBaseQuantities(exporterIFC, instanceHandle, (doorHeight * scale), (doorWidth * scale));

                                PropertyUtil.CreateInternalRevitPropertySets(exporterIFC, familyInstance, wrapper);
                                break;
                            }
                        case IFCExportType.ExportMemberType:
                            {
                                OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, extraParams, exporterIFC,
                                   localPlacement, setter, wrapper);

                                //export Base Quantities.
                                PropertyUtil.CreateBeamColumnBaseQuantities(exporterIFC, instanceHandle, familyInstance, typeInfo);
                                // TODO: create PropertySet!
                                //createMemberPropertySet(exporter, pFamInst, pWrapper, extraParams);
                                PropertyUtil.CreateInternalRevitPropertySets(exporterIFC, familyInstance, wrapper);
                                break;
                            }
                        case IFCExportType.ExportPlateType:
                            {
                                OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, extraParams, exporterIFC,
                                   localPlacement, setter, wrapper);

                                // TODO: create PropertySet!
                                //createPlatePropertySet(exporter, pFamInst, pWrapper, extraParams);
                                PropertyUtil.CreateInternalRevitPropertySets(exporterIFC, familyInstance, wrapper);
                                break;
                            }
                        case IFCExportType.ExportTransportElementType:
                            {
                                IFCAnyHandle localPlacementToUse;
                                ElementId roomId = setter.UpdateRoomRelativeCoordinates(familyInstance, out localPlacementToUse);

                                instanceHandle = IFCInstanceExporter.CreateTransportElement(file, instanceGUID, ownerHistory,
                                   instanceName, instanceDescription, instanceObjectType,
                                   localPlacementToUse, rep, instanceElemId, null, null, null);

                                if (roomId == ElementId.InvalidElementId)
                                {
                                    wrapper.AddElement(instanceHandle, setter, extraParams, true);
                                }
                                else
                                {
                                    exporterIFC.RelateSpatialElement(roomId, instanceHandle);
                                    wrapper.AddElement(instanceHandle, setter, extraParams, false);
                                }

                                PropertyUtil.CreateInternalRevitPropertySets(exporterIFC, familyInstance, wrapper);
                                break;
                            }
                        case IFCExportType.ExportBuildingElementProxy:
                        default:
                            {
                                bool isBuildingElementProxy = (exportType == IFCExportType.ExportBuildingElementProxy);

                                IFCAnyHandle localPlacementToUse;
                                ElementId roomId = setter.UpdateRoomRelativeCoordinates(familyInstance, out localPlacementToUse);

                                if (!isBuildingElementProxy)
                                {
                                    if (FamilyExporterUtil.IsDistributionControlElementSubType(exportType))
                                    {
                                        instanceHandle = IFCInstanceExporter.CreateDistributionControlElement(file, instanceGUID,
                                           ownerHistory, instanceName, instanceDescription, instanceObjectType,
                                           localPlacementToUse, rep, instanceElemId, null);

                                        if (roomId == ElementId.InvalidElementId)
                                        {
                                            wrapper.AddElement(instanceHandle, setter, extraParams, true);
                                        }
                                        else
                                        {
                                            exporterIFC.RelateSpatialElement(roomId, instanceHandle);
                                            wrapper.AddElement(instanceHandle, setter, extraParams, false);
                                        }
                                    }
                                    else if (IFCAnyHandleUtil.IsNullOrHasNoValue(instanceHandle))
                                    {
                                        isBuildingElementProxy = true;
                                    }
                                }

                                if (isBuildingElementProxy)
                                {
                                    Toolkit.IFCElementComposition proxyType = Toolkit.IFCElementComposition.Element;

                                    instanceHandle = IFCInstanceExporter.CreateBuildingElementProxy(file, instanceGUID,
                                       ownerHistory, instanceName, instanceDescription, instanceObjectType,
                                       localPlacementToUse, rep, instanceElemId, proxyType);

                                    if (roomId == ElementId.InvalidElementId)
                                    {
                                        wrapper.AddElement(instanceHandle, setter, extraParams, true);
                                    }
                                    else
                                    {
                                        exporterIFC.RelateSpatialElement(roomId, instanceHandle);
                                        wrapper.AddElement(instanceHandle, setter, extraParams, false);
                                    }
                                }

                                IFCAnyHandle placementToUse = localPlacement;
                                if (!useInstanceGeometry)
                                {
                                    bool needToCreateOpenings = OpeningUtil.NeedToCreateOpenings(instanceHandle, extraParams);
                                    if (needToCreateOpenings)
                                    {
                                        Transform openingTrf = new Transform(oldTrf);
                                        Transform extraRot = new Transform(oldTrf);
                                        extraRot.Origin = XYZ.Zero;
                                        openingTrf = openingTrf.Multiply(extraRot);
                                        openingTrf = openingTrf.Multiply(typeInfo.StyleTransform);

                                        IFCAnyHandle openingRelativePlacement = ExporterUtil.CreateAxis2Placement3D(file, openingTrf.Origin * scale,
                                           openingTrf.get_Basis(2), openingTrf.get_Basis(0));
                                        IFCAnyHandle openingPlacement = ExporterUtil.CopyLocalPlacement(file, localPlacement);
                                        GeometryUtil.SetRelativePlacement(openingPlacement, openingRelativePlacement);
                                        placementToUse = openingPlacement;
                                    }
                                }

                                OpeningUtil.CreateOpeningsIfNecessary(instanceHandle, familyInstance, extraParams, exporterIFC,
                                   placementToUse, setter, wrapper);
                                PropertyUtil.CreateInternalRevitPropertySets(exporterIFC, familyInstance, wrapper);
                                break;
                            }
                    }

                    if (!IFCAnyHandleUtil.IsNullOrHasNoValue(instanceHandle))
                    {
                        if (doorWindowInfo != null)
                        {
                            if (!IFCAnyHandleUtil.IsNullOrHasNoValue(doorWindowInfo.GetOpening()))
                            {
                                string relGUID = GUIDUtil.CreateGUID();
                                IFCInstanceExporter.CreateRelFillsElement(file, relGUID, ownerHistory, null, null, doorWindowInfo.GetOpening(), instanceHandle);
                            }
                            else if (doorWindowInfo.NeedsOpening)
                            {
                                bool added = doorWindowInfo.SetDelayedFamilyInstance(instanceHandle, localPlacement, doorWindowInfo.AssignedLevelId);
                                if (added)
                                    exporterIFC.RegisterDoorWindowForOpeningUpdate(doorWindowInfo);
                                else
                                {
                                    // we need to fill a later opening.
                                    exporterIFC.RegisterDoorWindowForUncreatedOpening(familyInstance.Id, instanceHandle);
                                }
                            }
                        }

                        if (!exportParts)
                            CategoryUtil.CreateMaterialAssociations(doc, exporterIFC, instanceHandle, typeInfo.MaterialIds);

                        if (!IFCAnyHandleUtil.IsNullOrHasNoValue(typeInfo.Style))
                            ExporterCacheManager.TypeRelationsCache.Add(typeInfo.Style, instanceHandle);
                    }
                }
            }
        }
Example #46
0
 /// <summary>
 /// Adds openings to an element.
 /// </summary>
 /// <param name="exporterIFC">The exporter.</param>
 /// <param name="elementHandle">The parent handle.</param>
 /// <param name="element">The element.</param>
 /// <param name="plane">The plane.</param>
 /// <param name="scaledWidth">The width.</param>
 /// <param name="range">The range.</param>
 /// <param name="setter">The placement setter.</param>
 /// <param name="localPlacement">The local placement.</param>
 /// <param name="localWrapper">The wrapper.</param>
 public static void AddOpeningsToElement(ExporterIFC exporterIFC, IFCAnyHandle elementHandle, Element element, Plane plane, double scaledWidth,
     IFCRange range, PlacementSetter setter, IFCAnyHandle localPlacement, ProductWrapper localWrapper)
 {
     IList<IFCAnyHandle> elementHandles = new List<IFCAnyHandle>();
     elementHandles.Add(elementHandle);
     AddOpeningsToElement(exporterIFC, elementHandles, null, element, plane, scaledWidth, range, setter, localPlacement, localWrapper);
 }
Example #47
0
        /// <summary>
        /// Adds openings to an element.
        /// </summary>
        /// <param name="exporterIFC">The exporter.</param>
        /// <param name="elementHandles">The parent handles.</param>
        /// <param name="curveLoops">The parent CurveLoops.</param>
        /// <param name="element">The element.</param>
        /// <param name="lcs">The local coordinate system.</param>
        /// <param name="scaledWidth">The width.</param>
        /// <param name="range">The range.</param>
        /// <param name="setter">The placement setter.</param>
        /// <param name="localPlacement">The local placement.</param>
        /// <param name="localWrapper">The wrapper.</param>
        public static void AddOpeningsToElement(ExporterIFC exporterIFC, IList<IFCAnyHandle> elementHandles,
            IList<CurveLoop> curveLoops, Element element, Transform lcs, double scaledWidth,
            IFCRange range, PlacementSetter setter, IFCAnyHandle localPlacement, ProductWrapper localWrapper)
        {
            IList<IFCOpeningData> openingDataList = ExporterIFCUtils.GetOpeningData(exporterIFC, element, lcs, range);
             IFCFile file = exporterIFC.GetFile();
             IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle;
             foreach (IFCOpeningData openingData in openingDataList)
             {
            Element openingElem = element.Document.GetElement(openingData.OpeningElementId);
            if (openingElem == null)
               openingElem = element;

            bool currentWallIsHost = false;
            FamilyInstance openingFInst = openingElem as FamilyInstance;
            if (openingFInst != null && openingFInst.Host != null)
            {
               if (openingFInst.Host.Id == element.Id)
                  currentWallIsHost = true;
                  //continue;      // If the host is not the current Wall, skip this opening
            }

            // Don't export the opening if WallSweep category has been turned off.
            // This is currently restricted to WallSweeps because the element responsible for the opening could be a variety of things,
            // including a line as part of the elevation profile of the wall.
            // As such, we will restrict which element types we check for CanExportElement.
            if ((openingElem is WallSweep) && (!ElementFilteringUtil.CanExportElement(exporterIFC, openingElem, true)))
               continue;

            IList<IFCExtrusionData> extrusionDataList = openingData.GetExtrusionData();
            IFCAnyHandle parentHandle = null;
            if (elementHandles.Count > 1 && extrusionDataList.Count > 0)
            {
               parentHandle = FindParentHandle(elementHandles, curveLoops, extrusionDataList[0].GetLoops()[0]);
            }

            if (parentHandle == null)
               parentHandle = elementHandles[0];

            bool isDoorOrWindowOpening = IsDoorOrWindowOpening(exporterIFC, openingElem, element);
            bool insertHasHost = false;
            bool insertInThisHost = false;
            if (openingElem is FamilyInstance && element is Wall)
            {
               string ifcEnumType;
               IFCExportInfoPair exportType = ExporterUtil.GetExportType(exporterIFC, openingElem, out ifcEnumType);
               Element instHost = (openingElem as FamilyInstance).Host;
               insertHasHost = (instHost != null);
               insertInThisHost = (insertHasHost && instHost.Id == element.Id);
               isDoorOrWindowOpening =
                  insertInThisHost &&
                  (exportType.ExportInstance == IFCEntityType.IfcDoor ||
                  exportType.ExportType == IFCEntityType.IfcDoorType ||
                  exportType.ExportInstance == IFCEntityType.IfcWindow ||
                  exportType.ExportType == IFCEntityType.IfcWindowType);
            }

            if (isDoorOrWindowOpening && currentWallIsHost)
            {
               DoorWindowDelayedOpeningCreator delayedCreator =
                   DoorWindowDelayedOpeningCreator.Create(exporterIFC, openingData, scaledWidth, element.Id, parentHandle, setter.LevelId);
               if (delayedCreator != null)
               {
                  ExporterCacheManager.DoorWindowDelayedOpeningCreatorCache.Add(delayedCreator);
                  continue;
               }
            }

            // If the opening is "filled" by another element (either a door or window as
            // determined above, or an embedded wall, then we can't use the element GUID
            // for the opening.
            bool canUseElementGUID = (!insertHasHost || insertInThisHost) &&
               !isDoorOrWindowOpening &&
               !(openingElem is Wall);

            IList<Solid> solids = openingData.GetOpeningSolids();
            foreach (Solid solid in solids)
            {
               using (IFCExtrusionCreationData extrusionCreationData = new IFCExtrusionCreationData())
               {
                  extrusionCreationData.SetLocalPlacement(ExporterUtil.CreateLocalPlacement(file, localPlacement, null));
                  extrusionCreationData.ReuseLocalPlacement = true;

                  string openingGUID = CreateOpeningGUID(openingElem, canUseElementGUID);
                  canUseElementGUID = false; // Either it was used above, and therefore is now false, or it was already false.

                  CreateOpening(exporterIFC, parentHandle, element, openingElem, openingGUID, solid, scaledWidth, openingData.IsRecess, extrusionCreationData,
                      setter, localWrapper);
               }
            }

            foreach (IFCExtrusionData extrusionData in extrusionDataList)
            {
               if (extrusionData.ScaledExtrusionLength < MathUtil.Eps())
                  extrusionData.ScaledExtrusionLength = scaledWidth;

               string openingGUID = CreateOpeningGUID(openingElem, canUseElementGUID);
               canUseElementGUID = false; // Either it was used above, and therefore is now false, or it was already false.

               CreateOpening(exporterIFC, parentHandle, localPlacement, element, openingElem, openingGUID, extrusionData, lcs, openingData.IsRecess,
                   setter, localWrapper);
            }
             }
        }
Example #48
0
        /// <summary>
        /// Export the individual part (IfcBuildingElementPart).
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="partElement">The part element to export.</param>
        /// <param name="geometryElement">The geometry of part.</param>
        /// <param name="productWrapper">The ProductWrapper object.</param>
        /// <param name="placementSetter"></param>
        /// <param name="originalPlacement"></param>
        /// <param name="range"></param>
        /// <param name="ifcExtrusionAxes"></param>
        /// <param name="hostElement">The host of the part.  This can be null.</param>
        /// <param name="overrideLevelId">The id of the level that the part is one, overridding other sources.</param>
        /// <param name="asBuildingElement">If true, export the Part as a building element instead of an IfcElementPart.</param>
        public static void ExportPart(ExporterIFC exporterIFC, Element partElement, ProductWrapper productWrapper,
                                      PlacementSetter placementSetter, IFCAnyHandle originalPlacement, IFCRange range, IFCExtrusionAxes ifcExtrusionAxes,
                                      Element hostElement, ElementId overrideLevelId, bool asBuildingElement)
        {
            if (!ElementFilteringUtil.IsElementVisible(partElement))
            {
                return;
            }

            Part part = partElement as Part;

            if (part == null)
            {
                return;
            }

            // We don't know how to export a part as a building element if we don't know it's host.
            if (asBuildingElement && (hostElement == null))
            {
                return;
            }

            if (!asBuildingElement)
            {
                // Check the intended IFC entity or type name is in the exclude list specified in the UI
                Common.Enums.IFCEntityType elementClassTypeEnum = Common.Enums.IFCEntityType.IfcBuildingElementPart;
                if (ExporterCacheManager.ExportOptionsCache.IsElementInExcludeList(elementClassTypeEnum))
                {
                    return;
                }
            }
            else
            {
                string            ifcEnumType = null;
                IFCExportInfoPair exportType  = ExporterUtil.GetExportType(exporterIFC, hostElement, out ifcEnumType);

                // 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>(exportType.ToString(), out elementClassTypeEnum))
                {
                    if (ExporterCacheManager.ExportOptionsCache.IsElementInExcludeList(elementClassTypeEnum))
                    {
                        return;
                    }
                }
            }

            PlacementSetter standalonePlacementSetter = null;
            bool            standaloneExport          = hostElement == null || asBuildingElement;

            ElementId partExportLevelId = (overrideLevelId != null) ? overrideLevelId : null;

            if (partExportLevelId == null && standaloneExport)
            {
                partExportLevelId = partElement.LevelId;
            }

            if (partExportLevelId == null)
            {
                if (hostElement == null || (part.OriginalCategoryId != hostElement.Category.Id))
                {
                    return;
                }
                partExportLevelId = hostElement.LevelId;
            }

            if (ExporterCacheManager.PartExportedCache.HasExported(partElement.Id, partExportLevelId))
            {
                return;
            }

            Options options   = GeometryUtil.GetIFCExportGeometryOptions();
            View    ownerView = partElement.Document.GetElement(partElement.OwnerViewId) as View;

            if (ownerView != null)
            {
                options.View = ownerView;
            }

            GeometryElement geometryElement = partElement.get_Geometry(options);

            if (geometryElement == null)
            {
                return;
            }

            try
            {
                IFCFile file = exporterIFC.GetFile();
                using (IFCTransaction transaction = new IFCTransaction(file))
                {
                    IFCAnyHandle partPlacement = null;
                    if (standaloneExport)
                    {
                        Transform    orientationTrf       = Transform.Identity;
                        IFCAnyHandle overrideContainerHnd = null;
                        ElementId    overrideContainerId  = ParameterUtil.OverrideContainmentParameter(exporterIFC, partElement, out overrideContainerHnd);
                        if (overrideContainerId != ElementId.InvalidElementId && (partExportLevelId == null || partExportLevelId == ElementId.InvalidElementId))
                        {
                            partExportLevelId = overrideContainerId;
                        }

                        standalonePlacementSetter = PlacementSetter.Create(exporterIFC, partElement, null, orientationTrf, partExportLevelId, overrideContainerHnd);
                        partPlacement             = standalonePlacementSetter.LocalPlacement;
                    }
                    else
                    {
                        //partPlacement = ExporterUtil.CreateLocalPlacement(file, null, null);
                        partPlacement = ExporterUtil.CreateLocalPlacement(file, originalPlacement, null);
                    }

                    bool validRange = (range != null && !MathUtil.IsAlmostZero(range.Start - range.End));

                    SolidMeshGeometryInfo solidMeshInfo;
                    if (validRange)
                    {
                        solidMeshInfo = GeometryUtil.GetSplitClippedSolidMeshGeometry(geometryElement, range);
                        if (solidMeshInfo.GetSolids().Count == 0 && solidMeshInfo.GetMeshes().Count == 0)
                        {
                            return;
                        }
                    }
                    else
                    {
                        solidMeshInfo = GeometryUtil.GetSplitSolidMeshGeometry(geometryElement);
                    }

                    using (IFCExtrusionCreationData extrusionCreationData = new IFCExtrusionCreationData())
                    {
                        extrusionCreationData.SetLocalPlacement(partPlacement);
                        extrusionCreationData.ReuseLocalPlacement   = false;
                        extrusionCreationData.PossibleExtrusionAxes = ifcExtrusionAxes;

                        IList <Solid>          solids = new List <Solid>();;
                        IList <Mesh>           meshes = new List <Mesh>();
                        IList <GeometryObject> gObjs  = FamilyExporterUtil.RemoveInvisibleSolidsAndMeshes(partElement.Document, exporterIFC, solidMeshInfo.GetSolids(), solidMeshInfo.GetMeshes());
                        foreach (GeometryObject gObj in gObjs)
                        {
                            if (gObj is Solid)
                            {
                                solids.Add(gObj as Solid);
                            }
                            else if (gObj is Mesh)
                            {
                                meshes.Add(gObj as Mesh);
                            }
                        }

                        ElementId catId     = CategoryUtil.GetSafeCategoryId(partElement);
                        ElementId hostCatId = CategoryUtil.GetSafeCategoryId(hostElement);

                        BodyData            bodyData            = null;
                        BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true, ExportOptionsCache.ExportTessellationLevel.ExtraLow);
                        if (solids.Count > 0 || meshes.Count > 0)
                        {
                            bodyData = BodyExporter.ExportBody(exporterIFC, partElement, catId, ElementId.InvalidElementId, solids, meshes,
                                                               bodyExporterOptions, extrusionCreationData);
                        }
                        else
                        {
                            IList <GeometryObject> geomlist = new List <GeometryObject>();
                            geomlist.Add(geometryElement);
                            bodyData = BodyExporter.ExportBody(exporterIFC, partElement, catId, ElementId.InvalidElementId, geomlist,
                                                               bodyExporterOptions, extrusionCreationData);
                        }

                        IFCAnyHandle bodyRep = bodyData.RepresentationHnd;
                        if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep))
                        {
                            extrusionCreationData.ClearOpenings();
                            return;
                        }

                        IList <IFCAnyHandle> representations = new List <IFCAnyHandle>();
                        representations.Add(bodyRep);

                        IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geometryElement, Transform.Identity);
                        if (boundingBoxRep != null)
                        {
                            representations.Add(boundingBoxRep);
                        }

                        IFCAnyHandle prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations);

                        IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle;

                        string            partGUID    = GUIDUtil.CreateGUID(partElement);
                        string            ifcEnumType = null;
                        IFCExportInfoPair exportType  = ExporterUtil.GetExportType(exporterIFC, hostElement, out ifcEnumType);
                        IFCAnyHandle      ifcPart     = null;
                        if (!asBuildingElement)
                        {
                            ifcPart = IFCInstanceExporter.CreateBuildingElementPart(exporterIFC, partElement, partGUID, ownerHistory,
                                                                                    extrusionCreationData.GetLocalPlacement(), prodRep);
                        }
                        else
                        {
                            switch (exportType.ExportInstance)
                            {
                            case IFCEntityType.IfcColumn:
                                ifcPart = IFCInstanceExporter.CreateColumn(exporterIFC, partElement, partGUID, ownerHistory,
                                                                           extrusionCreationData.GetLocalPlacement(), prodRep, ifcEnumType);
                                break;

                            case IFCEntityType.IfcCovering:
                                ifcPart = IFCInstanceExporter.CreateCovering(exporterIFC, partElement, partGUID, ownerHistory,
                                                                             extrusionCreationData.GetLocalPlacement(), prodRep, ifcEnumType);
                                break;

                            case IFCEntityType.IfcFooting:
                                ifcPart = IFCInstanceExporter.CreateFooting(exporterIFC, partElement, partGUID, ownerHistory,
                                                                            extrusionCreationData.GetLocalPlacement(), prodRep, ifcEnumType);
                                break;

                            case IFCEntityType.IfcPile:
                                ifcPart = IFCInstanceExporter.CreatePile(exporterIFC, partElement, partGUID, ownerHistory,
                                                                         extrusionCreationData.GetLocalPlacement(), prodRep, ifcEnumType, null);
                                break;

                            case IFCEntityType.IfcRoof:
                                ifcPart = IFCInstanceExporter.CreateRoof(exporterIFC, partElement, partGUID, ownerHistory,
                                                                         extrusionCreationData.GetLocalPlacement(), prodRep, ifcEnumType);
                                break;

                            case IFCEntityType.IfcSlab:
                            {
                                // TODO: fix this elsewhere.
                                if (ExporterUtil.IsNotDefined(ifcEnumType))
                                {
                                    if (hostCatId == new ElementId(BuiltInCategory.OST_Floors))
                                    {
                                        ifcEnumType = "FLOOR";
                                    }
                                    else if (hostCatId == new ElementId(BuiltInCategory.OST_Roofs))
                                    {
                                        ifcEnumType = "ROOF";
                                    }
                                }

                                ifcPart = IFCInstanceExporter.CreateSlab(exporterIFC, partElement, partGUID, ownerHistory,
                                                                         extrusionCreationData.GetLocalPlacement(), prodRep, ifcEnumType);
                            }
                            break;

                            case IFCEntityType.IfcWall:
                                ifcPart = IFCInstanceExporter.CreateWall(exporterIFC, partElement, partGUID, ownerHistory,
                                                                         extrusionCreationData.GetLocalPlacement(), prodRep, ifcEnumType);
                                break;

                            default:
                                ifcPart = IFCInstanceExporter.CreateBuildingElementProxy(exporterIFC, partElement, partGUID, ownerHistory,
                                                                                         extrusionCreationData.GetLocalPlacement(), prodRep, exportType.ValidatedPredefinedType);
                                break;
                            }
                        }

                        bool            containedInLevel     = standaloneExport;
                        PlacementSetter whichPlacementSetter = containedInLevel ? standalonePlacementSetter : placementSetter;
                        productWrapper.AddElement(partElement, ifcPart, whichPlacementSetter, extrusionCreationData, containedInLevel, exportType);

                        OpeningUtil.CreateOpeningsIfNecessary(ifcPart, partElement, extrusionCreationData, bodyData.OffsetTransform, exporterIFC,
                                                              extrusionCreationData.GetLocalPlacement(), whichPlacementSetter, productWrapper);

                        //Add the exported part to exported cache.
                        TraceExportedParts(partElement, partExportLevelId, standaloneExport ? ElementId.InvalidElementId : hostElement.Id);

                        CategoryUtil.CreateMaterialAssociation(exporterIFC, ifcPart, bodyData.MaterialIds);

                        transaction.Commit();
                    }
                }
            }
            finally
            {
                if (standalonePlacementSetter != null)
                {
                    standalonePlacementSetter.Dispose();
                }
            }
        }
Example #49
0
        /// <summary>
        /// Adds openings to an element.
        /// </summary>
        /// <param name="exporterIFC">The exporter.</param>
        /// <param name="elementHandles">The parent handles.</param>
        /// <param name="curveLoops">The parent CurveLoops.</param>
        /// <param name="element">The element.</param>
        /// <param name="plane">The plane.</param>
        /// <param name="scaledWidth">The width.</param>
        /// <param name="range">The range.</param>
        /// <param name="setter">The placement setter.</param>
        /// <param name="localPlacement">The local placement.</param>
        /// <param name="localWrapper">The wrapper.</param>
        public static void AddOpeningsToElement(ExporterIFC exporterIFC, IList <IFCAnyHandle> elementHandles, IList <CurveLoop> curveLoops, Element element, Plane plane, double scaledWidth,
                                                IFCRange range, PlacementSetter setter, IFCAnyHandle localPlacement, ProductWrapper localWrapper)
        {
            IList <IFCOpeningData> openingDataList = ExporterIFCUtils.GetOpeningData(exporterIFC, element, plane, range);
            IFCFile      file         = exporterIFC.GetFile();
            IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle();

            foreach (IFCOpeningData openingData in openingDataList)
            {
                Element openingElem = element.Document.GetElement(openingData.OpeningElementId);
                if (openingElem == null)
                {
                    openingElem = element;
                }

                // Don't export the opening if WallSweep category has been turned off.
                // This is currently restricted to WallSweeps because the element responsible for the opening could be a variety of things, including a line as part of the elevation profile of the wall.
                // As such, we will restrict which element types we check for CanExportElement.
                if ((openingElem is WallSweep) && (!ElementFilteringUtil.CanExportElement(exporterIFC, openingElem, true)))
                {
                    continue;
                }

                IList <IFCExtrusionData> extrusionDataList = openingData.GetExtrusionData();
                IFCAnyHandle             parentHandle      = null;
                if (elementHandles.Count > 1 && extrusionDataList.Count > 0)
                {
                    parentHandle = FindParentHandle(elementHandles, curveLoops, extrusionDataList[0].GetLoops()[0]);
                }

                if (parentHandle == null)
                {
                    parentHandle = elementHandles[0];
                }

                bool isDoorOrWindowOpening = IsDoorOrWindowOpening(exporterIFC, openingElem, element);
                if (isDoorOrWindowOpening)
                {
                    DoorWindowDelayedOpeningCreator delayedCreator =
                        DoorWindowDelayedOpeningCreator.Create(exporterIFC, openingData, scaledWidth, element.Id, parentHandle, setter.LevelId);
                    if (delayedCreator != null)
                    {
                        ExporterCacheManager.DoorWindowDelayedOpeningCreatorCache.Add(delayedCreator);
                        continue;
                    }
                }

                bool canUseElementGUID = !isDoorOrWindowOpening;

                IList <Solid> solids = openingData.GetOpeningSolids();
                foreach (Solid solid in solids)
                {
                    using (IFCExtrusionCreationData extrusionCreationData = new IFCExtrusionCreationData())
                    {
                        extrusionCreationData.SetLocalPlacement(ExporterUtil.CreateLocalPlacement(file, localPlacement, null));
                        extrusionCreationData.ReuseLocalPlacement = true;

                        string openingGUID = null;
                        if (canUseElementGUID)
                        {
                            openingGUID       = GUIDUtil.CreateGUID(openingElem);
                            canUseElementGUID = false;
                        }
                        else
                        {
                            openingGUID = GUIDUtil.CreateGUID();
                        }
                        CreateOpening(exporterIFC, parentHandle, element, openingElem, openingGUID, solid, scaledWidth, openingData.IsRecess, extrusionCreationData,
                                      setter, localWrapper);
                    }
                }

                foreach (IFCExtrusionData extrusionData in extrusionDataList)
                {
                    if (extrusionData.ScaledExtrusionLength < MathUtil.Eps())
                    {
                        extrusionData.ScaledExtrusionLength = scaledWidth;
                    }

                    string openingGUID = null;
                    if (canUseElementGUID)
                    {
                        openingGUID       = GUIDUtil.CreateGUID(element);
                        canUseElementGUID = false;
                    }
                    else
                    {
                        openingGUID = GUIDUtil.CreateGUID();
                    }
                    CreateOpening(exporterIFC, parentHandle, localPlacement, element, openingElem, openingGUID, extrusionData, plane, openingData.IsRecess,
                                  setter, localWrapper);
                }
            }
        }
Example #50
0
        /// <summary>
        /// Export the individual part (IfcBuildingElementPart).
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="partElement">The part element to export.</param>
        /// <param name="geometryElement">The geometry of part.</param>
        /// <param name="productWrapper">The ProductWrapper object.</param>
        public static void ExportPart(ExporterIFC exporterIFC, Element partElement, ProductWrapper productWrapper,
                                      IFCPlacementSetter placementSetter, IFCAnyHandle originalPlacement, IFCRange range, IFCExtrusionAxes ifcExtrusionAxes,
                                      Element hostElement, ElementId overrideLevelId, bool asBuildingElement)
        {
            if (!ElementFilteringUtil.IsElementVisible(partElement))
            {
                return;
            }

            Part part = partElement as Part;

            if (part == null)
            {
                return;
            }

            IFCPlacementSetter standalonePlacementSetter = null;
            bool standaloneExport = hostElement == null && !asBuildingElement;

            ElementId partExportLevel = null;

            if (overrideLevelId != null)
            {
                partExportLevel = overrideLevelId;
            }
            else if (standaloneExport || asBuildingElement)
            {
                if (partElement.Level != null)
                {
                    partExportLevel = partElement.Level.Id;
                }
            }
            else
            {
                if (part.OriginalCategoryId != hostElement.Category.Id)
                {
                    return;
                }
                partExportLevel = hostElement.Level.Id;
            }

            if (ExporterCacheManager.PartExportedCache.HasExported(partElement.Id, partExportLevel))
            {
                return;
            }

            Options options   = GeometryUtil.GetIFCExportGeometryOptions();
            View    ownerView = partElement.Document.GetElement(partElement.OwnerViewId) as View;

            if (ownerView != null)
            {
                options.View = ownerView;
            }

            GeometryElement geometryElement = partElement.get_Geometry(options);

            if (geometryElement == null)
            {
                return;
            }

            try
            {
                IFCFile file = exporterIFC.GetFile();
                using (IFCTransaction transaction = new IFCTransaction(file))
                {
                    IFCAnyHandle partPlacement = null;
                    if (standaloneExport || asBuildingElement)
                    {
                        Transform orientationTrf = Transform.Identity;
                        standalonePlacementSetter = IFCPlacementSetter.Create(exporterIFC, partElement, null, orientationTrf, partExportLevel);
                        partPlacement             = standalonePlacementSetter.GetPlacement();
                    }
                    else
                    {
                        partPlacement = ExporterUtil.CreateLocalPlacement(file, originalPlacement, null);
                    }

                    bool validRange = (range != null && !MathUtil.IsAlmostZero(range.Start - range.End));

                    SolidMeshGeometryInfo solidMeshInfo;
                    if (validRange)
                    {
                        solidMeshInfo = GeometryUtil.GetSplitClippedSolidMeshGeometry(geometryElement, range);
                        if (solidMeshInfo.GetSolids().Count == 0 && solidMeshInfo.GetMeshes().Count == 0)
                        {
                            return;
                        }
                    }
                    else
                    {
                        solidMeshInfo = GeometryUtil.GetSplitSolidMeshGeometry(geometryElement);
                    }

                    using (IFCExtrusionCreationData extrusionCreationData = new IFCExtrusionCreationData())
                    {
                        extrusionCreationData.SetLocalPlacement(partPlacement);
                        extrusionCreationData.ReuseLocalPlacement   = false;
                        extrusionCreationData.PossibleExtrusionAxes = ifcExtrusionAxes;

                        IList <Solid> solids = solidMeshInfo.GetSolids();
                        IList <Mesh>  meshes = solidMeshInfo.GetMeshes();

                        ElementId catId = CategoryUtil.GetSafeCategoryId(partElement);

                        BodyData            bodyData            = null;
                        BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true);
                        if (solids.Count > 0 || meshes.Count > 0)
                        {
                            bodyData = BodyExporter.ExportBody(exporterIFC, partElement, catId, ElementId.InvalidElementId, solids, meshes,
                                                               bodyExporterOptions, extrusionCreationData);
                        }
                        else
                        {
                            IList <GeometryObject> geomlist = new List <GeometryObject>();
                            geomlist.Add(geometryElement);
                            bodyData = BodyExporter.ExportBody(exporterIFC, partElement, catId, ElementId.InvalidElementId, geomlist,
                                                               bodyExporterOptions, extrusionCreationData);
                        }

                        IFCAnyHandle bodyRep = bodyData.RepresentationHnd;
                        if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep))
                        {
                            extrusionCreationData.ClearOpenings();
                            return;
                        }

                        IList <IFCAnyHandle> representations = new List <IFCAnyHandle>();
                        representations.Add(bodyRep);

                        IFCAnyHandle boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geometryElement, Transform.Identity);
                        if (boundingBoxRep != null)
                        {
                            representations.Add(boundingBoxRep);
                        }

                        IFCAnyHandle prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations);

                        IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle();

                        string partGUID        = GUIDUtil.CreateGUID(partElement);
                        string partName        = NamingUtil.GetNameOverride(partElement, NamingUtil.GetIFCName(partElement));
                        string partDescription = NamingUtil.GetDescriptionOverride(partElement, null);
                        string partObjectType  = NamingUtil.GetObjectTypeOverride(partElement, NamingUtil.CreateIFCObjectName(exporterIFC, partElement));
                        string partTag         = NamingUtil.GetTagOverride(partElement, NamingUtil.CreateIFCElementId(partElement));

                        IFCAnyHandle ifcPart = null;
                        if (!asBuildingElement)
                        {
                            ifcPart = IFCInstanceExporter.CreateBuildingElementPart(file, partGUID, ownerHistory, partName, partDescription,
                                                                                    partObjectType, extrusionCreationData.GetLocalPlacement(), prodRep, partTag);
                        }
                        else
                        {
                            string        ifcEnumType;
                            IFCExportType exportType = ExporterUtil.GetExportType(exporterIFC, hostElement, out ifcEnumType);
                            switch (exportType)
                            {
                            case IFCExportType.ExportColumnType:
                                ifcPart = IFCInstanceExporter.CreateColumn(file, partGUID, ownerHistory, partName, partDescription, partObjectType,
                                                                           extrusionCreationData.GetLocalPlacement(), prodRep, partTag);
                                break;

                            case IFCExportType.ExportCovering:
                                IFCCoveringType coveringType = CeilingExporter.GetIFCCoveringType(hostElement, ifcEnumType);
                                ifcPart = IFCInstanceExporter.CreateCovering(file, partGUID, ownerHistory, partName, partDescription, partObjectType,
                                                                             extrusionCreationData.GetLocalPlacement(), prodRep, partTag, coveringType);
                                break;

                            case IFCExportType.ExportFooting:
                                IFCFootingType footingType = FootingExporter.GetIFCFootingType(hostElement, ifcEnumType);
                                ifcPart = IFCInstanceExporter.CreateFooting(file, partGUID, ownerHistory, partName, partDescription, partObjectType,
                                                                            extrusionCreationData.GetLocalPlacement(), prodRep, partTag, footingType);
                                break;

                            case IFCExportType.ExportRoof:
                                IFCRoofType roofType = RoofExporter.GetIFCRoofType(ifcEnumType);
                                ifcPart = IFCInstanceExporter.CreateRoof(file, partGUID, ownerHistory, partName, partDescription, partObjectType,
                                                                         extrusionCreationData.GetLocalPlacement(), prodRep, partTag, roofType);
                                break;

                            case IFCExportType.ExportSlab:
                                IFCSlabType slabType = FloorExporter.GetIFCSlabType(ifcEnumType);
                                ifcPart = IFCInstanceExporter.CreateSlab(file, partGUID, ownerHistory, partName, partDescription, partObjectType,
                                                                         extrusionCreationData.GetLocalPlacement(), prodRep, partTag, slabType);
                                break;

                            case IFCExportType.ExportWall:
                                ifcPart = IFCInstanceExporter.CreateWall(file, partGUID, ownerHistory, partName, partDescription, partObjectType,
                                                                         extrusionCreationData.GetLocalPlacement(), prodRep, partTag);
                                break;

                            default:
                                ifcPart = IFCInstanceExporter.CreateBuildingElementProxy(file, partGUID, ownerHistory, partName, partDescription,
                                                                                         partObjectType, extrusionCreationData.GetLocalPlacement(), prodRep, partTag, null);
                                break;
                            }
                        }

                        bool containedInLevel = (standaloneExport || asBuildingElement);
                        IFCPlacementSetter whichPlacementSetter = containedInLevel ? standalonePlacementSetter : placementSetter;
                        productWrapper.AddElement(partElement, ifcPart, whichPlacementSetter, extrusionCreationData, containedInLevel);

                        //Add the exported part to exported cache.
                        TraceExportedParts(partElement, partExportLevel, standaloneExport || asBuildingElement ? ElementId.InvalidElementId : hostElement.Id);

                        CategoryUtil.CreateMaterialAssociations(exporterIFC, ifcPart, bodyData.MaterialIds);

                        transaction.Commit();
                    }
                }
            }
            finally
            {
                if (standalonePlacementSetter != null)
                {
                    standalonePlacementSetter.Dispose();
                }
            }
        }