public static Intersection EllipseEllipseIntersection(
            double h1, double k1, double a1, double b1, double cos1, double sin1,
            double h2, double k2, double a2, double b2, double cos2, double sin2,
            double epsilon = double.Epsilon)
        {
            if (sin2 == 1d || sin2 == -1d)
            {
                cos2 = 0d;
            }

            // Polynomials representing the Ellipses.
            var a = RotatedEllipseConicSectionPolynomialTests.EllipseConicPolynomial(h1, k1, a1, b1, cos1, sin1);
            var b = RotatedEllipseConicSectionPolynomialTests.EllipseConicPolynomial(h2, k2, a2, b2, cos2, sin2);

            var yRoots = new Polynomial(ConicSectionBezoutTests.ConicSectionBezout(a, b)).Trim().Roots();

            var norm0 = ((a.a * a.a) + (2d * a.b * a.b) + (a.c * a.c)) * epsilon;
            //var norm1 = ((b.a * b.a) + (2d * b.b * b.b) + (b.c * b.c)) * epsilon;

            var result = new Intersection(IntersectionStates.NoIntersection);

            for (var y = 0; y < yRoots.Length; y++)
            {
                var xRoots = new Polynomial(
                    a.a,
                    a.d + (yRoots[y] * a.b),
                    a.f + (yRoots[y] * (a.e + (yRoots[y] * a.c))),
                    epsilon).Trim().Roots();
                for (var x = 0; x < xRoots.Length; x++)
                {
                    var test = (((a.a * xRoots[x]) + (a.b * yRoots[y]) + a.d) * xRoots[x]) + (((a.c * yRoots[y]) + a.e) * yRoots[y]) + a.f;
                    if (Abs(test) < norm0)
                    {
                        test = (((b.a * xRoots[x]) + (b.b * yRoots[y]) + b.d) * xRoots[x]) + (((b.c * yRoots[y]) + b.e) * yRoots[y]) + b.f;
                        if (Abs(test) < 1d)//norm1) // Using norm1 breaks when an ellipse intersects certain other ellipses.
                        {
                            result.AppendPoint(new Point2D(xRoots[x], yRoots[y]));
                        }
                    }
                }
            }

            if (result.Items.Count > 0)
            {
                result.State = IntersectionStates.Intersection;
            }

            return(result);
        }
Ejemplo n.º 2
0
        public static Intersection ObliqueEllipseObliqueEllipseIntersection(
            double h1, double k1, double a1, double b1, double cos1, double sin1,
            double h2, double k2, double a2, double b2, double cos2, double sin2,
            double epsilon = double.Epsilon)
        {
            // If the ellipses aren't rotated, use the slightly faster Orthogonal method.
            if (cos1 == Cos0 && cos2 == Cos0 && sin1 == Sin0 && sin2 == Sin0)
            {
                return(OrthogonalEllipseOrthogonalEllipseIntersectionTests.OrthogonalEllipseOrthogonalEllipseIntersection(h1, k1, a1, b1, h2, k2, a2, b2, epsilon));
            }

            // If the angles are reflections of each other with slight loss of precision in sin cos, and they are the same height and size, the angle needs to be corrected.
            if (Abs(cos1 - cos2) < epsilon && Abs(sin1 + sin2) < epsilon && k1 == k2 && a1 == a2 && b1 == b2)
            {
                // Fix for Case 0.
                cos1 = cos2;
                sin1 = -sin2;
                // ToDo: Verify this fix with more tests.
                // What happens when the ellipses are swapped?
            }

            // If the ellipses are rotated at 90 degrees to each other, and their sizes are opposites, everything gets messed up. So, let's use Orthogonal intersection code.
            if (CrossProduct2Vector2DTests.CrossProduct2Vector2D(cos1, sin1, cos2, sin2) == 1d && a1 == b2 && a2 == b1)
            {
                // Rotate the center point of the second ellipse in the reverse angle about the center of the first ellipse to align with it.
                (h2, k2) = RotatePointAboutPointTests.RotatePoint(h2, k2, cos1, -sin1, h1, k1);

                // Rotate second ellipse Orthogonally.
                SwapTests.Swap(ref a2, ref b2);

                // Find the points of intersection.
                var intersection = OrthogonalEllipseOrthogonalEllipseIntersectionTests.OrthogonalEllipseOrthogonalEllipseIntersection(h1, k1, a1, b1, h2, k2, a2, b2, epsilon);

                // Rotate the points back forwards to the locations of the intersection.
                for (var i = 0; i < intersection.Items.Count; i++)
                {
                    // Rotate point.
                    intersection.Items[i] = RotatePointAboutPointTests.RotatePoint(intersection.Items[i].X, intersection.Items[i].Y, cos1, sin1, h1, k1);
                }

                // Return result.
                return(intersection);
            }

            // Polynomials representing the Ellipses.
            var e1 = EllipseConicSectionPolynomialTests.EllipseConicSectionPolynomial(h1, k1, a1, b1, cos1, sin1);
            var e2 = EllipseConicSectionPolynomialTests.EllipseConicSectionPolynomial(h2, k2, a2, b2, cos2, sin2);

            var yRoots = new Polynomial(ConicSectionBezoutTests.ConicSectionBezout(e1, e2)).Trim().Roots();

            // Double epsilon is too small for here.
            epsilon = 1e-6; //1e-3;
            var norm0 = ((e1.a * e1.a) + (2d * e1.b * e1.b) + (e1.c * e1.c)) * epsilon;
            var norm1 = ((e2.a * e2.a) + (2d * e2.b * e2.b) + (e2.c * e2.c)) * epsilon;

            var result = new Intersection(IntersectionStates.NoIntersection);

            foreach (var s in yRoots)
            {
                var xRoots = new Polynomial((
                                                a: e1.a,
                                                b: e1.d + (s * e1.b),
                                                c: e1.f + (s * (e1.e + (s * e1.c)))
                                                )).Trim().Roots();
                foreach (var t in xRoots)
                {
                    var test = (((e1.a * t) + (e1.b * s) + e1.d) * t) + (((e1.c * s) + e1.e) * s) + e1.f;
                    if (Abs(test) < norm0)
                    {
                        test = (((e2.a * t) + (e2.b * s) + e2.d) * t) + (((e2.c * s) + e2.e) * s) + e2.f;
                        if (Abs(test) < norm1)
                        {
                            result.AppendPoint(new Point2D(t, s));
                        }
                    }
                }
            }

            if (result.Items.Count > 0)
            {
                result.State = IntersectionStates.Intersection;
            }

            return(result);
        }