public static PolyCurve Offset(this PolyCurve curve, double offset, Vector normal = null, bool tangentExtensions = false, double tolerance = Tolerance.Distance) { if (curve == null || curve.Length() < tolerance) { return(null); } //if there are only Line segmensts switching to polyline method which is more reliable if (curve.Curves.All(x => x is Line)) { Polyline polyline = ((Polyline)curve).Offset(offset, normal, tangentExtensions, tolerance); if (polyline == null) { return(null); } return(new PolyCurve { Curves = polyline.SubParts().Cast <ICurve>().ToList() }); } List <ICurve> subParts = curve.SubParts(); //Check if contains any circles, if so, handle them explicitly, and offset any potential leftovers by backcalling this method if (subParts.Any(x => x is Circle)) { IEnumerable <Circle> circles = subParts.Where(x => x is Circle).Cast <Circle>().Select(x => x.Offset(offset, normal, tangentExtensions, tolerance)); PolyCurve nonCirclePolyCurve = new PolyCurve { Curves = curve.Curves.Where(x => !(x is Circle)).ToList() }; if (nonCirclePolyCurve.Curves.Count != 0) { nonCirclePolyCurve = nonCirclePolyCurve.Offset(offset, normal, tangentExtensions, tolerance); } nonCirclePolyCurve.Curves.AddRange(circles); return(nonCirclePolyCurve); } if (!curve.IsPlanar(tolerance)) { BH.Engine.Reflection.Compute.RecordError("Offset works only on planar curves"); return(null); } if (curve.IsSelfIntersecting(tolerance)) { BH.Engine.Reflection.Compute.RecordError("Offset works only on non-self intersecting curves"); return(null); } if (offset == 0) { return(curve); } bool isClosed = curve.IsClosed(tolerance); if (normal == null) { if (!isClosed) { BH.Engine.Reflection.Compute.RecordError("Normal is missing. Normal vector is not needed only for closed curves"); return(null); } else { normal = curve.Normal(); } } if (offset > 0.05 * curve.Length()) { return((curve.Offset(offset / 2, normal, tangentExtensions, tolerance))?.Offset(offset / 2, normal, tangentExtensions, tolerance)); } PolyCurve result = new PolyCurve(); Vector normalNormalised = normal.Normalise(); //First - offseting each individual element List <ICurve> offsetCurves = new List <ICurve>(); foreach (ICurve crv in subParts) { if (crv.IOffset(offset, normal, false, tolerance) != null) { offsetCurves.Add(crv.IOffset(offset, normal, false, tolerance)); } } int counter = 0; //removing curves that are on a wrong side of the main curve for (int i = 0; i < offsetCurves.Count; i++) { Point sp = offsetCurves[i].IStartPoint(); Point ep = offsetCurves[i].IEndPoint(); Point mp = offsetCurves[i].IPointAtParameter(0.5); Point spOnCurve = curve.ClosestPoint(sp); Point epOnCurve = curve.ClosestPoint(ep); Point mpOnCurve = curve.ClosestPoint(mp); Vector sTan = curve.TangentAtPoint(spOnCurve, tolerance); Vector eTan = curve.TangentAtPoint(epOnCurve, tolerance); Vector mTan = curve.TangentAtPoint(mpOnCurve, tolerance); Vector sCheck = sp - spOnCurve; Vector eCheck = ep - epOnCurve; Vector mCheck = mp - mpOnCurve; Vector sCP = sTan.CrossProduct(sCheck).Normalise(); Vector eCP = eTan.CrossProduct(eCheck).Normalise(); Vector mCP = mTan.CrossProduct(mCheck).Normalise(); if (offset > 0) { if (sCP.IsEqual(normalNormalised, tolerance) && eCP.IsEqual(normalNormalised, tolerance) && mCP.IsEqual(normalNormalised, tolerance)) { offsetCurves.RemoveAt(i); i--; counter++; } } else { if (!sCP.IsEqual(normalNormalised, tolerance) && !eCP.IsEqual(normalNormalised, tolerance) && !mCP.IsEqual(normalNormalised, tolerance)) { offsetCurves.RemoveAt(i); i--; counter++; } } } //Again if there are only Line segments switching to polyline method as it is more reliable if (offsetCurves.All(x => x is Line)) { Polyline polyline = new Polyline { ControlPoints = curve.DiscontinuityPoints() }; result.Curves.AddRange(polyline.Offset(offset, normal, tangentExtensions, tolerance).SubParts()); return(result); } bool connectingError = false; //Filleting offset curves to create continuous curve for (int i = 0; i < offsetCurves.Count; i++) { int j; if (i == offsetCurves.Count - 1) { if (isClosed) { j = 0; } else { break; } } else { j = i + 1; } PolyCurve temp = offsetCurves[i].Fillet(offsetCurves[j], tangentExtensions, true, false, tolerance); if (temp == null) //trying to fillet with next curve { offsetCurves.RemoveAt(j); if (j == 0) { i--; } if (j == offsetCurves.Count) { j = 0; } temp = offsetCurves[i].Fillet(offsetCurves[j], tangentExtensions, true, false, tolerance); } if (!(temp == null)) //inserting filetted curves { if (j != 0) { offsetCurves.RemoveRange(i, 2); offsetCurves.InsertRange(i, temp.Curves); } else { offsetCurves.RemoveAt(i); offsetCurves.RemoveAt(0); offsetCurves.InsertRange(i - 1, temp.Curves); } i = i + temp.Curves.Count - 2; } else { connectingError = true; } } //removing curves that are to close to the main curve for (int i = 0; i < offsetCurves.Count; i++) { if ((offsetCurves[i].IPointAtParameter(0.5).Distance(curve) + tolerance < Math.Abs(offset) && (offsetCurves[i].IStartPoint().Distance(curve) + tolerance < Math.Abs(offset) || offsetCurves[i].IEndPoint().Distance(curve) + tolerance < Math.Abs(offset)))) { PolyCurve temp = offsetCurves[((i - 1) + offsetCurves.Count) % offsetCurves.Count].Fillet(offsetCurves[(i + 1) % offsetCurves.Count], tangentExtensions, true, false, tolerance); if (temp != null) { if (i == 0) { offsetCurves.RemoveRange(0, 2); offsetCurves.RemoveAt(offsetCurves.Count - 1); offsetCurves.InsertRange(0, temp.Curves); i = temp.Curves.Count - 1; } else if (i == offsetCurves.Count - 1) { offsetCurves.RemoveRange(i - 1, 2); offsetCurves.RemoveAt(0); offsetCurves.InsertRange(offsetCurves.Count - 1, temp.Curves); i = offsetCurves.Count - 1; } else { offsetCurves.RemoveRange(i - 1, 3); offsetCurves.InsertRange(i - 1, temp.Curves); i = i - 3 + temp.Curves.Count; } } if (offsetCurves.Count < 1) { Reflection.Compute.ClearCurrentEvents(); Reflection.Compute.RecordError("Method failed to produce correct offset. Returning null."); return(null); } counter++; } } Reflection.Compute.ClearCurrentEvents(); if (connectingError) { Reflection.Compute.RecordWarning("Couldn't connect offset subCurves properly."); } if (offsetCurves.Count == 0) { Reflection.Compute.RecordError("Method failed to produce correct offset. Returning null."); return(null); } List <PolyCurve> resultList = Compute.IJoin(offsetCurves, tolerance); if (resultList.Count == 1) { result = resultList[0]; } else { result.Curves = offsetCurves; Reflection.Compute.RecordWarning("Offset may be wrong. Please inspect the results."); } if (counter > 0) { Reflection.Compute.RecordWarning("Reduced " + counter + " line(s). Please inspect the results."); } if (result.IsSelfIntersecting(tolerance) || result.CurveIntersections(curve, tolerance).Count != 0) { Reflection.Compute.RecordWarning("Intersections occured. Please inspect the results."); } if (isClosed && !result.IsClosed(tolerance)) { Reflection.Compute.RecordError("Final curve is not closed. Please inspect the results."); } return(result); }
/***************************************************/ private static PolyCurve Fillet(this ICurve curve1, ICurve curve2, bool tangentExtensions, bool keepCurve1StartPoint, bool keepCurve2StartPoint, double tolerance = Tolerance.Distance) { //TODO: //Write a proper fillet method, test and make it public if (!((curve1 is Line || curve1 is Arc) && (curve2 is Line || curve2 is Arc))) //for now works only with combinations of lines and arcs { Reflection.Compute.RecordError("Private method fillet is implemented only for PolyCurves consisting of Lines or Arcs."); return(null); } List <PolyCurve> joinCurves = Compute.IJoin(new List <ICurve> { curve1, curve2 }, tolerance).ToList(); if (joinCurves.Count == 1) { return(joinCurves[0]); } List <ICurve> resultCurves = new List <ICurve>(); bool C1SP = keepCurve1StartPoint; bool C2SP = keepCurve2StartPoint; List <Point> intersections = curve1.ICurveIntersections(curve2, tolerance); if (intersections.Count > 2) { Reflection.Compute.RecordError("Invalid number of intersections between curves. Two lines/arcs can have no more than two intersections."); } else if (intersections.Count == 2 || intersections.Count == 1) { Point intersection = intersections[0]; if (intersections.Count == 2) { double maxdist = double.MaxValue; if (C1SP) { foreach (Point p in intersections) { double dist = p.SquareDistance(curve1.IStartPoint()); if (dist < maxdist) { intersection = p; maxdist = dist; } } } else { foreach (Point p in intersections) { double dist = p.SquareDistance(curve1.IEndPoint()); if (dist < maxdist) { intersection = p; maxdist = dist; } } } } else { intersection = intersections[0]; } if (C1SP && C2SP) { resultCurves.AddRange(curve1.ExtendToPoint(curve1.IStartPoint(), intersection, tangentExtensions, tolerance)); resultCurves.AddRange(curve2.ExtendToPoint(curve2.IStartPoint(), intersection, tangentExtensions, tolerance)); resultCurves[1] = resultCurves[1].IFlip(); } else if (C1SP && !C2SP) { resultCurves.AddRange(curve1.ExtendToPoint(curve1.IStartPoint(), intersection, tangentExtensions, tolerance)); resultCurves.AddRange(curve2.ExtendToPoint(intersection, curve2.IEndPoint(), tangentExtensions, tolerance)); } else if (!C1SP && C2SP) { resultCurves.AddRange(curve1.ExtendToPoint(intersection, curve1.IEndPoint(), tangentExtensions, tolerance)); resultCurves.AddRange(curve2.ExtendToPoint(curve2.IStartPoint(), intersection, tangentExtensions, tolerance)); resultCurves[0] = resultCurves[0].IFlip(); resultCurves[1] = resultCurves[1].IFlip(); } else { resultCurves.AddRange(curve1.ExtendToPoint(intersection, curve1.IEndPoint(), tangentExtensions, tolerance)); resultCurves.AddRange(curve2.ExtendToPoint(intersection, curve2.IEndPoint(), tangentExtensions, tolerance)); resultCurves[0] = resultCurves[0].IFlip(); } } else { if (curve1 is Line && curve2 is Line) { Point intersection = (curve1 as Line).LineIntersection(curve2 as Line, true, tolerance); if (C1SP && C2SP) { if ((curve1.IStartPoint().Distance((curve2 as Line), true) < curve1.IEndPoint().Distance((curve2 as Line), true) && !intersection.IIsOnCurve(curve1)) || (curve2.IStartPoint().Distance((curve1 as Line), true) < curve2.IEndPoint().Distance((curve1 as Line), true) && !intersection.IIsOnCurve(curve2))) { Reflection.Compute.RecordWarning("Couldn't provide correct fillet for given input"); return(null); } resultCurves.AddRange(curve1.ExtendToPoint(curve1.IStartPoint(), intersection, tangentExtensions, tolerance)); resultCurves.AddRange(curve2.ExtendToPoint(curve2.IStartPoint(), intersection, tangentExtensions, tolerance)); resultCurves[1] = resultCurves[1].IFlip(); } else if (C1SP && !C2SP) { if ((curve1.IStartPoint().Distance((curve2 as Line), true) < curve1.IEndPoint().Distance((curve2 as Line), true) && !intersection.IIsOnCurve(curve1)) || (curve2.IStartPoint().Distance((curve1 as Line), true) > curve2.IEndPoint().Distance((curve1 as Line), true) && !intersection.IIsOnCurve(curve2))) { Reflection.Compute.RecordWarning("Couldn't provide correct fillet for given input"); return(null); } resultCurves.AddRange(curve1.ExtendToPoint(curve1.IStartPoint(), intersection, tangentExtensions, tolerance)); resultCurves.AddRange(curve2.ExtendToPoint(intersection, curve2.IEndPoint(), tangentExtensions, tolerance)); } else if (!C1SP && C2SP) { if ((curve1.IStartPoint().Distance((curve2 as Line), true) > curve1.IEndPoint().Distance((curve2 as Line), true) && !intersection.IIsOnCurve(curve1)) || (curve2.IStartPoint().Distance((curve1 as Line), true) < curve2.IEndPoint().Distance((curve1 as Line), true) && !intersection.IIsOnCurve(curve2))) { Reflection.Compute.RecordWarning("Couldn't provide correct fillet for given input"); return(null); } resultCurves.AddRange(curve1.ExtendToPoint(intersection, curve1.IEndPoint(), tangentExtensions, tolerance)); resultCurves.AddRange(curve2.ExtendToPoint(curve2.IStartPoint(), intersection, tangentExtensions, tolerance)); resultCurves[0] = resultCurves[0].IFlip(); resultCurves[1] = resultCurves[1].IFlip(); } else { if ((curve1.IStartPoint().Distance((curve2 as Line), true) > curve1.IEndPoint().Distance((curve2 as Line), true) && !intersection.IIsOnCurve(curve1)) || (curve2.IStartPoint().Distance((curve1 as Line), true) > curve2.IEndPoint().Distance((curve1 as Line), true) && !intersection.IIsOnCurve(curve2))) { Reflection.Compute.RecordWarning("Couldn't provide correct fillet for given input"); return(null); } resultCurves.AddRange(curve1.ExtendToPoint(intersection, curve1.IEndPoint(), tangentExtensions, tolerance)); resultCurves.AddRange(curve2.ExtendToPoint(intersection, curve2.IEndPoint(), tangentExtensions, tolerance)); resultCurves[0] = resultCurves[0].IFlip(); } } else { Point intersection; if (!tangentExtensions) { PolyCurve pCurve1 = new PolyCurve(); PolyCurve pCurve2 = new PolyCurve(); if (curve1 is Arc) { pCurve1.Curves.Add(new Circle { Centre = (curve1 as Arc).Centre(), Normal = (curve1 as Arc).Normal(), Radius = (curve1 as Arc).Radius }); } else { pCurve1.Curves.Add(new Line { Start = (curve1 as Line).Start, End = (curve1 as Line).End, Infinite = true }); } if (curve2 is Arc) { pCurve2.Curves.Add(new Circle { Centre = (curve2 as Arc).Centre(), Normal = (curve2 as Arc).Normal(), Radius = (curve2 as Arc).Radius }); } else { pCurve2.Curves.Add(new Line { Start = (curve2 as Line).Start, End = (curve2 as Line).End, Infinite = true }); } List <Point> curveIntersections = pCurve1.CurveIntersections(pCurve2, tolerance); if (curveIntersections.Count == 0) { Reflection.Compute.RecordError("Curves' extensions do not intersect"); return(null); } if (C1SP && C2SP) { intersection = curveIntersections.ClosestPoint(curve1.IEndPoint()); resultCurves.AddRange(curve1.ExtendToPoint(curve1.IStartPoint(), intersection, tangentExtensions, tolerance)); resultCurves.AddRange(curve2.ExtendToPoint(curve2.IStartPoint(), intersection, tangentExtensions, tolerance)); resultCurves[1] = resultCurves[1].IFlip(); } else if (C1SP && !C2SP) { intersection = curveIntersections.ClosestPoint(curve1.IEndPoint()); resultCurves.AddRange(curve1.ExtendToPoint(curve1.IStartPoint(), intersection, tangentExtensions, tolerance)); resultCurves.AddRange(curve2.ExtendToPoint(intersection, curve2.IEndPoint(), tangentExtensions, tolerance)); } else if (!C1SP && C2SP) { intersection = curveIntersections.ClosestPoint(curve1.IStartPoint()); resultCurves.AddRange(curve1.ExtendToPoint(intersection, curve1.IEndPoint(), tangentExtensions, tolerance)); resultCurves.AddRange(curve2.ExtendToPoint(curve2.IStartPoint(), intersection, tangentExtensions, tolerance)); resultCurves[0] = resultCurves[0].IFlip(); resultCurves[1] = resultCurves[1].IFlip(); } else { intersection = curveIntersections.ClosestPoint(curve1.IStartPoint()); resultCurves.AddRange(curve1.ExtendToPoint(intersection, curve1.IEndPoint(), tangentExtensions, tolerance)); resultCurves.AddRange(curve2.ExtendToPoint(intersection, curve2.IEndPoint(), tangentExtensions, tolerance)); resultCurves[0] = resultCurves[0].IFlip(); } } else { if (C1SP && C2SP) { Line tanLine1 = Create.Line(curve1.IEndPoint(), curve1.IEndDir() / tolerance); tanLine1.Infinite = false; PolyCurve pCurve1 = new PolyCurve { Curves = { curve1, tanLine1 } }; Line tanLine2 = Create.Line(curve2.IEndPoint(), curve2.IEndDir() / tolerance); tanLine2.Infinite = false; PolyCurve pCurve2 = new PolyCurve { Curves = { curve2, tanLine2 } }; List <Point> curveIntersecions = pCurve1.CurveIntersections(pCurve2, tolerance); if (curveIntersecions.Count > 0) { intersection = curveIntersecions.ClosestPoint(curve1.IEndPoint()); } else { Reflection.Compute.RecordWarning("Couldn't create fillet"); return(null); } PolyCurve subResult1 = new PolyCurve { Curves = curve1.ExtendToPoint(curve1.IStartPoint(), intersection, tangentExtensions, tolerance).ToList() }; PolyCurve subResult2 = new PolyCurve { Curves = curve2.ExtendToPoint(curve2.IStartPoint(), intersection, tangentExtensions, tolerance).ToList() }; subResult2 = subResult2.Flip(); resultCurves.AddRange(subResult1.Curves); resultCurves.AddRange(subResult2.Curves); } else if (C1SP && !C2SP) { Line tanLine1 = Create.Line(curve1.IEndPoint(), curve1.IEndDir() / tolerance); tanLine1.Infinite = false; PolyCurve pCurve1 = new PolyCurve { Curves = { curve1, tanLine1 } }; Line tanLine2 = Create.Line(curve2.IStartPoint(), curve2.IStartDir().Reverse() / tolerance); tanLine2.Infinite = false; PolyCurve pCurve2 = new PolyCurve { Curves = { tanLine2, curve2 } }; List <Point> curveIntersecions = pCurve1.ICurveIntersections(pCurve2, tolerance); if (curveIntersecions.Count > 0) { intersection = curveIntersecions.ClosestPoint(curve1.IEndPoint()); } else { Reflection.Compute.RecordWarning("Couldn't create fillet"); return(null); } resultCurves.AddRange(curve1.ExtendToPoint(curve1.IStartPoint(), intersection, tangentExtensions, tolerance)); resultCurves.AddRange(curve2.ExtendToPoint(intersection, curve2.IEndPoint(), tangentExtensions, tolerance)); } else if (!C1SP && C2SP) { Line tanLine1 = Create.Line(curve1.IStartPoint(), curve1.IStartDir().Reverse() / tolerance); tanLine1.Infinite = false; PolyCurve pCurve1 = new PolyCurve { Curves = { tanLine1, curve1 } }; Line tanLine2 = Create.Line(curve2.IEndPoint(), curve2.IEndDir() / tolerance); tanLine2.Infinite = false; PolyCurve pCurve2 = new PolyCurve { Curves = { curve2, tanLine2 } }; List <Point> curveIntersecions = pCurve1.ICurveIntersections(pCurve2, tolerance); if (curveIntersecions.Count > 0) { intersection = curveIntersecions.ClosestPoint(curve1.IStartPoint()); } else { Reflection.Compute.RecordWarning("Couldn't create fillet"); return(null); } PolyCurve subResult1 = new PolyCurve { Curves = curve1.ExtendToPoint(intersection, curve1.IEndPoint(), tangentExtensions, tolerance).ToList() }; PolyCurve subResult2 = new PolyCurve { Curves = curve2.ExtendToPoint(curve2.IStartPoint(), intersection, tangentExtensions, tolerance).ToList() }; subResult1 = subResult1.Flip(); subResult2 = subResult2.Flip(); resultCurves.AddRange(subResult1.Curves); resultCurves.AddRange(subResult2.Curves); } else { Line tanLine1 = Create.Line(curve1.IStartPoint(), curve1.IStartDir().Reverse() / tolerance); tanLine1.Infinite = false; PolyCurve pCurve1 = new PolyCurve { Curves = { tanLine1, curve1 } }; Line tanLine2 = Create.Line(curve2.IStartPoint(), curve2.IStartDir().Reverse() / tolerance); tanLine2.Infinite = false; PolyCurve pCurve2 = new PolyCurve { Curves = { tanLine2, curve2 } }; List <Point> curveIntersecions = pCurve1.ICurveIntersections(pCurve2, tolerance); if (curveIntersecions.Count > 0) { intersection = curveIntersecions.ClosestPoint(curve1.IStartPoint()); } else { Reflection.Compute.RecordWarning("Couldn't create fillet"); return(null); } PolyCurve subResult1 = new PolyCurve { Curves = curve1.ExtendToPoint(intersection, curve1.IEndPoint(), tangentExtensions, tolerance).ToList() }; PolyCurve subResult2 = new PolyCurve { Curves = curve2.ExtendToPoint(intersection, curve2.IEndPoint(), tangentExtensions, tolerance).ToList() }; subResult1 = subResult1.Flip(); resultCurves.AddRange(subResult1.Curves); resultCurves.AddRange(subResult2.Curves); } } } } for (int i = resultCurves.Count - 1; i >= 0; i--) { if (resultCurves[i] is PolyCurve) { PolyCurve temp = (PolyCurve)resultCurves[i]; resultCurves.RemoveAt(i); resultCurves.InsertRange(i, temp.Curves); } } PolyCurve result = new PolyCurve { Curves = resultCurves }; return(result); }
public static PolyCurve OffsetVariable(this PolyCurve curve, List <double> offsets, Vector normal = null, bool tangentExtensions = false, double tolerance = Tolerance.Distance) { //TODO: //Migrate to Geometry Engine and align with Offset method if (curve == null || curve.Length() < tolerance) { return(null); } List <ICurve> subParts = curve.SubParts(); if (subParts.Count != offsets.Count) { BH.Engine.Reflection.Compute.RecordError("PolyCurve segment count does not match amount of offset values provided."); return(null); } //Check if contains any circles, if so, handle them explicitly, and offset any potential leftovers by backcalling this method if (subParts.Any(x => x is Circle)) { curve.Offset(offsets[0]); return(null); } if (!curve.IsPlanar(tolerance)) { BH.Engine.Reflection.Compute.RecordError("Offset works only on planar curves"); return(null); } if (curve.IsSelfIntersecting(tolerance)) { BH.Engine.Reflection.Compute.RecordError("Offset works only on non-self intersecting curves"); return(null); } bool isClosed = curve.IsClosed(tolerance); if (normal == null) { if (!isClosed) { BH.Engine.Reflection.Compute.RecordError("Normal is missing. Normal vector is not needed only for closed curves"); return(null); } else { normal = curve.Normal(); } } PolyCurve result = new PolyCurve(); Vector normalNormalised = normal.Normalise(); //First - offseting each individual element List <ICurve> offsetCurves = new List <ICurve>(); for (int i = 0; i < subParts.Count; i++) { if (subParts[i].IOffset(offsets[i], normal, false, tolerance) != null) { offsetCurves.Add(subParts[i].IOffset(offsets[i], normal, false, tolerance)); } } bool connectingError = false; //Filleting offset curves to create continuous curve for (int i = 0; i < offsetCurves.Count; i++) { int j; if (i == offsetCurves.Count - 1) { if (isClosed) { j = 0; } else { break; } } else { j = i + 1; } PolyCurve temp = offsetCurves[i].Fillet(offsetCurves[j], tangentExtensions, true, false, tolerance); if (temp == null) //trying to fillet with next curve { offsetCurves.RemoveAt(j); if (j == 0) { i--; } if (j == offsetCurves.Count) { j = 0; } temp = offsetCurves[i].Fillet(offsetCurves[j], tangentExtensions, true, false, tolerance); } if (!(temp == null)) //inserting filetted curves { if (j != 0) { offsetCurves.RemoveRange(i, 2); offsetCurves.InsertRange(i, temp.Curves); } else { offsetCurves.RemoveAt(i); offsetCurves.RemoveAt(0); offsetCurves.InsertRange(i - 1, temp.Curves); } i = i + temp.Curves.Count - 2; } else { connectingError = true; } } Reflection.Compute.ClearCurrentEvents(); if (connectingError) { Reflection.Compute.RecordWarning("Couldn't connect offset subCurves properly."); } if (offsetCurves.Count == 0) { Reflection.Compute.RecordError("Method failed to produce correct offset. Returning null."); return(null); } List <PolyCurve> resultList = Geometry.Compute.IJoin(offsetCurves, tolerance); if (resultList.Count == 1) { result = resultList[0]; } else { result.Curves = offsetCurves; Reflection.Compute.RecordWarning("Offset may be wrong. Please inspect the results."); } if (result.IsSelfIntersecting(tolerance) || result.CurveIntersections(curve, tolerance).Count != 0) { Reflection.Compute.RecordWarning("Intersections occured. Please inspect the results."); } if (isClosed && !result.IsClosed(tolerance)) { Reflection.Compute.RecordError("Final curve is not closed. Please inspect the results."); } return(result); }