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));
 }
Пример #2
0
        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);
        }
Пример #3
0
        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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        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);
        }