public static Intersection QuadraticBezierLineSegmentIntersection0( double p1X, double p1Y, double p2X, double p2Y, double p3X, double p3Y, double a1X, double a1Y, double a2X, double a2Y, double epsilon = Epsilon) { var min = MinPointTests.MinPoint(a1X, a1Y, a2X, a2Y); var max = MaxPointTests.MaxPoint(a1X, a1Y, a2X, a2Y); var result = new Intersection(IntersectionStates.NoIntersection); var a = new Vector2D(p2X, p2Y) * (-2); var c2 = new Vector2D(p1X, p1Y) + (a + new Vector2D(p3X, p3Y)); a = new Vector2D(p1X, p1Y) * (-2); var b = new Vector2D(p2X, p2Y) * 2; var c1 = a + b; var c0 = new Point2D(p1X, p1Y); var n = new Point2D(a1Y - a2Y, a2X - a1X); var cl = (a1X * a2Y) - (a2X * a1Y); var roots = QuadraticRootsTests.QuadraticRoots( DotProduct2Vector2DTests.DotProduct2D(n.X, n.Y, c2.I, c2.J), DotProduct2Vector2DTests.DotProduct2D(n.X, n.Y, c1.I, c1.J), DotProduct2Vector2DTests.DotProduct2D(n.X, n.Y, c0.X + cl, c0.Y + cl), epsilon); for (var i = 0; i < roots.Count; i++) { var t = roots[i]; if (0 <= t && t <= 1) { var p4 = InterpolateLinear2DTests.LinearInterpolate2D(t, p1X, p1Y, p2X, p2Y); var p5 = InterpolateLinear2DTests.LinearInterpolate2D(t, p2X, p2Y, p3X, p3Y); var p6 = InterpolateLinear2DTests.LinearInterpolate2D(t, p4.X, p4.Y, p5.X, p5.Y); if (a1X == a2X) { if (min.Y <= p6.Y && p6.Y <= max.Y) { result.State = IntersectionStates.Intersection; result.AppendPoint(p6); } } else if (a1Y == a2Y) { if (min.X <= p6.X && p6.X <= max.X) { result.State = IntersectionStates.Intersection; result.AppendPoint(p6); } } else if (GreaterThanOrEqualTests.GreaterThanOrEqual(p6.X, p6.Y, min.X, min.Y) && LessThanOrEqualTests.LessThanOrEqual(p6.X, p6.Y, max.X, max.Y)) { result.State = IntersectionStates.Intersection; result.AppendPoint(p6); } } } return(result); }
/// <summary> /// Calculate the geometry of points offset at a specified distance. aka Double Line. /// </summary> /// <param name="pointA">First reference point.</param> /// <param name="pointB">First inclusive point.</param> /// <param name="pointC">Second inclusive point.</param> /// <param name="pointD">Second reference point.</param> /// <param name="offsetDistance">Offset Distance</param> /// <returns></returns> /// <acknowledgment> /// Suppose you have 4 points; A, B C, and D. With Lines AB, BC, and CD.<BR/> ///<BR/> /// B1 BC1 C1<BR/> /// |\¯B¯¯¯¯¯BC¯¯¯C¯¯¯/|<BR/> /// | \--------------/ |<BR/> /// | |\____________/| |<BR/> /// | | |B2 BC2 C2| | |<BR/> /// AB| | | | | |CD<BR/> /// AB1| | |AB2 CD2| | |CD1<BR/> /// | | | | | |<BR/> /// | | | | | |<BR/> /// A1 A A2 D2 D D1<BR/> /// /// </acknowledgment> public static Point2D[] CenteredOffsetLinePoints(Point2D pointA, Point2D pointB, Point2D pointC, Point2D pointD, double offsetDistance) { // To get the vectors of the angles at each corner B and C, Normalize the Unit Delta Vectors along AB, BC, and CD. var UnitVectorAB = pointB - pointA; UnitVectorAB = new Vector2D(Normalize2DVectorTests.Normalize(UnitVectorAB.I, UnitVectorAB.J)); var UnitVectorBC = pointC - pointB; UnitVectorBC = new Vector2D(Normalize2DVectorTests.Normalize(UnitVectorBC.I, UnitVectorBC.J)); var UnitVectorCD = pointD - pointC; UnitVectorCD = new Vector2D(Normalize2DVectorTests.Normalize(UnitVectorCD.I, UnitVectorCD.J)); // Find the Perpendicular of the outside vectors var PerpendicularAB = new Vector2D(PerpendicularClockwiseVectorTests.PerpendicularClockwise(UnitVectorAB.I, UnitVectorAB.J)); var PerpendicularCD = new Vector2D(PerpendicularClockwiseVectorTests.PerpendicularClockwise(UnitVectorCD.I, UnitVectorCD.J)); // Normalized Vectors pointing out from B and C. var OutUnitVectorB = UnitVectorAB - UnitVectorBC; OutUnitVectorB = new Vector2D(Normalize2DVectorTests.Normalize(OutUnitVectorB.I, OutUnitVectorB.J)); var OutUnitVectorC = UnitVectorCD - UnitVectorBC; OutUnitVectorC = new Vector2D(Normalize2DVectorTests.Normalize(OutUnitVectorC.I, OutUnitVectorC.J)); // The distance out from B is the radius / Cos(theta) where theta is the angle // from the perpendicular of BC of the UnitVector. The cosine can also be // calculated by doing the dot product of Unit(Perpendicular(AB)) and // UnitVector. var BPointScale = DotProduct2Vector2DTests.DotProduct2D(PerpendicularAB.I, PerpendicularAB.J, OutUnitVectorB.I, OutUnitVectorB.J) * offsetDistance; var CPointScale = DotProduct2Vector2DTests.DotProduct2D(PerpendicularCD.I, PerpendicularCD.J, OutUnitVectorC.I, OutUnitVectorC.J) * offsetDistance; OutUnitVectorB *= CPointScale; OutUnitVectorC *= BPointScale; // Corners of the parallelogram to draw var Out = new Point2D[] { pointC + OutUnitVectorC, pointB + OutUnitVectorB, pointB - OutUnitVectorB, pointC - OutUnitVectorC, pointC + OutUnitVectorC }; return(Out); }
public static Intersection UnrotatedEllipseLineSegmentIntersection0( double centerX, double centerY, double rx, double ry, double a1X, double a1Y, double a2X, double a2Y, double epsilon = Epsilon) { _ = epsilon; var origin = new Vector2D(a1X, a1Y); var dir = new Vector2D(a1X, a1Y, a2X, a2Y); var diff = origin - new Vector2D(centerX, centerY); var mDir = new Vector2D(dir.I / (rx * rx), dir.J / (ry * ry)); var mDiff = new Vector2D(diff.I / (rx * rx), diff.J / (ry * ry)); var a = DotProduct2Vector2DTests.DotProduct2D(dir.I, dir.J, mDir.I, mDir.J); var b = DotProduct2Vector2DTests.DotProduct2D(dir.I, dir.J, mDiff.I, mDiff.J); var c = DotProduct2Vector2DTests.DotProduct2D(diff.I, diff.J, mDiff.I, mDiff.J) - 1d; var d = (b * b) - (a * c); Intersection result; if (d < 0) { result = new Intersection(IntersectionStates.Outside); } else if (d > 0) { var root = Sqrt(d); var t_a = (-b - root) / a; var t_b = (-b + root) / a; if ((t_a < 0 || 1 < t_a) && (t_b < 0 || 1 < t_b)) { result = (t_a < 0 && t_b < 0) || (t_a > 1 && t_b > 1) ? new Intersection(IntersectionStates.Outside) : new Intersection(IntersectionStates.Inside); } else { result = new Intersection(IntersectionStates.Intersection); if (0 <= t_a && t_a <= 1) { result.AppendPoint(InterpolateLinear2DTests.LinearInterpolate2D(t_a, a1X, a1Y, a2X, a2Y)); } if (0 <= t_b && t_b <= 1) { result.AppendPoint(InterpolateLinear2DTests.LinearInterpolate2D(t_b, a1X, a1Y, a2X, a2Y)); } } } else { var t = -b / a; if (0 <= t && t <= 1) { result = new Intersection(IntersectionStates.Intersection); result.AppendPoint(InterpolateLinear2DTests.LinearInterpolate2D(t, a1X, a1Y, a2X, a2Y)); } else { result = new Intersection(IntersectionStates.Outside); } } return(result); }
public static Intersection UnrotatedEllipticalArcLineSegmentIntersection0( double cx, double cy, double rx, double ry, double startAngle, double sweepAngle, double x0, double y0, double x1, double y1, double epsilon = Epsilon) { _ = epsilon; // Initialize the resulting intersection structure. var result = new Intersection(IntersectionStates.NoIntersection); // Translate the line to put the ellipse centered at the origin. var origin = new Vector2D(x0, y0); var dir = new Vector2D(x0, y0, x1, y1); var diff = origin - new Vector2D(cx, cy); var mDir = new Vector2D(dir.I / (rx * rx), dir.J / (ry * ry)); var mDiff = new Vector2D(diff.I / (rx * rx), diff.J / (ry * ry)); // Calculate the quadratic parameters. var a = DotProduct2Vector2DTests.DotProduct2D(dir.I, dir.J, mDir.I, mDir.J); var b = DotProduct2Vector2DTests.DotProduct2D(dir.I, dir.J, mDiff.I, mDiff.J); var c = DotProduct2Vector2DTests.DotProduct2D(diff.I, diff.J, mDiff.I, mDiff.J) - 1d; // Calculate the discriminant of the quadratic. The 4 is omitted. var discriminant = (b * b) - (a * c); // Check whether line segment is outside of the ellipse. if (discriminant < 0d) { return(new Intersection(IntersectionStates.Outside)); } // Find the start and end angles. var sa = EllipticalPolarAngleTests.EllipticalPolarAngle(startAngle, rx, ry); var ea = EllipticalPolarAngleTests.EllipticalPolarAngle(startAngle + sweepAngle, rx, ry); // Get the ellipse rotation transform. var cosT = Cos(0d); var sinT = Sin(0d); // Ellipse equation for an ellipse at origin for the chord end points. var u1 = rx * Cos(sa); var v1 = -(ry * Sin(sa)); var u2 = rx * Cos(ea); var v2 = -(ry * Sin(ea)); // Find the points of the chord. var sX = cx + ((u1 * cosT) + (v1 * sinT)); var sY = cy + ((u1 * sinT) - (v1 * cosT)); var eX = cx + ((u2 * cosT) + (v2 * sinT)); var eY = cy + ((u2 * sinT) - (v2 * cosT)); if (discriminant > 0d) { // Two real possible solutions. var root = Sqrt(discriminant); var t1 = (-b - root) / a; var t2 = (-b + root) / a; if ((t1 < 0d || 1d < t1) && (t2 < 0d || 1d < t2)) { result = (t1 < 0d && t2 < 0d) || (t1 > 1d && t2 > 1d) ? new Intersection(IntersectionStates.Outside) : new Intersection(IntersectionStates.Inside); } else { var p = InterpolateLinear2DTests.LinearInterpolate2D(t1, x0, y0, x1, y1); // Find the determinant of the chord. var determinant = ((sX - p.X) * (eY - p.Y)) - ((eX - p.X) * (sY - p.Y)); // Check whether the point is on the side of the chord as the center. if (0d <= t1 && t1 <= 1d && (Sign(determinant) != Sign(sweepAngle))) { result.AppendPoint(p); } p = InterpolateLinear2DTests.LinearInterpolate2D(t2, x0, y0, x1, y1); // Find the determinant of the chord. determinant = ((sX - p.X) * (eY - p.Y)) - ((eX - p.X) * (sY - p.Y)); if (0d <= t2 && t2 <= 1 && (Sign(determinant) != Sign(sweepAngle))) { result.AppendPoint(p); } } } else // discriminant == 0. { // One real possible solution. var t = -b / a; if (t >= 0d && t <= 1d) { var p = InterpolateLinear2DTests.LinearInterpolate2D(t, x0, y0, x1, y1); // Find the determinant of the matrix representing the chord. var determinant = ((sX - p.X) * (eY - p.Y)) - ((eX - p.X) * (sY - p.Y)); // Add the point if it is on the sweep side of the chord. if (Sign(determinant) != Sign(sweepAngle)) { result.AppendPoint(InterpolateLinear2DTests.LinearInterpolate2D(t, x0, y0, x1, y1)); } } else { result = new Intersection(IntersectionStates.Outside); } } if (result.Count > 0) { result.State |= IntersectionStates.Intersection; } return(result); }
public static Intersection CubicBezierLineIntersection0( double p1X, double p1Y, double p2X, double p2Y, double p3X, double p3Y, double p4X, double p4Y, double a1X, double a1Y, double a2X, double a2Y, double epsilon = Epsilon) { Vector2D a, b, c, d; Vector2D c3, c2, c1, c0; double cl; Vector2D n; var min = MinPointTests.MinPoint(a1X, a1Y, a2X, a2Y); var max = MaxPointTests.MaxPoint(a1X, a1Y, a2X, a2Y); var result = new Intersection(IntersectionStates.NoIntersection); a = new Vector2D(p1X, p1Y) * (-1); b = new Vector2D(p2X, p2Y) * 3; c = new Vector2D(p3X, p3Y) * (-3); d = a + (b + (c + new Vector2D(p4X, p4Y))); c3 = new Vector2D(d.I, d.J); a = new Vector2D(p1X, p1Y) * 3; b = new Vector2D(p2X, p2Y) * (-6); c = new Vector2D(p3X, p3Y) * 3; d = a + (b + c); c2 = new Vector2D(d.I, d.J); a = new Vector2D(p1X, p1Y) * (-3); b = new Vector2D(p2X, p2Y) * 3; c = a + b; c1 = new Vector2D(c.I, c.J); c0 = new Vector2D(p1X, p1Y); n = new Vector2D(a1Y - a2Y, a2X - a1X); cl = (a1X * a2Y) - (a2X * a1Y); var roots = CubicRootsTests.CubicRoots( DotProduct2Vector2DTests.DotProduct2D(n.I, n.J, c3.I, c3.J), DotProduct2Vector2DTests.DotProduct2D(n.I, n.J, c2.I, c2.J), DotProduct2Vector2DTests.DotProduct2D(n.I, n.J, c1.I, c1.J), DotProduct2Vector2DTests.DotProduct2D(n.I, n.J, c0.I + cl, c0.J + cl), epsilon); for (var i = 0; i < roots.Count; i++) { var t = roots[i]; if (0 <= t && t <= 1) { var p5 = InterpolateLinear2DTests.LinearInterpolate2D(t, p1X, p1Y, p2X, p2Y); var p6 = InterpolateLinear2DTests.LinearInterpolate2D(t, p2X, p2Y, p3X, p3Y); var p7 = InterpolateLinear2DTests.LinearInterpolate2D(t, p3X, p3Y, p4X, p4Y); var p8 = InterpolateLinear2DTests.LinearInterpolate2D(t, p5.X, p5.Y, p6.X, p6.Y); var p9 = InterpolateLinear2DTests.LinearInterpolate2D(t, p6.X, p6.Y, p7.X, p7.Y); var p10 = InterpolateLinear2DTests.LinearInterpolate2D(t, p8.X, p8.Y, p9.X, p9.Y); if (a1X == a2X) { result.State = IntersectionStates.Intersection; result.AppendPoint(p10); } else if (a1Y == a2Y) { result.State = IntersectionStates.Intersection; result.AppendPoint(p10); } else if (GreaterThanOrEqualTests.GreaterThanOrEqual(p10.X, p10.Y, min.X, min.Y) && LessThanOrEqualTests.LessThanOrEqual(p10.X, p10.Y, max.X, max.Y)) { result.State = IntersectionStates.Intersection; result.AppendPoint(p10); } } } return(result); }