/***************************************************/ /**** Split curve at points ****/ /***************************************************/ public static List <Arc> SplitAtPoints(this Arc arc, List <Point> points, double tolerance = Tolerance.Distance) { if (!points.Any()) { return new List <Arc> { arc.DeepClone() } } ; List <Arc> result = new List <Arc>(); List <Point> cPts = new List <Point>(); Vector normal = arc.Normal(); foreach (Point point in points) { if (point.IsOnCurve(arc, tolerance)) { cPts.Add(point); } } cPts.Add(arc.StartPoint()); cPts.Add(arc.EndPoint()); cPts = cPts.CullDuplicates(tolerance); cPts = cPts.SortAlongCurve(arc, tolerance); if (arc.EndAngle - 2 * Math.PI < tolerance && arc.EndAngle - 2 * Math.PI > -tolerance) { cPts.Add(arc.EndPoint()); } if (cPts.Count > 2) { Double startAng = arc.StartAngle; Double endAng = arc.EndAngle; Double tmpAng = 0; Arc tmpArc; for (int i = 1; i < cPts.Count; i++) { tmpArc = arc.DeepClone(); tmpArc.StartAngle = startAng; tmpAng = (2 * Math.PI + (cPts[i - 1] - arc.Centre()).SignedAngle(cPts[i] - arc.Centre(), normal)) % (2 * Math.PI); endAng = startAng + tmpAng; tmpArc.EndAngle = endAng; result.Add(tmpArc); startAng = endAng; } } else { result.Add(arc.DeepClone()); } return(result); }
/***************************************************/ /**** Public Methods - Curves ****/ /***************************************************/ public static Point ClosestPoint(this Arc curve, Point point, double tolerance = Tolerance.Distance) { if (point.SquareDistance(curve.Centre()) <= tolerance * tolerance) { return(curve.StartPoint()); } Point center = curve.Centre(); Point midPoint = curve.PointAtParameter(0.5); Plane p = curve.FitPlane(); Point onCircle = center + (point.Project(p) - center).Normalise() * curve.Radius; double sqrd = midPoint.SquareDistance(curve.StartPoint()); return(midPoint.SquareDistance(onCircle) <= sqrd ? onCircle : onCircle.ClosestPoint(new List <Point> { curve.StartPoint(), curve.EndPoint() })); }
/***************************************************/ /**** Public Methods - Curve / curve ****/ /***************************************************/ public static bool IsContaining(this Arc curve1, ICurve curve2, bool acceptOnEdge = true, double tolerance = Tolerance.Distance) { if (!curve1.IsClosed(tolerance)) { return(false); } Circle circle = new Circle { Centre = curve1.Centre(), Radius = curve1.Radius(), Normal = curve1.FitPlane().Normal }; return(circle.IsContaining(curve2)); }
/***************************************************/ /**** Public Methods - Curve / points ****/ /***************************************************/ public static bool IsContaining(this Arc curve, List <Point> points, bool acceptOnEdge = true, double tolerance = Tolerance.Distance) { if (!curve.IsClosed(tolerance)) { return(false); } Circle circle = new Circle { Centre = curve.Centre(), Radius = curve.Radius(), Normal = curve.FitPlane().Normal }; return(circle.IsContaining(points, acceptOnEdge, tolerance)); }
/***************************************************/ /**** Public Methods - Curves ****/ /***************************************************/ public static Point ClosestPoint(this Arc arc, Point point) { Point center = arc.Centre(); Point midPoint = arc.PointAtParameter(0.5); Plane p = arc.FitPlane(); Point onCircle = center + (point.Project(p) - center).Normalise() * arc.Radius; double sqrd = midPoint.SquareDistance(arc.StartPoint()); return(midPoint.SquareDistance(onCircle) <= sqrd ? onCircle : onCircle.ClosestPoint(new List <Point> { arc.StartPoint(), arc.EndPoint() })); }
/***************************************************/ public static List <Point> LineIntersections(this Arc arc, Line line, bool useInfiniteLine = false, double tolerance = Tolerance.Distance) { Line l = line.DeepClone(); l.Infinite = useInfiniteLine ? true : l.Infinite; List <Point> iPts = new List <Point>(); Point midPoint = arc.PointAtParameter(0.5); Point center = arc.Centre(); //Check if curves are coplanar if (Math.Abs(arc.CoordinateSystem.Z.DotProduct(l.Direction())) > Tolerance.Angle) { //Curves not coplanar Point pt = l.PlaneIntersection((Plane)arc.CoordinateSystem); if (pt != null && Math.Abs(pt.Distance(center) - arc.Radius) <= tolerance) { iPts.Add(pt); } } else { //Curves coplanar Circle c = new Circle { Centre = center, Normal = arc.CoordinateSystem.Z, Radius = arc.Radius }; iPts = c.LineIntersections(l); } List <Point> output = new List <Point>(); double halfAngle = arc.Angle() / 2; double tolAngle = tolerance / arc.Radius; double sqrd = 2 * Math.Pow(arc.Radius, 2) * (1 - Math.Cos(Math.Abs(halfAngle + tolAngle))); // Cosine rule { foreach (Point pt in iPts) { if ((l.Infinite || pt.Distance(l) <= tolerance) && midPoint.SquareDistance(pt) <= sqrd) { output.Add(pt); } } } return(output); }
/***************************************************/ /**** Public Methods - Curves ****/ /***************************************************/ public static NurbsCurve ToNurbsCurve(this Arc arc) { { double angle = arc.EndAngle - arc.StartAngle; Point centre = arc.Centre(); int nbPts = 1 + 2 * (int)Math.Ceiling(2 * angle / Math.PI); double factor = Math.Cos(angle / (nbPts - 1)); // Create the points List <Point> points = new List <Point>(); for (int i = 0; i < nbPts; i++) { double t = i * 1.0 / (nbPts - 1); Point pt = arc.PointAtParameter(t); if (i % 2 == 1) { pt = centre + (pt - centre) / factor; } points.Add(pt); } // Create the knots double knotStep = 2.0 / (nbPts - 1); List <double> knots = new List <double>(); for (int i = 0; i < (nbPts + 1) / 2; i++) { knots.Add(i * knotStep); knots.Add(i * knotStep); } // Create the weights List <double> weights = new List <double>(); for (int i = 0; i < nbPts; i++) { double w = (i % 2 == 0) ? 1.0 : factor; weights.Add(w); } return(new NurbsCurve { ControlPoints = points, Knots = knots, Weights = weights }); } }
/***************************************************/ public static Output <Point, Point> CurveProximity(this Arc curve1, Circle curve2, double tolerance = Tolerance.Distance) { List <Point> cIntersections = curve1.CurveIntersections(curve2); if (cIntersections.Count > 0) { return new Output <Point, Point> { Item1 = cIntersections[0], Item2 = cIntersections[0] } } ; Output <Point, Point> result = new Output <Point, Point>(); Plane ftPln1 = curve1.FitPlane(); Plane ftPln2 = curve2.FitPlane(); List <Point> intPts = new List <Point>(); Point tmp = null; if ((intPts = curve1.PlaneIntersections(ftPln2)).Count != 0) { if (intPts.Count == 1) { tmp = intPts[0]; } else { if (intPts[0].Distance(curve2) < intPts[1].Distance(curve2)) { tmp = intPts[0]; } else { tmp = intPts[1]; } } } else if ((intPts = curve2.PlaneIntersections(ftPln1)).Count != 0) { if (intPts.Count == 1) { if (tmp == null) { tmp = intPts[0]; } else if (tmp.Distance(curve2) > intPts[0].Distance(curve1)) { tmp = intPts[0]; } } else { if (intPts[0].Distance(curve1) < intPts[1].Distance(curve1)) { if (tmp == null) { tmp = intPts[0]; } else if (tmp.Distance(curve2) > intPts[0].Distance(curve1)) { tmp = intPts[0]; } } else { if (tmp == null) { tmp = intPts[1]; } else if (tmp.Distance(curve2) > intPts[1].Distance(curve1)) { tmp = intPts[1]; } } } } Output <Point, Point> oldresult = new Output <Point, Point>(); Output <Point, Point> oldresult2 = new Output <Point, Point>(); Output <Point, Point> result2 = new Output <Point, Point>(); if (tmp != null) { if (tmp.IsOnCurve(curve1)) { result.Item1 = tmp; result.Item2 = curve2.ClosestPoint(result.Item1); } else { result.Item2 = tmp; result.Item1 = curve1.ClosestPoint(result.Item2); } do { oldresult.Item1 = result.Item1; oldresult.Item2 = result.Item2; result.Item1 = curve2.ClosestPoint(result.Item2); result.Item2 = curve1.ClosestPoint(result.Item1); }while (oldresult.Item2.Distance(result.Item2) > tolerance * tolerance && oldresult.Item1.Distance(result.Item1) > tolerance * tolerance); } else { Line intersect = new Line { Start = curve1.Centre(), End = curve2.Centre }; Point tmp1 = intersect.CurveProximity(curve1).Item1; Point tmp2 = intersect.CurveProximity(curve2).Item1; if (tmp == null) { tmp = tmp1; } if (tmp1.Distance(curve2) < tmp.Distance(curve1) || tmp1.Distance(curve2) < tmp.Distance(curve2)) { tmp = tmp1; } if (tmp2.Distance(curve1) < tmp.Distance(curve1) || tmp2.Distance(curve1) < tmp.Distance(curve2)) { tmp = tmp2; } if (tmp.IsOnCurve(curve1)) { result.Item1 = tmp; result.Item2 = curve2.ClosestPoint(tmp); } else { result.Item2 = tmp; result.Item1 = curve1.ClosestPoint(tmp); } do { oldresult.Item1 = result.Item1; oldresult.Item2 = result.Item2; result.Item1 = curve2.ClosestPoint(result.Item2); result.Item2 = curve1.ClosestPoint(result.Item1); }while (oldresult.Item2.Distance(result.Item2) > tolerance * tolerance && oldresult.Item1.Distance(result.Item1) > tolerance * tolerance); } if (curve1.EndPoint().Distance(curve2.ClosestPoint(curve1.EndPoint())) < result.Item1.Distance(result.Item2)) { result.Item1 = curve1.EndPoint(); result.Item2 = curve2.ClosestPoint(result.Item1); } if (curve1.StartPoint().Distance(curve2.ClosestPoint(curve1.StartPoint())) < result.Item1.Distance(result.Item2)) { result.Item1 = curve1.StartPoint(); result.Item2 = curve2.ClosestPoint(result.Item1); } tmp = curve1.PointAtParameter((curve1.ParameterAtPoint(result.Item1) + 0.6) % 1); result2.Item1 = tmp; result2.Item2 = curve2.ClosestPoint(tmp); do { oldresult2.Item1 = result2.Item1; oldresult2.Item2 = result2.Item2; result2.Item1 = curve2.ClosestPoint(result2.Item2); result2.Item2 = curve1.ClosestPoint(result2.Item1); }while (oldresult2.Item2.Distance(result2.Item2) > tolerance * tolerance && oldresult2.Item1.Distance(result2.Item1) > tolerance * tolerance); if (result.Item1.Distance(result.Item2) > result2.Item1.Distance(result2.Item2)) { result = result2; } return(result); }
/***************************************************/ public static Output <Point, Point> CurveProximity(this Arc curve1, Arc curve2, double tolerance = Tolerance.Distance) { List <Point> cIntersections = curve1.CurveIntersections(curve2); if (cIntersections.Count > 0) { return new Output <Point, Point> { Item1 = cIntersections[0], Item2 = cIntersections[0] } } ; Output <Point, Point> result = new Output <Point, Point>(); Output <Point, Point> oldresult = new Output <Point, Point>(); Output <Point, Point> result2 = new Output <Point, Point>(); Output <Point, Point> result3 = new Output <Point, Point>(); Output <Point, Point> result4 = new Output <Point, Point>(); Output <Point, Point> result5 = new Output <Point, Point>(); Output <Point, Point> result6 = new Output <Point, Point>(); Plane ftPln1 = curve1.FitPlane(); Plane ftPln2 = curve2.FitPlane(); List <Point> fitPoints = new List <Point>(); bool check = false; if ((fitPoints = curve1.PlaneIntersections(ftPln2)).Count > 0) { if (fitPoints.Count == 1) { result.Item1 = fitPoints[0]; result.Item2 = curve2.ClosestPoint(fitPoints[0]); check = true; } else if (fitPoints.Count > 1) { if (fitPoints[0].Distance(curve2) < fitPoints[1].Distance(curve2)) { result.Item1 = fitPoints[0]; result.Item2 = curve2.ClosestPoint(fitPoints[0]); check = true; } else { result.Item1 = fitPoints[1]; result.Item2 = curve2.ClosestPoint(fitPoints[1]); check = true; } } } if ((fitPoints = curve2.PlaneIntersections(ftPln1)).Count > 0) { if (check) { if (fitPoints.Count == 1 && (fitPoints[0].Distance(curve1) < result.Item1.Distance(curve2))) { result.Item2 = fitPoints[0]; result.Item1 = curve1.ClosestPoint(fitPoints[0]); } else if (fitPoints.Count > 1) { if (fitPoints[0].Distance(curve1) < fitPoints[1].Distance(curve1)) { if (fitPoints[0].Distance(curve1) < result.Item1.Distance(curve2)) { result.Item2 = fitPoints[0]; result.Item1 = curve1.ClosestPoint(fitPoints[0]); } } else { if (fitPoints[1].Distance(curve1) < result.Item1.Distance(curve2)) { result.Item2 = fitPoints[1]; result.Item1 = curve1.ClosestPoint(fitPoints[1]); } } } } else if (fitPoints.Count == 1) { result.Item2 = fitPoints[0]; result.Item1 = curve1.ClosestPoint(fitPoints[0]); check = true; } else if (fitPoints.Count > 1) { if (fitPoints[0].Distance(curve1) < fitPoints[1].Distance(curve1)) { result.Item2 = fitPoints[0]; result.Item1 = curve1.ClosestPoint(fitPoints[0]); check = true; } else { result.Item2 = fitPoints[1]; result.Item1 = curve1.ClosestPoint(fitPoints[1]); check = true; } } } if (check) { do { oldresult.Item1 = result.Item1; oldresult.Item2 = result.Item2; result.Item1 = curve2.ClosestPoint(result.Item2); result.Item2 = curve1.ClosestPoint(result.Item1); }while (oldresult.Item2.Distance(result.Item2) > tolerance * tolerance && oldresult.Item1.Distance(result.Item1) > tolerance * tolerance); } check = false; Line intersect = new Line { Start = curve1.Centre(), End = curve2.Centre() }; Point tmp1 = intersect.CurveProximity(curve1).Item2; Point tmp2 = intersect.CurveProximity(curve2).Item2; if (tmp1.Distance(curve2) < tmp2.Distance(curve1)) { result2.Item1 = tmp1; result2.Item2 = curve2.ClosestPoint(tmp1); } else { result2.Item2 = tmp2; result2.Item1 = curve1.ClosestPoint(tmp2); } do { oldresult.Item1 = result2.Item1; oldresult.Item2 = result2.Item2; result2.Item1 = curve2.ClosestPoint(result2.Item2); result2.Item2 = curve1.ClosestPoint(result2.Item1); }while (oldresult.Item2.Distance(result2.Item2) > tolerance * tolerance && oldresult.Item1.Distance(result2.Item1) > tolerance * tolerance); if (curve1.EndPoint().Distance(curve2.ClosestPoint(curve1.EndPoint())) < curve1.StartPoint().Distance(curve2.ClosestPoint(curve1.StartPoint()))) { result3.Item1 = curve1.EndPoint(); result3.Item2 = curve2.ClosestPoint(result3.Item1); } else { result3.Item1 = curve1.StartPoint(); result3.Item2 = curve2.ClosestPoint(result3.Item1); } if (curve2.EndPoint().Distance(curve1.ClosestPoint(curve2.EndPoint())) < curve2.StartPoint().Distance(curve1.ClosestPoint(curve2.StartPoint()))) { result4.Item2 = curve2.EndPoint(); result4.Item1 = curve1.ClosestPoint(result4.Item2); } else { result4.Item2 = curve2.StartPoint(); result4.Item1 = curve1.ClosestPoint(result4.Item2); } do { oldresult.Item1 = result3.Item1; oldresult.Item2 = result3.Item2; result3.Item1 = curve2.ClosestPoint(result3.Item2); result3.Item2 = curve1.ClosestPoint(result3.Item1); }while (oldresult.Item2.Distance(result3.Item2) > tolerance * tolerance && oldresult.Item1.Distance(result3.Item1) > tolerance * tolerance); do { oldresult.Item1 = result4.Item1; oldresult.Item2 = result4.Item2; result4.Item1 = curve2.ClosestPoint(result4.Item2); result4.Item2 = curve1.ClosestPoint(result4.Item1); }while (oldresult.Item2.Distance(result4.Item2) > tolerance * tolerance && oldresult.Item1.Distance(result4.Item1) > tolerance * tolerance); result5.Item2 = curve2.PointAtParameter(0.5); result5.Item1 = curve1.ClosestPoint(result5.Item2); result6.Item1 = curve1.PointAtParameter(0.5); result6.Item2 = curve2.ClosestPoint(result6.Item1); do { oldresult.Item1 = result5.Item1; oldresult.Item2 = result5.Item2; result5.Item1 = curve2.ClosestPoint(result5.Item2); result5.Item2 = curve1.ClosestPoint(result5.Item1); }while (oldresult.Item2.Distance(result5.Item2) > tolerance * tolerance && oldresult.Item1.Distance(result5.Item1) > tolerance * tolerance); do { oldresult.Item1 = result6.Item1; oldresult.Item2 = result6.Item2; result6.Item1 = curve2.ClosestPoint(result6.Item2); result6.Item2 = curve1.ClosestPoint(result6.Item1); }while (oldresult.Item2.Distance(result6.Item2) > tolerance * tolerance && oldresult.Item1.Distance(result6.Item1) > tolerance * tolerance); if (result.Item1 == null || result.Item2 == null) { result = result2; } if (result2.Item2.Distance(result2.Item1) < result.Item1.Distance(result.Item2)) { result = result2; } if (result3.Item2.Distance(result3.Item1) < result.Item1.Distance(result.Item2)) { result = result3; } if (result4.Item2.Distance(result4.Item1) < result.Item1.Distance(result.Item2)) { result = result4; } if (result5.Item2.Distance(result5.Item1) < result.Item1.Distance(result.Item2)) { result = result5; } if (result6.Item2.Distance(result6.Item1) < result.Item1.Distance(result.Item2)) { result = result6; } return(result); }
/***************************************************/ public static Output <Point, Point> CurveProximity(this Line curve1, Arc curve2, double tolerance = Tolerance.Distance) { List <Point> cIntersections = curve1.CurveIntersections(curve2); if (cIntersections.Count > 0) { return new Output <Point, Point> { Item1 = cIntersections[0], Item2 = cIntersections[0] } } ; List <Point> plnPts = new List <Point>(); plnPts.Add(curve1.Start); plnPts.Add(curve1.End); plnPts.Add(curve2.Centre()); Point tmp; Plane ftPln = plnPts.FitPlane(); if (ftPln != null) { List <Point> intersecting = curve2.PlaneIntersections(ftPln); if (intersecting.Count > 1) { if (intersecting[0].Distance(curve1) < intersecting[1].Distance(curve1)) { tmp = intersecting[0]; } else { tmp = intersecting[1]; } } else if (intersecting.Count == 1) { tmp = intersecting[0]; } else { tmp = curve2.StartPoint(); } } else { tmp = curve2.StartPoint(); } if (curve2.StartPoint().Distance(curve1) < tmp.Distance(curve1)) { tmp = curve2.StartPoint(); } if (curve2.EndPoint().Distance(curve1) < tmp.Distance(curve1)) { tmp = curve2.EndPoint(); } Line prLn = curve1.Project(curve2.FitPlane()); List <Point> lnInt = prLn.CurveIntersections(curve2); if (lnInt.Count > 0) { if (lnInt.Count > 1) { if (lnInt[0].Distance(curve1) > lnInt[0].Distance(curve1)) { lnInt[0] = lnInt[1]; } } if (lnInt[0].Distance(curve1) < tmp.Distance(curve1)) { tmp = lnInt[0]; } } Output <Point, Point> result = new Output <Point, Point>(); result.Item1 = curve1.ClosestPoint(tmp); result.Item2 = curve2.ClosestPoint(result.Item1); result.Item1 = curve1.ClosestPoint(result.Item2); Output <Point, Point> oldfinal = new Output <Point, Point>(); Output <Point, Point> result2 = new Output <Point, Point>(); if (curve1.Start.Distance(curve2) < curve1.End.Distance(curve2)) { result2.Item1 = curve1.Start; } else { result2.Item1 = curve1.End; } result2.Item2 = curve2.ClosestPoint(result2.Item1); result2.Item1 = curve1.ClosestPoint(result2.Item2); Output <Point, Point> final = new Output <Point, Point>(); if (result.Item1.Distance(result.Item2) < result2.Item1.Distance(result2.Item2)) { final = result; } else { final = result2; } do { oldfinal.Item1 = final.Item1; oldfinal.Item2 = final.Item2; final.Item2 = curve2.ClosestPoint(final.Item1); final.Item1 = curve1.ClosestPoint(final.Item2); }while (Math.Abs(oldfinal.Item1.Distance(oldfinal.Item2) - final.Item1.Distance(final.Item2)) > tolerance * tolerance); return(final); }