public static IList <CurveLoop> TrimCurveLoops(int id, IFCCurve ifcCurve, double startVal, double?origEndVal) { if (ifcCurve.CurveLoops == null) { return(null); } if (!NeedsTrimming(startVal, origEndVal)) { return(ifcCurve.CurveLoops); } if (ifcCurve.CurveLoops.Count != 1) { Importer.TheLog.LogError(id, "Ignoring potential trimming for disjoint curve.", false); return(ifcCurve.CurveLoops); } CurveLoop trimmedDirectrix = TrimCurveLoop(id, ifcCurve, startVal, origEndVal); if (trimmedDirectrix == null) { return(null); } IList <CurveLoop> trimmedDirectrices = new List <CurveLoop>(); trimmedDirectrices.Add(trimmedDirectrix); return(trimmedDirectrices); }
/// <summary> /// Specifically check if the trim parameters are likely set incorrectly to the sum of the lengths of the curve segments, /// if some of the curve segments are line segments. /// </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="endVal">The ending trim parameter.</param> /// <param name="totalParamLength">The total parametric length of the curve, as defined by IFC.</param> /// <returns>False if the trim parameters are thought to be invalid or unnecessary, true otherwise.</returns> private static bool CheckIfTrimParametersAreNeeded(int id, IFCCurve ifcCurve, double startVal, double endVal, double totalParamLength) { // This check allows for some leniency in the setting of startVal and endVal; we assume that: // 1. If the parameter range is equal, that an offset value is OK; don't trim. // 2. If the start parameter is 0 and the curveParamLength is greater than the total length, don't trim. double curveParamLength = endVal - startVal; if (MathUtil.IsAlmostEqual(curveParamLength, totalParamLength)) { return(false); } if (MathUtil.IsAlmostZero(startVal) && totalParamLength < curveParamLength - MathUtil.Eps()) { return(false); } if (!(ifcCurve is IFCCompositeCurve)) { return(true); } double totalRawParametricLength = 0.0; foreach (IFCCurve curveSegment in (ifcCurve as IFCCompositeCurve).Segments) { if (!(curveSegment is IFCTrimmedCurve)) { return(true); } IFCTrimmedCurve trimmedCurveSegment = curveSegment as IFCTrimmedCurve; if (trimmedCurveSegment.Trim1 == null || trimmedCurveSegment.Trim2 == null) { return(true); } totalRawParametricLength += (trimmedCurveSegment.Trim2.Value - trimmedCurveSegment.Trim1.Value); } // Error in some Tekla files - lines are parameterized by length, instead of 1.0 (as is correct). // Warn and ignore the parameter length. This must come after the MathUtil.IsAlmostEqual(curveParamLength, totalParamLength) // check above, since we don't want to warn if curveParamLength == totalParamLength. if (MathUtil.IsAlmostEqual(curveParamLength, totalRawParametricLength)) { Importer.TheLog.LogWarning(id, "The total parameter length for this curve is equal to the sum of the parameter deltas, " + "and not the parameter length as defined in IFC. " + "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(false); } return(true); }
/// <summary> /// Specifically check if the trim parameters are likely set incorrectly to the sum of the lengths of the curve segments, /// if some of the curve segments are line segments. /// </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="curveParamLength">The delta between the start and end parameters of the overall curve.</param> /// <returns>False if the trim parameters are thought to be invalid, true otherwise.</returns> private static bool CheckIfTrimParametersAreValidForSomeInvalidities(int id, IFCCurve ifcCurve, double curveParamLength) { if (!(ifcCurve is IFCCompositeCurve)) { return(true); } double totalRawParametricLength = 0.0; foreach (IFCCurve curveSegment in (ifcCurve as IFCCompositeCurve).Segments) { if (!(curveSegment is IFCTrimmedCurve)) { return(true); } IFCTrimmedCurve trimmedCurveSegment = curveSegment as IFCTrimmedCurve; if (trimmedCurveSegment.Trim1 == null || trimmedCurveSegment.Trim2 == null) { return(true); } totalRawParametricLength += (trimmedCurveSegment.Trim2.Value - trimmedCurveSegment.Trim1.Value); } if (MathUtil.IsAlmostEqual(curveParamLength, totalRawParametricLength)) { Importer.TheLog.LogWarning(id, "The total parameter length for this curve is equal to the sum of the parameter deltas, " + "and not the parameter length as defined in IFC. " + "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(false); } return(true); }
/// <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); }
/// <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> public static CurveLoop TrimCurveLoop(int id, IFCCurve ifcCurve, double startVal, double?origEndVal) { CurveLoop origCurveLoop = ifcCurve.GetCurveLoop(); if (origCurveLoop == null) { return(null); } // Trivial case: no trimming. if (!origEndVal.HasValue && MathUtil.IsAlmostZero(startVal)) { return(origCurveLoop); } 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; // This check allows for some leniency in the setting of startVal and endVal; we assume that if the parameter range // is equal, that an offset value is OK. double curveParamLength = endVal - startVal; if (MathUtil.IsAlmostEqual(curveParamLength, totalParamLength)) { return(origCurveLoop); } // Error in some Tekla files - lines are parameterized by length, instead of 1.0 (as is correct). // Warn and ignore the parameter length. This must come after the MathUtil.IsAlmostEqual(curveParamLength, totalParamLength) // check above, since we don't want to warn if curveParamLength == totalParamLength. if (!CheckIfTrimParametersAreValidForSomeInvalidities(id, ifcCurve, curveParamLength)) { 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 + MathUtil.Eps()) { currentPosition += curveLengths[currCurve]; continue; } Curve newCurve = loopCurves[currCurve].Clone(); if (!MathUtil.IsAlmostEqual(currentPosition, startVal)) { newCurve.MakeBound(UnscaleSweptSolidCurveParam(loopCurves[currCurve], startVal - currentPosition), newCurve.GetEndParameter(1)); } newLoopCurves.Add(newCurve); break; } } if (endVal < totalParamLength - MathUtil.Eps()) { for (; currCurve < numCurves; currCurve++) { if (currentPosition + curveLengths[currCurve] < endVal - MathUtil.Eps()) { currentPosition += curveLengths[currCurve]; newLoopCurves.Add(loopCurves[currCurve]); continue; } Curve newCurve = loopCurves[currCurve].Clone(); if (!MathUtil.IsAlmostEqual(currentPosition + curveLengths[currCurve], endVal)) { newCurve.MakeBound(newCurve.GetEndParameter(0), UnscaleSweptSolidCurveParam(loopCurves[currCurve], endVal - currentPosition)); } newLoopCurves.Add(newCurve); break; } } CurveLoop trimmedCurveLoop = new CurveLoop(); foreach (Curve curve in newLoopCurves) { trimmedCurveLoop.Append(curve); } return(trimmedCurveLoop); }