/***************************************************/ public static bool IsContaining(this PolyCurve curve, List <Point> points, bool acceptOnEdge = true, double tolerance = Tolerance.Distance) { // Todo: // - to be replaced with a general method for a nurbs curve? // - this is very problematic for edge cases (cutting line going through a sharp corner, to be superseded? BoundingBox box = curve.Bounds(); if (points.Any(x => !box.IsContaining(x, true, tolerance))) { return(false); } if (!curve.IsClosed(tolerance)) { return(false); } if (curve.Curves.Count == 1 && curve.Curves[0] is Circle) { return(IsContaining(curve.Curves[0] as Circle, points, acceptOnEdge, tolerance)); } Plane p = curve.FitPlane(tolerance); double sqTol = tolerance * tolerance; if (p == null) { if (acceptOnEdge) { foreach (Point pt in points) { if (curve.ClosestPoint(pt).SquareDistance(pt) > sqTol) { return(false); } } return(true); } else { return(false); } } List <ICurve> subParts = curve.SubParts(); List <Vector> edgeDirections = subParts.Where(s => s is Line).Select(c => (c as Line).Direction()).ToList(); foreach (Point pt in points) { Point pPt = pt.Project(p); if (pPt.SquareDistance(pt) > sqTol) // not on the same plane { return(false); } Point end = p.Origin; // Avrage of control points Vector direction = (end - pPt).Normalise(); // Gets a line cutting through the curves and the point while (direction.SquareLength() <= 0.5 || edgeDirections.Any(e => 1 - Math.Abs(e.DotProduct(direction)) <= Tolerance.Angle)) // not zeroa or parallel to edges { end = end.Translate(Create.RandomVectorInPlane(p, true)); direction = (end - pPt).Normalise(); } Line ray = new Line { Start = pPt, End = end }; ray.Infinite = true; List <Point> intersects = new List <Point>(); List <Point> extraIntersects = new List <Point>(); foreach (ICurve subPart in subParts) { List <Point> iPts = subPart.ILineIntersections(ray, false, tolerance); // LineIntersection ignores the `false` foreach (Point iPt in iPts) { double signedAngle = direction.SignedAngle(subPart.ITangentAtPoint(iPt, tolerance), p.Normal); if ((subPart.IStartPoint().SquareDistance(iPt) <= sqTol)) // Keep intersections from beeing counted twice? { if (signedAngle >= -Tolerance.Angle) // tangent is to the left of the direction { intersects.Add(iPt); } else { extraIntersects.Add(iPt); } } else if ((subPart.IEndPoint().SquareDistance(iPt) <= sqTol)) { if (signedAngle <= Tolerance.Angle) // tangent is to the rigth of the direction { intersects.Add(iPt); } else { extraIntersects.Add(iPt); } } else if (Math.Abs(signedAngle) <= Tolerance.Angle) // They are parallel { extraIntersects.Add(iPt); } else { intersects.Add(iPt); } } } if (intersects.Count == 0) // did not intersect the curve (strange) { return(false); } if ((pPt.ClosestPoint(intersects.Union(extraIntersects)).SquareDistance(pPt) <= sqTol)) // if any intersection point is the point { if (acceptOnEdge) { continue; } else { return(false); } } intersects.Add(pPt); intersects = intersects.SortCollinear(tolerance); for (int j = 0; j < intersects.Count; j++) // Even indecies on a colinerar sort is outside the region { if (j % 2 == 0 && intersects[j] == pPt) { return(false); } } } return(true); }
/***************************************************/ public static bool IsContaining(this PolyCurve curve, List <Point> points, bool acceptOnEdge = true, double tolerance = Tolerance.Distance) { // Todo: // - to be replaced with a general method for a nurbs curve? // - this is very problematic for edge cases (cutting line going through a sharp corner, to be superseded? if (curve.IsClosed(tolerance)) { Plane p = curve.FitPlane(tolerance); double sqTol = tolerance * tolerance; if (p == null) { if (acceptOnEdge) { foreach (Point pt in points) { if (curve.ClosestPoint(pt).SquareDistance(pt) > sqTol) { return(false); } } return(true); } else { return(false); } } else { List <ICurve> subParts = curve.SubParts(); List <Vector> edgeDirections = subParts.Where(s => s is Line).Select(c => (c as Line).Direction()).ToList(); foreach (Point pt in points) { Point pPt = pt.Project(p); if (pPt.SquareDistance(pt) <= sqTol) { Point end = p.Origin; Vector direction = (end - pPt).Normalise(); while (direction.SquareLength() <= sqTol || edgeDirections.Any(e => 1 - Math.Abs(e.DotProduct(direction)) <= Tolerance.Angle)) { end = end.Translate(Create.RandomVectorInPlane(p, true)); direction = (end - pPt).Normalise(); } Line ray = new Line { Start = pPt, End = end }; ray.Infinite = true; List <Point> intersects = new List <Point>(); List <Point> extraIntersects = new List <Point>(); foreach (ICurve subPart in subParts) { List <Point> iPts = subPart.ILineIntersections(ray, false, tolerance); foreach (Point iPt in iPts) { double signedAngle = direction.SignedAngle(subPart.ITangentAtPoint(iPt, tolerance), p.Normal); if ((subPart.IStartPoint().SquareDistance(iPt) <= sqTol)) { if (signedAngle >= -Tolerance.Angle) { intersects.Add(iPt); } else { extraIntersects.Add(iPt); } } else if ((subPart.IEndPoint().SquareDistance(iPt) <= sqTol)) { if (signedAngle <= Tolerance.Angle) { intersects.Add(iPt); } else { extraIntersects.Add(iPt); } } else if (Math.Abs(signedAngle) <= Tolerance.Angle) { extraIntersects.Add(iPt); } else { intersects.Add(iPt); } } } if (intersects.Count == 0) { return(false); } if ((pPt.ClosestPoint(intersects.Union(extraIntersects)).SquareDistance(pPt) <= sqTol)) { if (acceptOnEdge) { continue; } else { return(false); } } intersects.Add(pPt); intersects = intersects.SortCollinear(tolerance); for (int j = 0; j < intersects.Count; j++) { if (j % 2 == 0 && intersects[j] == pPt) { return(false); } } } else { return(false); } } return(true); } } return(false); }
/***************************************************/ public static bool IsContaining(this Polyline curve, List <Point> points, bool acceptOnEdge = true, double tolerance = Tolerance.Distance) { // Todo: // check boundingBox/proximity at the beginning! // project to 2D & rewrite methods to 2D to improve performance // - to be replaced with a general method for a nurbs curve? // - could be done with a ray instead of an infinite line! if (curve.IsClosed(tolerance)) { Plane p = curve.FitPlane(tolerance); double sqTol = tolerance * tolerance; if (p == null) { if (acceptOnEdge) { foreach (Point pt in points) { if (curve.ClosestPoint(pt).SquareDistance(pt) > sqTol) { return(false); } } return(true); } else { return(false); } } else { List <Line> subParts = curve.SubParts(); List <Vector> edgeDirections = subParts.Select(c => c.Direction()).ToList(); foreach (Point pt in points) { Point pPt = pt.Project(p); if (pPt.SquareDistance(pt) <= sqTol) { Point end = p.Origin; Vector direction = (end - pPt).Normalise(); while (direction.SquareLength() <= 0.5 || edgeDirections.Any(e => 1 - Math.Abs(e.DotProduct(direction)) <= Tolerance.Angle)) { end = end.Translate(Create.RandomVectorInPlane(p, true)); direction = (end - pPt).Normalise(); } Line ray = new Line { Start = pPt, End = end }; ray.Infinite = true; List <Point> intersects = new List <Point>(); List <Point> extraIntersects = new List <Point>(); Func <double, double, double> ToFactor = (t, n) => (1 - t * t) / (1 - n * n); Line current = subParts[1]; double prevTolFactor = ToFactor(subParts[0].Direction().DotProduct(direction), current.Direction().DotProduct(direction)); for (int i = 1; i < subParts.Count + 1; i++) { Line next = subParts[(i + 1) % subParts.Count]; double nextTolFactor = ToFactor(next.Direction().DotProduct(direction), current.Direction().DotProduct(direction)); Point iPt = current.LineIntersection(ray, false, tolerance); if (iPt != null) { double signedAngle = direction.SignedAngle(current.Direction(), p.Normal); if ((current.Start.SquareDistance(iPt) <= sqTol * prevTolFactor)) // Will we get a point on the previous line { if (signedAngle > Tolerance.Angle) { intersects.Add(iPt); } else { extraIntersects.Add(iPt); } } else if ((current.End.SquareDistance(iPt) <= sqTol * nextTolFactor)) // Will we get a point on the next line { if (signedAngle < -Tolerance.Angle) { intersects.Add(iPt); } else { extraIntersects.Add(iPt); } } else { intersects.Add(iPt); } } prevTolFactor = 1 / nextTolFactor; current = next; } if (intersects.Count == 0) { return(false); } if ((pPt.ClosestPoint(intersects.Union(extraIntersects)).SquareDistance(pPt) <= sqTol)) { if (acceptOnEdge) { continue; } else { return(false); } } intersects.Add(pPt); intersects = intersects.SortCollinear(tolerance); for (int j = 0; j < intersects.Count; j++) { if (j % 2 == 0 && intersects[j] == pPt) { return(false); } } } else { return(false); } } return(true); } } return(false); }
/***************************************************/ public static bool IsContaining(this Polyline curve, List <Point> points, bool acceptOnEdge = true, double tolerance = Tolerance.Distance) { // Todo: // check boundingBox/proximity at the beginning! // project to 2D & rewrite methods to 2D to improve performance // - to be replaced with a general method for a nurbs curve? // - could be done with a ray instead of an infinite line! if (curve.IsClosed(tolerance)) { Plane p = curve.FitPlane(tolerance); double sqTol = tolerance * tolerance; if (p == null) { if (acceptOnEdge) { foreach (Point pt in points) { if (curve.ClosestPoint(pt).SquareDistance(pt) > sqTol) { return(false); } } return(true); } else { return(false); } } else { foreach (Point pt in points) { Point pPt = pt.Project(p); if (pPt.SquareDistance(pt) <= sqTol) { Point end = p.Origin; if (pPt.SquareDistance(end) <= sqTol) { end = end.Translate(Create.RandomVectorInPlane(p, true)); } Line ray = new Line { Start = pPt, End = end }; ray.Infinite = true; Vector rayDir = ray.Direction(); List <Line> subParts = curve.SubParts(); List <Point> intersects = new List <Point>(); List <Point> extraIntersects = new List <Point>(); foreach (Line subPart in subParts) { Point iPt = subPart.LineIntersection(ray, false, tolerance); if (iPt != null) { double signedAngle = rayDir.SignedAngle(subPart.Direction(), p.Normal); if ((subPart.Start.SquareDistance(iPt) <= sqTol)) { if (signedAngle > Tolerance.Angle) { intersects.Add(iPt); } else { extraIntersects.Add(iPt); } } else if ((subPart.End.SquareDistance(iPt) <= sqTol)) { if (signedAngle < -Tolerance.Angle) { intersects.Add(iPt); } else { extraIntersects.Add(iPt); } } else { intersects.Add(iPt); } } } if (intersects.Count == 0) { return(false); } if ((pPt.ClosestPoint(intersects.Union(extraIntersects)).SquareDistance(pPt) <= sqTol)) { if (acceptOnEdge) { continue; } else { return(false); } } intersects.Add(pPt); intersects = intersects.SortCollinear(tolerance); for (int j = 0; j < intersects.Count; j++) { if (j % 2 == 0 && intersects[j] == pPt) { return(false); } } } else { return(false); } } return(true); } } return(false); }