/// <summary> /// Gets the first or last riser curve of the run. /// </summary> /// <param name="last">True to get the last curve, false to get the first.</param> /// <returns>The curve.</returns> private Curve GetEndCurve(bool last) { if (m_stairsRun == null) { throw new NotSupportedException("Stairs run hasn't been constructed yet."); } // Obtain the footprint boundary of the run. CurveLoop boundary = m_stairsRun.GetFootprintBoundary(); // Find the first or last point on the path CurveLoop path = m_stairsRun.GetStairsPath(); Curve pathCurve = path.First <Curve>(); XYZ pathPoint = pathCurve.GetEndPoint(last ? 1 : 0); // Walk the footprint boundary, and look for a curve whose projection of the target point is equal to the point. foreach (Curve boundaryCurve in boundary) { if (boundaryCurve.Project(pathPoint).XYZPoint.IsAlmostEqualTo(pathPoint)) { return(boundaryCurve); } } throw new Exception("Unable to find an intersecting boundary curve in the run."); }
/// <summary> /// Gets the first or last riser curve of the run. /// </summary> /// <param name="last">True to get the last curve, false to get the first.</param> /// <returns>The curve.</returns> private Curve GetEndCurve(bool last) { if (m_stairsRun == null) { throw new NotSupportedException("Stairs run hasn't been constructed yet."); } // Obtain the footprint boundary CurveLoop boundary = m_stairsRun.GetFootprintBoundary(); // Obtain the endpoint of the stairs path matching the desired end, // and find out which curve contains this point. CurveLoop path = m_stairsRun.GetStairsPath(); Curve pathCurve = path.First <Curve>(); XYZ pathPoint = pathCurve.GetEndPoint(last ? 1 : 0); foreach (Curve boundaryCurve in boundary) { if (boundaryCurve.Project(pathPoint).XYZPoint.IsAlmostEqualTo(pathPoint)) { return(boundaryCurve); } } throw new Exception("Unable to find an intersecting boundary curve in the run."); }
/// <summary> /// Attempt to create a single curve from a curve loop composed of linear segments. /// </summary> /// <param name="curveLoop">The curve loop.</param> /// <param name="pointXYZs">The original points from which the curve loop was created.</param> /// <returns>The curve, if the curve loop is linear, or null.</returns> /// <remarks>Note that the routine does not actually check that the curveLoop is composed /// of line segments, or that the point array matches the curve loop in any way.</remarks> public static Curve CreateCurveFromPolyCurveLoop(CurveLoop curveLoop, IList <XYZ> pointXYZs) { if (curveLoop == null) { return(null); } int numCurves = curveLoop.NumberOfCurves(); if (numCurves == 0) { return(null); } if (numCurves == 1) { Curve originalCurve = curveLoop.First(); if (originalCurve != null) { return(originalCurve.Clone()); } return(null); } if (pointXYZs == null) { return(null); } int numPoints = pointXYZs.Count; // If we are here, we are sure that the number of points must be at least 3. XYZ firstPoint = pointXYZs[0]; XYZ secondPoint = pointXYZs[1]; XYZ vectorToTest = (secondPoint - firstPoint).Normalize(); bool allAreCollinear = true; for (int ii = 2; ii < numPoints; ii++) { XYZ vectorTmp = (pointXYZs[ii] - firstPoint).Normalize(); if (!vectorTmp.IsAlmostEqualTo(vectorToTest)) { allAreCollinear = false; break; } } if (allAreCollinear) { return(Line.CreateBound(firstPoint, pointXYZs[numPoints - 1])); } return(null); }
public static LinearRing ToNtsLinearRing(this CurveLoop _cl) { var coords = new List <Coordinate>(); foreach (var c in _cl) { var co = c.GetEndPoint(0).ToNtsCoord(); coords.Add(co); } coords.Add(_cl.First().GetEndPoint(0).ToNtsCoord()); var lr = new LinearRing(coords.ToArray()); return(gpr.Reduce(lr) as LinearRing); }
/// <summary> /// Returns the surface which defines the internal shape of the face /// </summary> /// <param name="lcs">The local coordinate system for the surface. Can be null.</param> /// <returns>The surface which defines the internal shape of the face</returns> public override Surface GetSurface(Transform lcs) { if (SweptCurve == null) { Importer.TheLog.LogError(Id, "Cannot find the profile curve of this revolved face.", true); } IFCSimpleProfile simpleProfile = SweptCurve as IFCSimpleProfile; if (simpleProfile == null) { Importer.TheLog.LogError(Id, "Can't handle profile curve of type " + SweptCurve.GetType() + ".", true); } CurveLoop outerCurve = simpleProfile.OuterCurve; Curve profileCurve = (outerCurve != null) ? outerCurve.First <Curve>() : null; if (profileCurve == null) { Importer.TheLog.LogError(Id, "Cannot create the profile curve of this revolved surface.", true); } if (outerCurve.Count() > 1) { Importer.TheLog.LogError(Id, "Revolved surface has multiple profile curves, ignoring all but first.", false); } Curve revolvedSurfaceProfileCurve = profileCurve.CreateTransformed(Position); if (!RevolvedSurface.IsValidProfileCurve(AxisPosition.Origin, AxisPosition.BasisZ, revolvedSurfaceProfileCurve)) { Importer.TheLog.LogError(Id, "Profile curve is invalid for this revolved surface.", true); } if (lcs == null) { return(RevolvedSurface.Create(AxisPosition.Origin, AxisPosition.BasisZ, revolvedSurfaceProfileCurve)); } Curve transformedRevolvedSurfaceProfileCurve = revolvedSurfaceProfileCurve.CreateTransformed(lcs); return(RevolvedSurface.Create(lcs.OfPoint(AxisPosition.Origin), lcs.OfVector(AxisPosition.BasisZ), transformedRevolvedSurfaceProfileCurve)); }
/// <summary> /// Get the local surface transform at a given point on the surface. /// </summary> /// <param name="pointOnSurface">The point.</param> /// <returns>The transform.</returns> /// <remarks>This does not include the translation component.</remarks> public override Transform GetTransformAtPoint(XYZ pointOnSurface) { if (!(SweptCurve is IFCSimpleProfile)) { // LOG: ERROR: warn that we only support simple profiles. return(null); } CurveLoop outerCurveLoop = (SweptCurve as IFCSimpleProfile).OuterCurve; if (outerCurveLoop == null || outerCurveLoop.Count() != 1) { // LOG: ERROR return(null); } Curve outerCurve = outerCurveLoop.First(); if (outerCurve == null) { // LOG: ERROR return(null); } IntersectionResult result = outerCurve.Project(pointOnSurface); if (result == null) { // LOG: ERROR return(null); } double parameter = result.Parameter; Transform atPoint = outerCurve.ComputeDerivatives(parameter, false); atPoint.set_Basis(0, atPoint.BasisX.Normalize()); atPoint.set_Basis(1, atPoint.BasisY.Normalize()); atPoint.set_Basis(2, atPoint.BasisZ.Normalize()); atPoint.Origin = pointOnSurface; return(atPoint); }
/// <summary> /// Get the curve from the Axis representation of the given IfcProduct, transformed to the current local coordinate system. /// </summary> /// <param name="creator">The IfcProduct that may or may not contain a valid axis curve.</param> /// <param name="lcs">The local coordinate system.</param> /// <returns>The axis curve, if found, and valid.</returns> /// <remarks>In this case, we only allow bounded lines and arcs to be valid axis curves, as per IFC2x3 convention. /// The Curve may be contained as either a single Curve in the IFCCurve representation item, or it could be an /// open CurveLoop with one item.</remarks> private Curve GetAxisCurve(IFCProduct creator, Transform lcs) { // We need an axis curve to clip the extrusion profiles; if we can't get one, fail IFCProductRepresentation productRepresentation = creator.ProductRepresentation; if (productRepresentation == null) { return(null); } IList <IFCRepresentation> representations = productRepresentation.Representations; if (representations == null) { return(null); } foreach (IFCRepresentation representation in representations) { // Go through the list of representations for this product, to find the Axis representation. if (representation == null || representation.Identifier != IFCRepresentationIdentifier.Axis) { continue; } IList <IFCRepresentationItem> items = representation.RepresentationItems; if (items == null) { continue; } // Go through the list of representation items in the Axis representation, to look for the IfcCurve. foreach (IFCRepresentationItem item in items) { if (item is IFCCurve) { // We will accept either a bounded Curve of type Line or Arc, // or an open CurveLoop with one curve that satisfies the same condition. IFCCurve ifcCurve = item as IFCCurve; Curve axisCurve = ifcCurve.Curve; if (axisCurve == null) { CurveLoop axisCurveLoop = ifcCurve.CurveLoop; if (axisCurveLoop != null && axisCurveLoop.IsOpen() && axisCurveLoop.Count() == 1) { axisCurve = axisCurveLoop.First(); if (!(axisCurve is Line || axisCurve is Arc)) { axisCurve = null; } } } if (axisCurve != null) { return(axisCurve.CreateTransformed(lcs)); } } } } return(null); }
/// <summary> /// Return geometry for a particular representation item. /// </summary> /// <param name="shapeEditScope">The geometry creation scope.</param> /// <param name="unscaledLcs">The unscaled local coordinate system for the geometry, if the scaled version isn't supported downstream.</param> /// <param name="scaledLcs">The scaled (true) local coordinate system for the geometry.</param> /// <param name="guid">The guid of an element for which represntation is being created.</param> /// <returns>The created geometry.</returns> protected override IList <GeometryObject> CreateGeometryInternal( IFCImportShapeEditScope shapeEditScope, Transform unscaledLcs, Transform scaledLcs, string guid) { Transform unscaledObjectPosition = (unscaledLcs == null) ? Position : unscaledLcs.Multiply(Position); Transform scaledObjectPosition = (scaledLcs == null) ? Position : scaledLcs.Multiply(Position); CurveLoop baseProfileCurve = Directrix.GetCurveLoop(); if (baseProfileCurve == null) { return(null); } CurveLoop trimmedDirectrix = IFCGeometryUtil.TrimCurveLoop(Id, baseProfileCurve, StartParameter, EndParameter); if (trimmedDirectrix == null) { return(null); } double startParam = 0.0; // If the directrix isn't bound, this arbitrary parameter will do. Transform originTrf0 = null; Curve firstCurve0 = trimmedDirectrix.First(); if (firstCurve0.IsBound) { startParam = firstCurve0.GetEndParameter(0); } originTrf0 = firstCurve0.ComputeDerivatives(startParam, false); if (originTrf0 == null) { return(null); } // Note: the computation of the reference Surface Local Transform must be done before the directrix is transform to LCS (because the ref surface isn't) // and therefore the origin is at the start of the curve should be the start of the directrix that lies on the surface. // This is needed to transform the swept area that must be perpendicular to the start of the directrix curve Transform referenceSurfaceLocalTransform = ReferenceSurface.GetTransformAtPoint(originTrf0.Origin); CurveLoop trimmedDirectrixInLCS = IFCGeometryUtil.CreateTransformed(trimmedDirectrix, Id, unscaledObjectPosition, scaledObjectPosition); // Create the sweep. Transform originTrf = null; Curve firstCurve = trimmedDirectrixInLCS.First(); //if (firstCurve.IsBound) // startParam = firstCurve.GetEndParameter(0); originTrf = firstCurve.ComputeDerivatives(startParam, false); Transform unscaledReferenceSurfaceTransform = unscaledObjectPosition.Multiply(referenceSurfaceLocalTransform); Transform scaledReferenceSurfaceTransform = scaledObjectPosition.Multiply(referenceSurfaceLocalTransform); Transform profileCurveLoopsTransform = Transform.CreateTranslation(originTrf.Origin); profileCurveLoopsTransform.BasisX = scaledReferenceSurfaceTransform.BasisZ; profileCurveLoopsTransform.BasisZ = originTrf.BasisX.Normalize(); profileCurveLoopsTransform.BasisY = profileCurveLoopsTransform.BasisZ.CrossProduct(profileCurveLoopsTransform.BasisX); ISet <IList <CurveLoop> > profileCurveLoops = GetTransformedCurveLoops(profileCurveLoopsTransform, profileCurveLoopsTransform); if (profileCurveLoops == null || profileCurveLoops.Count == 0) { return(null); } SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); IList <GeometryObject> myObjs = new List <GeometryObject>(); foreach (IList <CurveLoop> loops in profileCurveLoops) { GeometryObject myObj = GeometryCreationUtilities.CreateSweptGeometry(trimmedDirectrixInLCS, 0, startParam, loops, solidOptions); if (myObj != null) { myObjs.Add(myObj); } } return(myObjs); }
/// <summary> /// Return geometry for a particular representation item. /// </summary> /// <param name="shapeEditScope">The geometry creation scope.</param> /// <param name="lcs">Local coordinate system for the geometry.</param> /// <param name="guid">The guid of an element for which represntation is being created.</param> /// <returns>The created geometry.</returns> protected override IList <GeometryObject> CreateGeometryInternal( IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid) { Transform objectPosition = (lcs == null) ? Position : lcs.Multiply(Position); CurveLoop baseProfileCurve = Directrix.GetCurveLoop(); if (baseProfileCurve == null) { return(null); } CurveLoop trimmedDirectrix = IFCGeometryUtil.TrimCurveLoop(baseProfileCurve, StartParameter, EndParameter); if (trimmedDirectrix == null) { return(null); } CurveLoop trimmedDirectrixInLCS = IFCGeometryUtil.CreateTransformed(trimmedDirectrix, objectPosition); // Create the sweep. double startParam = 0.0; // If the directrix isn't bound, this arbitrary parameter will do. Transform originTrf = null; Curve firstCurve = trimmedDirectrixInLCS.First(); if (firstCurve.IsBound) { startParam = firstCurve.GetEndParameter(0); } originTrf = firstCurve.ComputeDerivatives(startParam, false); if (originTrf == null) { return(null); } Transform referenceSurfaceLocalTransform = ReferenceSurface.GetTransformAtPoint(originTrf.Origin); Transform referenceSurfaceTransform = objectPosition.Multiply(referenceSurfaceLocalTransform); Transform profileCurveLoopsTransform = Transform.CreateTranslation(originTrf.Origin); profileCurveLoopsTransform.BasisX = referenceSurfaceTransform.BasisZ; profileCurveLoopsTransform.BasisZ = originTrf.BasisX.Normalize(); profileCurveLoopsTransform.BasisY = profileCurveLoopsTransform.BasisZ.CrossProduct(profileCurveLoopsTransform.BasisX); ISet <IList <CurveLoop> > profileCurveLoops = GetTransformedCurveLoops(profileCurveLoopsTransform); if (profileCurveLoops == null || profileCurveLoops.Count == 0) { return(null); } SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); IList <GeometryObject> myObjs = new List <GeometryObject>(); foreach (IList <CurveLoop> loops in profileCurveLoops) { GeometryObject myObj = GeometryCreationUtilities.CreateSweptGeometry(trimmedDirectrixInLCS, 0, startParam, loops, solidOptions); if (myObj != null) { myObjs.Add(myObj); } } return(myObjs); }
/// <returns>true if the curve loop is clockwise, false otherwise.</returns> private static bool SafeIsCurveLoopClockwise(CurveLoop curveLoop, XYZ dir) { if (curveLoop == null) return false; if (curveLoop.IsOpen()) return false; if ((curveLoop.Count() == 1) && !(curveLoop.First().IsBound)) return false; return !curveLoop.IsCounterclockwise(dir); }
void SubDivideSoffits_CreateFireRatedLayers(Document doc) { try { #region Get Soffits List <Element> Soffits = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Floors).ToElements().Where(m => !(m is ElementType)).ToList(); #endregion //Subdivide foreach (Element Soffit in Soffits.Where(m => m.Name.ToLower().Contains("eave"))) { #region Get Soffit Geometry Options ops = new Options(); ops.DetailLevel = ViewDetailLevel.Fine; ops.IncludeNonVisibleObjects = true; GeometryElement Geo = Soffit.get_Geometry(ops); #endregion foreach (var item in Geo) { if (item is Solid) { #region Get one of the Main Faces, it doesn't really matter if it is top or bottom Solid GSol = item as Solid; List <Face> Fs = new List <Face>(); foreach (Face f in GSol.Faces) { Fs.Add(f); } Face F = Fs.Where(m => m.Area == Fs.Max(a => a.Area)).First(); #endregion #region Triangulate the Face with max detail Mesh M = F.Triangulate(1); #endregion #region Create Variables for: the curves that will define the new Soffits, List of Custom Triangle Class, List of Custom Pair of Triangle Class List <List <Curve> > LLC = new List <List <Curve> >(); List <Triangle> Triangles = new List <Triangle>(); List <TrianglePair> TPairs = new List <TrianglePair>(); #endregion #region Loop Through Triangles & Add Them to the list of My Triangle Class for (int i = 0; i < M.NumTriangles; i++) { List <Curve> LC = new List <Curve>(); #region Make List of Curves From Triangle MeshTriangle MT = M.get_Triangle(i); List <Curve> Curves = new List <Curve>(); Curve C = Line.CreateBound(MT.get_Vertex(0), MT.get_Vertex(1)) as Curve; Curves.Add(C); C = Line.CreateBound(MT.get_Vertex(1), MT.get_Vertex(2)) as Curve; Curves.Add(C); C = Line.CreateBound(MT.get_Vertex(2), MT.get_Vertex(0)) as Curve; Curves.Add(C); #endregion Triangle T = new Triangle(); T.Sides = new List <Curve>(); T.Sides = Curves; T.Vertices = new List <XYZ>(); T.Vertices.Add(MT.get_Vertex(0)); T.Vertices.Add(MT.get_Vertex(1)); T.Vertices.Add(MT.get_Vertex(2)); Triangles.Add(T); } #endregion #region Loop Through Triangles And Create Trapezoid Pairs To Catch The Segments, Getting Rid of The Shared sides bool GO = true; do { Triangle TKeeper1 = new Triangle(); Triangle TKeeper2 = new Triangle(); foreach (Triangle T in Triangles) { TKeeper1 = new Triangle(); foreach (Triangle T2 in Triangles) { TKeeper2 = new Triangle(); if (T != T2) { if (FindCurvesFacing(T, T2) != null) { if (FindCurvesFacing(T, T2)[0].Length == T.Sides.Min(c => c.Length) || FindCurvesFacing(T, T2)[1].Length == T2.Sides.Min(c => c.Length)) { continue; } Curve[] Cs = FindCurvesFacing(T, T2); T.Sides.Remove(Cs[0]); T2.Sides.Remove(Cs[1]); if (T.Sides.Count() == 2 && T2.Sides.Count() == 2) { TKeeper1 = T; TKeeper2 = T2; goto ADDANDGOROUND; } } } } } GO = false; ADDANDGOROUND: if (GO) { Triangles.Remove(TKeeper1); Triangles.Remove(TKeeper2); TrianglePair TP = new TrianglePair(); TP.T1 = TKeeper1; TP.T2 = TKeeper2; TPairs.Add(TP); } } while(GO); #endregion #region Create Curve Loops From Triangle Pairs foreach (TrianglePair TPair in TPairs) { List <Curve> Cs = new List <Curve>(); Cs.AddRange(TPair.T1.Sides); Cs.AddRange(TPair.T2.Sides); LLC.Add(Cs); } #endregion double Offset = Convert.ToDouble(Soffit.LookupParameter("Height Offset From Level").AsValueString()); FloorType FT = (Soffit as Floor).FloorType; Level Lvl = doc.GetElement((Soffit as Floor).LevelId) as Level; #region Delete Old Soffit If All Went Well using (Transaction T = new Transaction(doc, "Delete Soffit")) { T.Start(); doc.Delete(Soffit.Id); T.Commit(); } #endregion #region Sort The Lists of Curves and Create The New Segments foreach (List <Curve> LC in LLC) { List <Curve> LCSorted = new List <Curve>(); try { LCSorted = SortCurvesContiguous(LC, false); } #region Exception Details if Curves Could not be sorted catch (Exception EXC) { string exmsge = EXC.Message; } #endregion CurveArray CA = new CurveArray(); foreach (Curve C in LCSorted) { CA.Append(C); } using (Transaction T = new Transaction(doc, "Make Segment")) { T.Start(); Floor newFloor = doc.Create.NewFloor(CA, FT, Lvl, false); newFloor.LookupParameter("Height Offset From Level").SetValueString(Offset.ToString()); T.Commit(); } } #endregion } } } //refresh collection Soffits = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Floors).ToElements().Where(m => !(m is ElementType)).ToList(); //test soffits for needing fire rating foreach (Element Soffit in Soffits.Where(m => m.Name.ToLower().Contains("eave"))) { #region Get Soffit Geometry Options ops = new Options(); ops.DetailLevel = ViewDetailLevel.Fine; ops.IncludeNonVisibleObjects = true; GeometryElement Geo = Soffit.get_Geometry(ops); #endregion foreach (var item in Geo) { if (item is Solid) { #region Find boundary Void Element List <Element> MaybeBoundary = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Floors).ToElements().Where(m => !(m is ElementType)).ToList(); Element BoundryElement = MaybeBoundary.Where(m => !(m is FloorType) && m.Name == "Boundary").First(); #endregion #region Get Intersection of Boundary and eave PolygonAnalyser com = new PolygonAnalyser(); List <CurveArray> CArray = com.Execute(BoundryElement as Floor, Soffit as Floor); Level L = doc.GetElement(Soffit.LevelId) as Level; #endregion foreach (CurveArray CA in CArray) { #region Sort The Curves IList <Curve> CAL = new List <Curve>(); foreach (Curve C in CA) { CAL.Add(C); } List <Curve> Curves = SortCurvesContiguous(CAL, false); List <XYZ> NewCurveEnds = new List <XYZ>(); #endregion #region Close the loop if nesesary CurveLoop CL = new CurveLoop(); foreach (Curve curv in Curves) { CL.Append(curv); } if (CL.IsOpen()) { Curves.Add(Line.CreateBound(CL.First().GetEndPoint(0), CL.Last().GetEndPoint(1)) as Curve); } #endregion #region Recreate a Curve Array Curves = SortCurvesContiguous(Curves, false); CurveArray CA2 = new CurveArray(); int i = 0; foreach (Curve c in Curves) { CA2.Insert(c, i); i += 1; } #endregion #region Create The New Fire Rated Layer element FloorType ft = new FilteredElementCollector(doc).WhereElementIsElementType().OfCategory(BuiltInCategory.OST_Floors).ToElements().Where(m => m.Name == "Fire Rated Layer").First() as FloorType; Transaction T = new Transaction(doc, "Fire Rated Layer Creation"); try { T.Start(); Floor F = doc.Create.NewFloor(CA2, ft, L, false); string s = Soffit.LookupParameter("Height Offset From Level").AsValueString(); double si = Convert.ToDouble(s); si = si + (Convert.ToDouble(Soffit.LookupParameter("Thickness").AsValueString())); F.LookupParameter("Height Offset From Level").SetValueString(si.ToString()); T.Commit(); } catch (Exception EX) { T.RollBack(); string EXmsg = EX.Message; } #endregion } } } } } catch (Exception ex) { string mesg = ex.Message; } }
/// <summary> /// Trims the CurveLoop contained in an IFCCurve by the start and optional end parameter values. /// </summary> /// <param name="id">The id of the IFC entity containing the directrix, for messaging purposes.</param> /// <param name="ifcCurve">The IFCCurve entity containing the CurveLoop to be trimmed.</param> /// <param name="startVal">The starting trim parameter.</param> /// <param name="origEndVal">The optional end trim parameter. If not supplied, assume no end trim.</param> /// <returns>The original curve loop, if no trimming has been done, otherwise a trimmed copy.</returns> private static CurveLoop TrimCurveLoop(int id, IFCCurve ifcCurve, double startVal, double?origEndVal) { CurveLoop origCurveLoop = ifcCurve.GetTheCurveLoop(); if (origCurveLoop == null || origCurveLoop.Count() == 0) { return(null); } // Trivial case: unbound curve. Curve possiblyUnboundCurve = origCurveLoop.First(); if (!possiblyUnboundCurve.IsBound) { if (!origEndVal.HasValue) { Importer.TheLog.LogError(id, "Can't trim unbound curve with no given end parameter.", true); } CurveLoop boundCurveLoop = new CurveLoop(); Curve boundCurve = possiblyUnboundCurve.Clone(); boundCurve.MakeBound(startVal, origEndVal.Value * ifcCurve.ParametericScaling); boundCurveLoop.Append(boundCurve); return(boundCurveLoop); } IList <double> curveLengths = new List <double>(); IList <Curve> loopCurves = new List <Curve>(); double totalParamLength = 0.0; bool allLines = true; foreach (Curve curve in origCurveLoop) { if (!(curve is Line)) { allLines = false; } double curveLength = curve.GetEndParameter(1) - curve.GetEndParameter(0); double currLength = ScaleCurveLengthForSweptSolid(curve, curveLength); loopCurves.Add(curve); curveLengths.Add(currLength); totalParamLength += currLength; } double endVal = origEndVal.HasValue ? origEndVal.Value : totalParamLength; double eps = MathUtil.Eps(); if (!CheckIfTrimParametersAreNeeded(id, ifcCurve, startVal, endVal, totalParamLength)) { return(origCurveLoop); } // Special cases: // if startval = 0 and endval = 1 and we have a polyline, then this likely means that the importing application // incorrectly set the extents to be the "whole" curve, when really this is just a portion of the curves // (the parametrization is described above). // As such, if the totalParamLength is not 1 but startVal = 0 and endVal = 1, we will warn but not trim. // This is not a hypothetical case: it occurs in several AllPlan 2017 files at least. if (allLines) { if ((!MathUtil.IsAlmostEqual(totalParamLength, 1.0)) && (MathUtil.IsAlmostZero(startVal) && MathUtil.IsAlmostEqual(endVal, 1.0))) { Importer.TheLog.LogWarning(id, "The Start Parameter for the trimming of this curve was set to 0, and the End Parameter was set to 1. " + "Most likely, this is an error in the sending application, and the trim extents are being ignored. " + "If this trim was intended, please contact Autodesk.", true); return(origCurveLoop); } } int numCurves = loopCurves.Count; double currentPosition = 0.0; int currCurve = 0; IList <Curve> newLoopCurves = new List <Curve>(); if (startVal > MathUtil.Eps()) { for (; currCurve < numCurves; currCurve++) { if (currentPosition + curveLengths[currCurve] < startVal + eps) { currentPosition += curveLengths[currCurve]; continue; } Curve newCurve = loopCurves[currCurve].Clone(); if (!MathUtil.IsAlmostEqual(currentPosition, startVal)) { double startParam = UnscaleSweptSolidCurveParam(loopCurves[currCurve], startVal - currentPosition); double endParam = newCurve.GetEndParameter(1); AdjustParamsIfNecessary(newCurve, ref startParam, ref endParam); newCurve.MakeBound(startParam, endParam); } newLoopCurves.Add(newCurve); break; } } if (endVal < totalParamLength - eps) { for (; currCurve < numCurves; currCurve++) { if (currentPosition + curveLengths[currCurve] < endVal - eps) { currentPosition += curveLengths[currCurve]; newLoopCurves.Add(loopCurves[currCurve]); continue; } Curve newCurve = loopCurves[currCurve].Clone(); if (!MathUtil.IsAlmostEqual(currentPosition + curveLengths[currCurve], endVal)) { double startParam = newCurve.GetEndParameter(0); double endParam = UnscaleSweptSolidCurveParam(loopCurves[currCurve], endVal - currentPosition); AdjustParamsIfNecessary(newCurve, ref startParam, ref endParam); newCurve.MakeBound(startParam, endParam); } newLoopCurves.Add(newCurve); break; } } CurveLoop trimmedCurveLoop = new CurveLoop(); foreach (Curve curve in newLoopCurves) { trimmedCurveLoop.Append(curve); } return(trimmedCurveLoop); }