public static (double X, double Y) EllipticalArc1( double t, double cX, double cY, double r1, double r2, double angle, double startAngle, double sweepAngle) { return(InterpolateRotatedEllipseTests.Ellipse(EllipticalPolarAngleTests.EllipticalPolarAngle(startAngle + (sweepAngle * t), r1, r2), cX, cY, r1, r2, angle)); }
public static Inclusions EllipticalArcContainsPoint2( double cX, double cY, double r1, double r2, double cosT, double sinT, double startCosT, double startSinT, double sweepCosT, double sweepSinT, double pX, double pY, double epsilon = Epsilon) { // If the ellipse is empty it can't contain anything. if (r1 <= 0d || r2 <= 0d) { return(Inclusions.Outside); } // If the Sweep angle is Tau, the EllipticalArc must be an Ellipse. if (Abs(sweepCosT - 1d) < epsilon && Abs(sweepSinT) < epsilon) { return(EllipseWithVectorAngleContainsPointTests.EllipseContainsPoint(cX, cY, r1, r2, sinT, cosT, pX, pY)); } var endSinT = (sweepSinT * startCosT) + (sweepCosT * startSinT); var endCosT = (sweepCosT * startCosT) - (sweepSinT * startSinT); // ToDo: Simplify out Atan2 var startAngle = Atan2(startSinT, startCosT); var endAngle = Atan2(endSinT, endCosT); // Find the start and end angles. var sa = EllipticalPolarAngleTests.EllipticalPolarAngle(startAngle, r1, r2); var ea = EllipticalPolarAngleTests.EllipticalPolarAngle(endAngle, r1, r2); // Ellipse equation for an ellipse at origin for the chord end points. var u1 = r1 * Cos(sa); var v1 = -(r2 * Sin(sa)); var u2 = r1 * Cos(ea); var v2 = -(r2 * 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)); // Find the determinant of the chord. var determinant = ((sX - pX) * (eY - pY)) - ((eX - pX) * (sY - pY)); // Check whether the point is on the same side of the chord as the center. if (Sign(-determinant) == Sign(sweepSinT * sweepCosT)) { return(Inclusions.Outside); } // Translate point to origin. var u0 = pX - cX; var v0 = pY - cY; // Apply the rotation transformation to the point at the origin. var a = (u0 * cosT) + (v0 * sinT); var b = (u0 * sinT) - (v0 * cosT); // Normalize the radius. var normalizedRadius = (a * a / (r1 * r1)) + (b * b / (r2 * r2)); return((normalizedRadius <= 1d) ? ((Abs(normalizedRadius - 1d) < epsilon) ? Inclusions.Boundary : Inclusions.Inside) : Inclusions.Outside); }
public static Inclusions EllipticalArcSectorContainsPoint0( double cX, double cY, double r1, double r2, double cosT, double sinT, double startAngle, double sweepAngle, double pX, double pY, double epsilon = Epsilon) { // If the ellipse is empty it can't contain anything. if (r1 <= 0d || r2 <= 0d) { return(Inclusions.Outside); } var endAngle = startAngle + sweepAngle; // Find the start and end angles. var sa = EllipticalPolarAngleTests.EllipticalPolarAngle(startAngle, r1, r2); var ea = EllipticalPolarAngleTests.EllipticalPolarAngle(endAngle, r1, r2); // Ellipse equation for an ellipse at origin for the chord end points. var u1 = r1 * Cos(sa); var v1 = -(r2 * Sin(sa)); var u2 = r1 * Cos(ea); var v2 = -(r2 * 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)); // Find the determinant of the chord. var determinant = ((sX - pX) * (eY - pY)) - ((eX - pX) * (sY - pY)); // Check if the point is on the chord. if (Abs(determinant) <= epsilon) { return((sX < eX) ? (sX <= pX && pX <= eX) ? Inclusions.Boundary : Inclusions.Outside : (eX <= pX && pX <= sX) ? Inclusions.Boundary : Inclusions.Outside); } // Check whether the point is on the side of the chord as the center. if (Sign(determinant) == Sign(sweepAngle)) { return(Inclusions.Outside); } // Translate points to origin. var u0 = pX - cX; var v0 = pY - cY; // Apply the rotation transformation. var a = (u0 * cosT) + (v0 * sinT); var b = (u0 * sinT) - (v0 * cosT); // Normalize the radius. var normalizedRadius = (a * a / (r1 * r1)) + (b * b / (r2 * r2)); return((normalizedRadius <= 1d) ? ((Abs(normalizedRadius - 1d) < epsilon) ? Inclusions.Boundary : Inclusions.Inside) : Inclusions.Outside); }
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 Rectangle2D EllipticalArc0( double cX, double cY, double r1, double r2, double angle, double startAngle, double sweepAngle) { // Get the ellipse rotation transform. var cosT = Cos(angle); var sinT = Sin(angle); var i = (r1 - r2) * (r1 + r2) * sinT * cosT; // Find the angles of the Cartesian extremes. var angles = new double[4] { Atan2(i, (r2 * r2 * sinT * sinT) + (r1 * r1 * cosT * cosT)), Atan2((r1 * r1 * sinT * sinT) + (r2 * r2 * cosT * cosT), i), Atan2(i, (r2 * r2 * sinT * sinT) + (r1 * r1 * cosT * cosT)) + PI, Atan2((r1 * r1 * sinT * sinT) + (r2 * r2 * cosT * cosT), i) + PI }; // Sort the angles so that like sides are consistently at the same index. Array.Sort(angles); // Get the start and end angles adjusted to polar coordinates. var t0 = EllipticalPolarAngleTests.EllipticalPolarAngle(startAngle, r1, r2); var t1 = EllipticalPolarAngleTests.EllipticalPolarAngle(startAngle + sweepAngle, r1, r2); // Interpolate the ratios of height and width of the chord. var sinT0 = Sin(t0); var cosT0 = Cos(t0); var sinT1 = Sin(t1); var cosT1 = Cos(t1); // Get the end points of the chord. var bounds = new Rectangle2D( // Apply the rotation transformation and translate to new center. new Point2D( cX + ((r1 * cosT0 * cosT) - (r2 * sinT0 * sinT)), cY + ((r1 * cosT0 * sinT) + (r2 * sinT0 * cosT))), // Apply the rotation transformation and translate to new center. new Point2D( cX + ((r1 * cosT1 * cosT) - (r2 * sinT1 * sinT)), cY + ((r1 * cosT1 * sinT) + (r2 * sinT1 * cosT)))); // Find the parent ellipse's horizontal and vertical radii extremes. var halfWidth = Sqrt((r1 * r1 * cosT * cosT) + (r2 * r2 * sinT * sinT)); var halfHeight = Sqrt((r1 * r1 * sinT * sinT) + (r2 * r2 * cosT * cosT)); // Expand the elliptical boundaries if any of the extreme angles fall within the sweep angle. if (AngleWithinAngleTests.Within(angles[0], angle + startAngle, sweepAngle)) { bounds.Right = cX + halfWidth; } if (AngleWithinAngleTests.Within(angles[1], angle + startAngle, sweepAngle)) { bounds.Bottom = cY + halfHeight; } if (AngleWithinAngleTests.Within(angles[2], angle + startAngle, sweepAngle)) { bounds.Left = cX - halfWidth; } if (AngleWithinAngleTests.Within(angles[3], angle + startAngle, sweepAngle)) { bounds.Top = cY - halfHeight; } // Return the points of the Cartesian extremes of the rotated elliptical arc. return(bounds); }