/// <summary> /// Creates or updates the IfcLocalPlacement associated with the current origin offset. /// </summary> /// <param name="exporterIFC">The exporter.</param> /// <param name="bbox">The bounding box.</param> /// <param name="ecData">The extrusion creation data which contains the local placement.</param> /// <param name="lpOrig">The local placement origin.</param> /// <param name="unscaledTrfOrig">The unscaled local placement origin.</param> public void CreateLocalPlacementFromOffset(ExporterIFC exporterIFC, BoundingBoxXYZ bbox, IFCExtrusionCreationData ecData, XYZ lpOrig, XYZ unscaledTrfOrig) { if (ecData == null) { return; } IFCAnyHandle localPlacement = ecData.GetLocalPlacement(); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(localPlacement)) { IFCFile file = exporterIFC.GetFile(); // If the BBox passes through (0,0, 0), or no bbox, do nothing. if (bbox == null || ((bbox.Min.X < MathUtil.Eps() && bbox.Max.X > -MathUtil.Eps()) && (bbox.Min.Y < MathUtil.Eps() && bbox.Max.Y > -MathUtil.Eps()) && (bbox.Min.Z < MathUtil.Eps() && bbox.Max.Z > -MathUtil.Eps()))) { if (!ecData.ReuseLocalPlacement) { ecData.SetLocalPlacement(ExporterUtil.CopyLocalPlacement(file, localPlacement)); } return; } if (!MathUtil.IsAlmostZero(unscaledTrfOrig.DotProduct(unscaledTrfOrig))) { if (!ecData.ReuseLocalPlacement) { ecData.SetLocalPlacement(ExporterUtil.CreateLocalPlacement(file, localPlacement, lpOrig, null, null)); } else { IFCAnyHandle relativePlacement = GeometryUtil.GetRelativePlacementFromLocalPlacement(localPlacement); if (IFCAnyHandleUtil.IsNullOrHasNoValue(relativePlacement)) { IFCAnyHandle newRelativePlacement = ExporterUtil.CreateAxis(file, lpOrig, null, null); GeometryUtil.SetRelativePlacement(localPlacement, newRelativePlacement); } else { IFCAnyHandle newOriginHnd = ExporterUtil.CreateCartesianPoint(file, lpOrig); IFCAnyHandleUtil.SetAttribute(relativePlacement, "Location", newOriginHnd); } } } else if (ecData.ForceOffset) { ecData.SetLocalPlacement(ExporterUtil.CreateLocalPlacement(file, localPlacement, null)); } else if (!ecData.ReuseLocalPlacement) { ecData.SetLocalPlacement(ExporterUtil.CopyLocalPlacement(file, localPlacement)); } } }
/// <summary> /// Creates a new IfcAnnotation object. /// </summary> /// <param name="exporterIFC">The exporter.</param> /// <param name="curveElement">The curve element.</param> /// <param name="categoryId">The category id.</param> /// <param name="sketchPlaneId">The sketch plane id.</param> /// <param name="curveLCS">The curve local coordinate system.</param> /// <param name="curveStyle">The curve style.</param> /// <param name="placementSetter">The placemenet setter.</param> /// <param name="localPlacement">The local placement.</param> /// <param name="repItemHnd">The representation item.</param> /// <returns>The handle.</returns> static IFCAnyHandle CreateCurveAnnotation(ExporterIFC exporterIFC, Element curveElement, ElementId categoryId, ElementId sketchPlaneId, Transform curveLCS, IFCAnyHandle curveStyle, PlacementSetter placementSetter, IFCAnyHandle localPlacement, IFCAnyHandle repItemHnd) { HashSet <IFCAnyHandle> bodyItems = new HashSet <IFCAnyHandle>(); bodyItems.Add(repItemHnd); IFCAnyHandle bodyRepHnd = RepresentationUtil.CreateAnnotationSetRep(exporterIFC, curveElement, categoryId, exporterIFC.Get2DContextHandle(), bodyItems); if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRepHnd)) { throw new Exception("Failed to create shape representation."); } List <IFCAnyHandle> shapes = new List <IFCAnyHandle>(); shapes.Add(bodyRepHnd); IFCFile file = exporterIFC.GetFile(); IFCAnyHandle prodShapeHnd = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, shapes); XYZ xDir = curveLCS.BasisX; XYZ zDir = curveLCS.BasisZ; XYZ origin = curveLCS.Origin; // subtract out level origin if we didn't already before. IFCLevelInfo levelInfo = placementSetter.LevelInfo; if (levelInfo != null && !MathUtil.IsAlmostEqual(zDir.Z, 1.0)) { zDir -= new XYZ(0, 0, levelInfo.Elevation); } origin = UnitUtil.ScaleLength(origin); IFCAnyHandle relativePlacement = ExporterUtil.CreateAxis(file, origin, zDir, xDir); GeometryUtil.SetRelativePlacement(localPlacement, relativePlacement); string guid = GUIDUtil.CreateGUID(curveElement); IFCAnyHandle annotation = IFCInstanceExporter.CreateAnnotation(exporterIFC, curveElement, guid, ExporterCacheManager.OwnerHistoryHandle, localPlacement, prodShapeHnd); return(annotation); }
/// <summary> /// Exports text note elements. /// </summary> /// <param name="exporterIFC"> /// The ExporterIFC object. /// </param> /// <param name="textNote"> /// The text note element. /// </param> /// <param name="productWrapper"> /// The ProductWrapper. /// </param> public static void Export(ExporterIFC exporterIFC, TextNote textNote, ProductWrapper productWrapper) { // Check the intended IFC entity or type name is in the exclude list specified in the UI string predefinedType = null; IFCExportInfoPair exportType = ExporterUtil.GetProductExportType(exporterIFC, textNote, out predefinedType); if (ExporterCacheManager.ExportOptionsCache.IsElementInExcludeList(exportType.ExportInstance)) { return; } IFCFile file = exporterIFC.GetFile(); using (IFCTransaction tr = new IFCTransaction(file)) { string textString = textNote.Text; if (String.IsNullOrEmpty(textString)) { throw new Exception("TextNote does not have test string."); } ElementId symId = textNote.GetTypeId(); if (symId == ElementId.InvalidElementId) { throw new Exception("TextNote does not have valid type id."); } PresentationStyleAssignmentCache cache = ExporterCacheManager.PresentationStyleAssignmentCache; IFCAnyHandle presHnd = cache.Find(symId); if (IFCAnyHandleUtil.IsNullOrHasNoValue(presHnd)) { TextElementType textElemType = textNote.Symbol; CreatePresentationStyleAssignmentForTextElementType(exporterIFC, textElemType, cache); presHnd = cache.Find(symId); if (IFCAnyHandleUtil.IsNullOrHasNoValue(presHnd)) { throw new Exception("Failed to create presentation style assignment for TextElementType."); } } HashSet <IFCAnyHandle> presHndSet = new HashSet <IFCAnyHandle>(); presHndSet.Add(presHnd); using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, textNote)) { const double planScale = 100.0; // currently hardwired. XYZ orig = UnitUtil.ScaleLength(textNote.Coord); XYZ yDir = textNote.UpDirection; XYZ xDir = textNote.BaseDirection; XYZ zDir = xDir.CrossProduct(yDir); double sizeX = UnitUtil.ScaleLength(textNote.Width * planScale); double sizeY = UnitUtil.ScaleLength(textNote.Height * planScale); // When we display text on screen, we "flip" it if the xDir is negative with relation to // the X-axis. So if it is, we'll flip x and y. bool flipOrig = false; if (xDir.X < 0) { xDir = xDir.Multiply(-1.0); yDir = yDir.Multiply(-1.0); flipOrig = true; } // xFactor, yFactor only used if flipOrig. double xFactor = 0.0, yFactor = 0.0; string boxAlignment = ConvertTextNoteAlignToBoxAlign(textNote, out xFactor, out yFactor); // modify the origin to match the alignment. In Revit, the origin is at the top-left (unless flipped, // then bottom-right). if (flipOrig) { orig = orig.Add(xDir.Multiply(sizeX * xFactor)); orig = orig.Add(yDir.Multiply(sizeY * yFactor)); } IFCAnyHandle origin = ExporterUtil.CreateAxis(file, orig, zDir, xDir); IFCAnyHandle extent = IFCInstanceExporter.CreatePlanarExtent(file, sizeX, sizeY); IFCAnyHandle repItemHnd = IFCInstanceExporter.CreateTextLiteralWithExtent(file, textString, origin, Toolkit.IFCTextPath.Left, extent, boxAlignment); IFCAnyHandle annoTextOccHnd = IFCInstanceExporter.CreateStyledItem(file, repItemHnd, presHndSet, null); ElementId catId = textNote.Category != null ? textNote.Category.Id : ElementId.InvalidElementId; HashSet <IFCAnyHandle> bodyItems = new HashSet <IFCAnyHandle>(); bodyItems.Add(repItemHnd); IFCAnyHandle bodyRepHnd = RepresentationUtil.CreateAnnotationSetRep(exporterIFC, textNote, catId, exporterIFC.Get2DContextHandle(), bodyItems); if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRepHnd)) { throw new Exception("Failed to create shape representation."); } IList <IFCAnyHandle> shapeReps = new List <IFCAnyHandle>(); shapeReps.Add(bodyRepHnd); IFCAnyHandle prodShapeHnd = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, shapeReps); IFCAnyHandle instHnd; if (exportType.ExportInstance == Common.Enums.IFCEntityType.IfcAnnotation) { instHnd = IFCInstanceExporter.CreateAnnotation(exporterIFC, textNote, GUIDUtil.CreateGUID(), ExporterCacheManager.OwnerHistoryHandle, setter.LocalPlacement, prodShapeHnd); } else { instHnd = IFCInstanceExporter.CreateGenericIFCEntity(exportType, exporterIFC, textNote, GUIDUtil.CreateGUID(), ExporterCacheManager.OwnerHistoryHandle, setter.LocalPlacement, prodShapeHnd); } productWrapper.AddAnnotation(instHnd, setter.LevelInfo, true); } tr.Commit(); } }
/// <summary> /// Creates a simple swept solid from a list of curve loops. /// </summary> /// <param name="exporterIFC">The exporter.</param> /// <param name="profileName">The profile name.</param> /// <param name="profileCurveLoops">The profile curve loops.</param> /// <param name="normal">The normal of the plane that the path lies on.</param> /// <param name="directrix">The path curve.</param> /// <returns>The swept solid handle.</returns> public static IFCAnyHandle CreateSimpleSweptSolid(ExporterIFC exporterIFC, string profileName, IList <CurveLoop> profileCurveLoops, XYZ normal, Curve directrix) { // see definition of IfcSurfaceCurveSweptAreaSolid from // http://www.buildingsmart-tech.org/ifc/IFC2x4/rc4/html/schema/ifcgeometricmodelresource/lexical/ifcsurfacecurvesweptareasolid.htm IFCAnyHandle simpleSweptSolidHnd = null; if (!CanCreateSimpleSweptSolid(profileCurveLoops, normal, directrix)) { return(simpleSweptSolidHnd); } bool isBound = directrix.IsBound; double originalStartParam = isBound ? directrix.GetEndParameter(0) : 0.0; Plane axisPlane, profilePlane; CreateAxisAndProfileCurvePlanes(directrix, originalStartParam, out axisPlane, out profilePlane); IList <CurveLoop> curveLoops = null; try { // Check that curve loops are valid. curveLoops = ExporterIFCUtils.ValidateCurveLoops(profileCurveLoops, profilePlane.Normal); } catch (Exception) { return(null); } if (curveLoops == null || curveLoops.Count == 0) { return(simpleSweptSolidHnd); } double startParam = 0.0, endParam = 1.0; if (directrix is Arc) { // This effectively resets the start parameter to 0.0, and end parameter = length of curve. if (isBound) { endParam = UnitUtil.ScaleAngle(MathUtil.PutInRange(directrix.GetEndParameter(1), Math.PI, 2 * Math.PI) - MathUtil.PutInRange(originalStartParam, Math.PI, 2 * Math.PI)); } else { endParam = 2.0 * Math.PI; } } // Start creating IFC entities. IFCAnyHandle sweptArea = ExtrusionExporter.CreateSweptArea(exporterIFC, profileName, curveLoops, profilePlane, profilePlane.Normal); if (IFCAnyHandleUtil.IsNullOrHasNoValue(sweptArea)) { return(simpleSweptSolidHnd); } IFCAnyHandle curveHandle = null; IFCAnyHandle referenceSurfaceHandle = ExtrusionExporter.CreateSurfaceOfLinearExtrusionFromCurve(exporterIFC, directrix, axisPlane, 1.0, 1.0, out curveHandle); // Should this be moved up? Check. Plane scaledAxisPlane = GeometryUtil.GetScaledPlane(exporterIFC, axisPlane); IFCFile file = exporterIFC.GetFile(); IFCAnyHandle solidAxis = ExporterUtil.CreateAxis(file, scaledAxisPlane.Origin, scaledAxisPlane.Normal, scaledAxisPlane.XVec); simpleSweptSolidHnd = IFCInstanceExporter.CreateSurfaceCurveSweptAreaSolid(file, sweptArea, solidAxis, curveHandle, startParam, endParam, referenceSurfaceHandle); return(simpleSweptSolidHnd); }
/// <summary> /// Initializes the transformation in the transform setter. /// </summary> /// <param name="exporterIFC">The exporter.</param> /// <param name="geometryList">The set of geometry used to determine the bounding box.</param> /// <param name="ecData">The extrusion creation data which contains the local placement.</param> /// <returns>The transform corresponding to the movement, if any.</returns> /// <remarks>This method will eventually be obsoleted by the InitializeFromBoundingBox/CreateLocalPlacementFromOffset pair below, which delays creating or updating the local placement /// until we are certain we will use it, saving time and reducing wasted line numbers.</remarks> public Transform InitializeFromBoundingBox(ExporterIFC exporterIFC, IList <GeometryObject> geometryList, IFCExtrusionCreationData ecData) { if (ecData == null) { return(null); } Transform trf = Transform.Identity; IFCAnyHandle localPlacement = ecData.GetLocalPlacement(); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(localPlacement)) { IFCFile file = exporterIFC.GetFile(); BoundingBoxXYZ bbox = GeometryUtil.GetBBoxOfGeometries(geometryList); // If the BBox passes through (0,0, 0), or no bbox, do nothing. if (bbox == null || ((bbox.Min.X < MathUtil.Eps() && bbox.Max.X > -MathUtil.Eps()) && (bbox.Min.Y < MathUtil.Eps() && bbox.Max.Y > -MathUtil.Eps()) && (bbox.Min.Z < MathUtil.Eps() && bbox.Max.Z > -MathUtil.Eps()))) { if (!ecData.ReuseLocalPlacement) { ecData.SetLocalPlacement(ExporterUtil.CopyLocalPlacement(file, localPlacement)); } return(trf); } XYZ bboxMin = bbox.Min; XYZ scaledOrig = UnitUtil.ScaleLength(bboxMin); Transform scaledTrf = GeometryUtil.GetScaledTransform(exporterIFC); XYZ lpOrig = scaledTrf.OfPoint(scaledOrig); if (!ecData.AllowVerticalOffsetOfBReps) { lpOrig = new XYZ(lpOrig.X, lpOrig.Y, 0.0); } Transform scaledTrfInv = scaledTrf.Inverse; XYZ scaledInvOrig = scaledTrfInv.OfPoint(XYZ.Zero); XYZ unscaledInvOrig = UnitUtil.UnscaleLength(scaledInvOrig); XYZ trfOrig = unscaledInvOrig - bboxMin; if (!ecData.AllowVerticalOffsetOfBReps) { trfOrig = new XYZ(trfOrig.X, trfOrig.Y, 0.0); } if (!MathUtil.IsAlmostZero(trfOrig.DotProduct(trfOrig))) { Initialize(exporterIFC, trfOrig, XYZ.BasisX, XYZ.BasisY); if (!ecData.ReuseLocalPlacement) { ecData.SetLocalPlacement(ExporterUtil.CreateLocalPlacement(file, localPlacement, lpOrig, null, null)); } else { IFCAnyHandle relativePlacement = GeometryUtil.GetRelativePlacementFromLocalPlacement(localPlacement); if (IFCAnyHandleUtil.IsNullOrHasNoValue(relativePlacement)) { IFCAnyHandle newRelativePlacement = ExporterUtil.CreateAxis(file, lpOrig, null, null); GeometryUtil.SetRelativePlacement(localPlacement, newRelativePlacement); } else { IFCAnyHandle oldOriginHnd, zDirHnd, xDirHnd; xDirHnd = IFCAnyHandleUtil.GetInstanceAttribute(relativePlacement, "RefDirection"); zDirHnd = IFCAnyHandleUtil.GetInstanceAttribute(relativePlacement, "Axis"); oldOriginHnd = IFCAnyHandleUtil.GetInstanceAttribute(relativePlacement, "Location"); bool trfSet = false; XYZ xDir = XYZ.BasisX; XYZ zDir = XYZ.BasisZ; XYZ oldCoords = XYZ.Zero; if (!IFCAnyHandleUtil.IsNullOrHasNoValue(xDirHnd)) { xDir = GeometryUtil.GetDirectionRatios(xDirHnd); trfSet = true; } if (!IFCAnyHandleUtil.IsNullOrHasNoValue(zDirHnd)) { zDir = GeometryUtil.GetDirectionRatios(zDirHnd); trfSet = true; } if (!IFCAnyHandleUtil.IsNullOrHasNoValue(oldOriginHnd)) { oldCoords = GeometryUtil.GetCoordinates(oldOriginHnd); } if (trfSet) { XYZ yDir = zDir.CrossProduct(xDir); Transform relPlacementTrf = Transform.Identity; relPlacementTrf.Origin = oldCoords; relPlacementTrf.BasisX = xDir; relPlacementTrf.BasisY = yDir; relPlacementTrf.BasisZ = zDir; lpOrig = relPlacementTrf.OfPoint(lpOrig); } else { lpOrig = oldCoords + lpOrig; } IFCAnyHandle newOriginHnd = ExporterUtil.CreateCartesianPoint(file, lpOrig); IFCAnyHandleUtil.SetAttribute(relativePlacement, "Location", newOriginHnd); } } trf.Origin = lpOrig; } else if (ecData.ForceOffset) { ecData.SetLocalPlacement(ExporterUtil.CreateLocalPlacement(file, localPlacement, null)); } else if (!ecData.ReuseLocalPlacement) { ecData.SetLocalPlacement(ExporterUtil.CopyLocalPlacement(file, localPlacement)); } } return(trf); }
/// <summary> /// Creates a simple swept solid from a list of curve loops. /// </summary> /// <param name="exporterIFC">The exporter.</param> /// <param name="profileName">The profile name.</param> /// <param name="profileCurveLoops">The profile curve loops.</param> /// <param name="normal">The normal of the plane that the path lies on.</param> /// <param name="directrix">The path curve.</param> /// <returns>The swept solid handle.</returns> public static IFCAnyHandle CreateSimpleSweptSolid(ExporterIFC exporterIFC, string profileName, IList <CurveLoop> profileCurveLoops, XYZ normal, Curve directrix) { // see definition of IfcSurfaceCurveSweptAreaSolid from // http://www.buildingsmart-tech.org/ifc/IFC2x4/rc4/html/schema/ifcgeometricmodelresource/lexical/ifcsurfacecurvesweptareasolid.htm IFCAnyHandle simpleSweptSolidHnd = null; if (!CanCreateSimpleSweptSolid(profileCurveLoops, normal, directrix)) { return(simpleSweptSolidHnd); } bool isBound = directrix.IsBound; double originalStartParam = isBound ? directrix.GetEndParameter(0) : 0.0; Transform axisLCS, profileLCS; CreateAxisAndProfileCurveLCS(directrix, originalStartParam, out axisLCS, out profileLCS); IList <CurveLoop> curveLoops = null; try { // Check that curve loops are valid. curveLoops = ExporterIFCUtils.ValidateCurveLoops(profileCurveLoops, profileLCS.BasisZ); } catch (Exception) { return(null); } if (curveLoops == null || curveLoops.Count == 0) { return(simpleSweptSolidHnd); } double startParam = 0.0, endParam = 1.0; if (directrix is Arc) { // This effectively resets the start parameter to 0.0, and end parameter = length of curve. if (isBound) { // Put the parameters in range of [0, 2*Pi] double inRangeStarParam = (directrix.GetEndParameter(0) % (2 * Math.PI)); double inRangeEndParam = (directrix.GetEndParameter(1) % (2 * Math.PI)); // We want the angle direction is anti-clockwise (+ direction), therefore we will always start with the smaller one if (inRangeEndParam < inRangeStarParam) { double tmp = inRangeStarParam; inRangeStarParam = inRangeEndParam; inRangeEndParam = tmp; } // If start param is negative, we will reset it to 0 and shift the end accordingly if (inRangeStarParam < 0) { double parRange = inRangeEndParam - inRangeStarParam; inRangeStarParam = 0.0; inRangeEndParam = parRange; } endParam = UnitUtil.ScaleAngle(inRangeEndParam); //endParam = UnitUtil.ScaleAngle(MathUtil.PutInRange(directrix.GetEndParameter(1), Math.PI, 2 * Math.PI) - // MathUtil.PutInRange(originalStartParam, Math.PI, 2 * Math.PI)); } else { endParam = 2.0 * Math.PI; } } // Start creating IFC entities. IFCAnyHandle sweptArea = ExtrusionExporter.CreateSweptArea(exporterIFC, profileName, curveLoops, profileLCS, profileLCS.BasisZ); if (IFCAnyHandleUtil.IsNullOrHasNoValue(sweptArea)) { return(simpleSweptSolidHnd); } IFCAnyHandle curveHandle = null; IFCAnyHandle referenceSurfaceHandle = ExtrusionExporter.CreateSurfaceOfLinearExtrusionFromCurve(exporterIFC, directrix, axisLCS, 1.0, 1.0, out curveHandle); // Should this be moved up? Check. XYZ scaledOrigin = ExporterIFCUtils.TransformAndScalePoint(exporterIFC, axisLCS.Origin); XYZ scaledXDir = ExporterIFCUtils.TransformAndScaleVector(exporterIFC, axisLCS.BasisX).Normalize(); XYZ scaledNormal = ExporterIFCUtils.TransformAndScaleVector(exporterIFC, axisLCS.BasisZ).Normalize(); IFCFile file = exporterIFC.GetFile(); IFCAnyHandle solidAxis = ExporterUtil.CreateAxis(file, scaledOrigin, scaledNormal, scaledXDir); simpleSweptSolidHnd = IFCInstanceExporter.CreateSurfaceCurveSweptAreaSolid(file, sweptArea, solidAxis, curveHandle, startParam, endParam, referenceSurfaceHandle); return(simpleSweptSolidHnd); }
/// <summary> /// Creates a simple swept solid from a list of curve loops. /// </summary> /// <param name="exporterIFC">The exporter.</param> /// <param name="profileName">The profile name.</param> /// <param name="profileCurveLoops">The profile curve loops.</param> /// <param name="normal">The normal of the plane that the path lies on.</param> /// <param name="directrix">The path curve.</param> /// <returns>The swept solid handle.</returns> public static IFCAnyHandle CreateSimpleSweptSolid(ExporterIFC exporterIFC, string profileName, IList <CurveLoop> profileCurveLoops, XYZ normal, Curve directrix) { // see definition of IfcSurfaceCurveSweptAreaSolid from // http://www.buildingsmart-tech.org/ifc/IFC2x4/rc4/html/schema/ifcgeometricmodelresource/lexical/ifcsurfacecurvesweptareasolid.htm IFCAnyHandle simpleSweptSolidHnd = null; if (profileCurveLoops.Count == 0) { return(simpleSweptSolidHnd); } IFCFile file = exporterIFC.GetFile(); XYZ startPoint = directrix.get_EndPoint(0); XYZ profilePlaneNormal = null; XYZ profilePlaneXDir = null; XYZ profilePlaneYDir = null; IFCAnyHandle curveHandle = null; double startParam = 0, endParam = 1; Plane scaledReferencePlane = null; if (directrix is Line) { Line line = directrix as Line; startParam = 0.0; endParam = 1.0; profilePlaneNormal = line.Direction; profilePlaneYDir = normal; profilePlaneXDir = profilePlaneNormal.CrossProduct(profilePlaneYDir); XYZ linePlaneNormal = profilePlaneYDir; XYZ linePlaneXDir = profilePlaneXDir; XYZ linePlaneYDir = linePlaneNormal.CrossProduct(linePlaneXDir); XYZ linePlaneOrig = startPoint; scaledReferencePlane = GeometryUtil.CreateScaledPlane(exporterIFC, linePlaneXDir, linePlaneYDir, linePlaneOrig); curveHandle = GeometryUtil.CreateLine(exporterIFC, line, scaledReferencePlane); } else if (directrix is Arc) { Arc arc = directrix as Arc; // profilePlaneXDir is set relative to the startPoint of the directrix. This effectively resets the start parameter to 0.0, and end parameter = length of curve. startParam = 0.0; endParam = (MathUtil.PutInRange(arc.get_EndParameter(1), Math.PI, 2 * Math.PI) - MathUtil.PutInRange(arc.get_EndParameter(0), Math.PI, 2 * Math.PI)) * (180 / Math.PI); profilePlaneNormal = directrix.ComputeDerivatives(0, true).BasisX; profilePlaneXDir = (arc.Center - startPoint).Normalize(); profilePlaneYDir = profilePlaneNormal.CrossProduct(profilePlaneXDir).Normalize(); XYZ arcPlaneNormal = arc.Normal; XYZ arcPlaneXDir = profilePlaneXDir; XYZ arcPlaneYDir = arcPlaneNormal.CrossProduct(arcPlaneXDir); XYZ arcPlaneOrig = startPoint; scaledReferencePlane = GeometryUtil.CreateScaledPlane(exporterIFC, arcPlaneXDir, arcPlaneYDir, arcPlaneOrig); curveHandle = GeometryUtil.CreateArc(exporterIFC, arc, scaledReferencePlane); } else { return(simpleSweptSolidHnd); } IFCAnyHandle referencePlaneAxisHandle = ExporterUtil.CreateAxis(file, scaledReferencePlane.Origin, scaledReferencePlane.Normal, scaledReferencePlane.XVec); IFCAnyHandle referencePlaneHandle = IFCInstanceExporter.CreatePlane(file, referencePlaneAxisHandle); Plane profilePlane = new Plane(profilePlaneXDir, profilePlaneYDir, startPoint); IList <CurveLoop> curveLoops = null; try { // Check that curve loops are valid. curveLoops = ExporterIFCUtils.ValidateCurveLoops(profileCurveLoops, profilePlaneNormal); } catch (Exception) { return(null); } if (curveLoops == null || curveLoops.Count == 0) { return(simpleSweptSolidHnd); } IFCAnyHandle sweptArea = ExtrusionExporter.CreateSweptArea(exporterIFC, profileName, curveLoops, profilePlane, profilePlaneNormal); if (IFCAnyHandleUtil.IsNullOrHasNoValue(sweptArea)) { return(simpleSweptSolidHnd); } profilePlane = GeometryUtil.GetScaledPlane(exporterIFC, profilePlane); IFCAnyHandle solidAxis = ExporterUtil.CreateAxis(file, profilePlane.Origin, profilePlane.Normal, profilePlane.XVec); simpleSweptSolidHnd = IFCInstanceExporter.CreateSurfaceCurveSweptAreaSolid(file, sweptArea, solidAxis, curveHandle, startParam, endParam, referencePlaneHandle); return(simpleSweptSolidHnd); }