Пример #1
0
        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);
        }
Пример #2
0
        public static IList <double> CubicRootsStephenRSchmitt(double a, double b, double c, double d, double epsilon = Epsilon)
        {
            // If a is 0 the polynomial is quadratic.
            if (a is 0d)
            {
                return(QuadraticRootsTests.QuadraticRoots(b, c, d, epsilon));
            }

            var ba = b / a;
            var ca = c / a;
            var da = d / a;

            var q = ((3d * ca) - (ba * ba)) / 9d;
            var r = (-(2d * ba * ba * ba) + (9d * ba * ca) - (27d * da)) / 54d;

            var offset = ba * OneThird;

            // Polynomial discriminant
            var discriminant = (r * r) + (q * q * q);

            // ToDo: May need to switch from a hash set to a list for scan-beams.
            var results = new HashSet <double>();

            if (Abs(discriminant) <= epsilon)
            {
                discriminant = 0d;
            }

            if (discriminant == 0d)
            {
                var t = Sign(r) * Cbrt(Abs(r));

                // Real root.
                results.Add(-offset + (t + t));

                // Real part of complex root.
                results.Add(-offset - ((t + t) * OneHalf));
            }
            if (discriminant > 0)
            {
                var e = Sqrt(discriminant);
                var s = Sign(r + e) * Cbrt(Abs(r + e));
                var t = Sign(r - e) * Cbrt(Abs(r - e));

                // Real root.
                results.Add(-offset + (s + t));

                // Complex part of root pair.
                var Im = Abs(Sqrt3 * (s - t) * OneHalf);
                if (Im == 0d)
                {
                    // Real part of complex root.
                    results.Add(-offset - ((s + t) * OneHalf));
                }
            }
            else if (discriminant < 0)
            {
                // Distinct real roots.
                var th = Acos(r / Sqrt(-q * q * q));

                var sq = Sqrt(-q);
                results.Add((2d * sq * Cos(th * OneThird)) - offset);
                results.Add((2d * sq * Cos((th + Tau) * OneThird)) - offset);
                results.Add((2d * sq * Cos((th + (4d * PI)) * OneThird)) - offset);
            }

            return(results.ToList());
        }
Пример #3
0
        public static IList <double> CubicRootsSwitch(double a, double b, double c, double d, double epsilon = Epsilon)
        {
            if (a is 0d)
            {
                return(QuadraticRootsTests.QuadraticRoots(b, c, d, epsilon));
            }

            var ba = b / a;
            var ca = c / a;
            var da = d / a;

            var q = ((3d * ca) - (ba * ba)) * OneThird;                                     // / 9d;
            var r = ((2d * ba * ba * ba) - (9d * ba * ca) + (27d * da)) * OneTwentySeventh; // / 54d;

            var offset       = ba * OneThird;
            var discriminant = (r * r * OneQuarter) + (q * q * q * OneTwentySeventh);
            var halfB        = OneHalf * r;

            if (Abs(discriminant) <= epsilon)
            {
                discriminant = 0d;
            }

            switch (discriminant)
            {
            case 0:
            {
                var f = halfB >= 0d ? -Cbrt(halfB) : Cbrt(-halfB);
                return(new double[] {
                        (2d * f) - offset,
                        -f - offset
                    }.ToList());
            }

            case double v when v > 0d:
            {
                var e    = Sqrt(v);
                var tmp  = -halfB + e;
                var root = tmp >= 0 ? Cbrt(tmp) : -Cbrt(-tmp);
                tmp = -halfB - e;
                if (tmp >= 0)
                {
                    root += Cbrt(tmp);
                }
                else
                {
                    root -= Cbrt(-tmp);
                }

                return(new double[] { root - offset }.ToList());

                //var s = Sign(r + e) * Cbrt(Abs(r + e));
                //var t = Sign(r - e) * Cbrt(Abs(r - e));
                //var im = Abs(Sqrt(3d) * (s - t) * OneHalf);
                //return im == 0d ?
                //    new double[] {
                //    -offset + (s + t)
                //    }.ToList() :
                //    new double[] {
                //        -offset + (s + t),
                //        -offset - ((s + t) * OneHalf)
                //    }.ToList();
            }

            default:
            {
                var distance = Sqrt(-q * OneThird);
                var angle    = Atan2(Sqrt(-discriminant), -halfB) * OneThird;
                var cos      = Cos(angle);
                var sin      = Sin(angle);
                return(new double[] {
                        (2d * distance * cos) - offset,
                        (-distance * (cos + (Sqrt3 * sin))) - offset,
                        (-distance * (cos - (Sqrt3 * sin))) - offset
                    }.ToList());
            }
            }
        }
Пример #4
0
        public static IList <double> CubicRootsKevinLinDev(double a, double b, double c, double d, double epsilon = Epsilon)
        {
            // If a is 0 the polynomial is quadratic.
            if (a is 0d)
            {
                return(QuadraticRootsTests.QuadraticRoots(b, c, d, epsilon));
            }

            var ba = b / a;
            var ca = c / a;
            var da = d / a;

            var q = ((3d * ca) - (ba * ba)) * OneThird;
            var r = ((2d * ba * ba * ba) - (9d * ca * ba) + (27d * da)) * OneTwentySeventh;

            var offset       = ba * OneThird;
            var discriminant = (r * r * OneQuarter) + (q * q * q * OneTwentySeventh);

            var halfR = OneHalf * r;

            //var ZEROepsilon = ZeroErrorEstimate();

            if (Abs(discriminant) <= epsilon)//ZEROepsilon)
            {
                discriminant = 0d;
            }

            var results = new HashSet <double>();

            if (discriminant > 0d)
            {
                var e    = Sqrt(discriminant);
                var tmp  = -halfR + e;
                var root = tmp >= 0 ? Cbrt(tmp) : -Cbrt(-tmp);
                tmp = -halfR - e;
                if (tmp >= 0)
                {
                    root += Cbrt(tmp);
                }
                else
                {
                    root -= Cbrt(-tmp);
                }

                results.Add(root - offset);
            }
            else if (discriminant < 0d)
            {
                var distance = Sqrt(-q * OneThird);
                var angle    = Atan2(Sqrt(-discriminant), -halfR) * OneThird;

                //var (c, s) = ();

                var cos = Cos(angle);
                var sin = Sin(angle);
                results.Add((2d * distance * cos) - offset);
                results.Add((-distance * (cos + (Sqrt3 * sin))) - offset);
                results.Add((-distance * (cos - (Sqrt3 * sin))) - offset);
            }
            else
            {
                var tmp = halfR >= 0d ? -Cbrt(halfR) : Cbrt(-halfR);
                results.Add((2d * tmp) - offset);
                // really should return next root twice, but we return only one
                results.Add(-tmp - offset);
            }
            return(results.ToList());
        }
        public static Intersection QuadraticBezierSegmentCubicBezierSegmentIntersection2(
            double a1X, double a1Y, double a2X, double a2Y, double a3X, double a3Y,
            double b1X, double b1Y, double b2X, double b2Y, double b3X, double b3Y, double b4X, double b4Y,
            double epsilon = Epsilon)
        {
            var result = new Intersection(IntersectionStates.NoIntersection);

            // ToDo: Break early if the AABB bounding box of the curve does not intersect.

            var c12 = new Vector2D(a1X - (a2X * 2) + a3X, a1Y - (a2Y * 2) + a3Y);
            var c11 = new Vector2D(2 * (a2X - a1X), 2 * (a2Y - a1Y));
            var c23 = new Vector2D(b4X - (b3X * 3) + (b2X * 3) - (b1X * 1), b4Y - (b3Y * 3) + (b2Y * 3) - (b1Y * 1));
            var c22 = new Vector2D(3 * (b3X - (b2X * 2) + b1X), 3 * (b3Y - (b2Y * 2) + b1Y));
            var c21 = new Vector2D(3 * (b2X - b1X), 3 * (b2Y - b1Y));

            var c10x2 = a1X * a1X;
            var c10y2 = a1Y * a1Y;
            var c11x2 = c11.I * c11.I;
            var c11y2 = c11.J * c11.J;
            var c12x2 = c12.I * c12.I;
            var c12y2 = c12.J * c12.J;

            var c20x2 = b1X * b1X;
            var c20y2 = b1Y * b1Y;
            var c21x2 = c21.I * c21.I;
            var c21y2 = c21.J * c21.J;
            var c22x2 = c22.I * c22.I;
            var c22y2 = c22.J * c22.J;
            var c23x2 = c23.I * c23.I;
            var c23y2 = c23.J * c23.J;

            var roots = new Polynomial(
                /* t^0 */ (-2 * c12.I * c12.J * c22.I * c23.J) - (2 * c12.I * c12.J * c22.J * c23.I) + (2 * c12y2 * c22.I * c23.I) + (2 * c12x2 * c22.J * c23.J),
                /* t^1 */ (-2 * c12.I * c12.J * c23.I * c23.J) + (c12x2 * c23y2) + (c12y2 * c23x2),
                /* t^2 */ (-2 * c12.I * c21.I * c12.J * c23.J) - (2 * c12.I * c12.J * c21.J * c23.I) - (2 * c12.I * c12.J * c22.I * c22.J) + (2 * c21.I * c12y2 * c23.I) + (c12y2 * c22x2) + (c12x2 * ((2 * c21.J * c23.J) + c22y2)),
                /* t^3 */ (2 * a1X * c12.I * c12.J * c23.J) + (2 * a1Y * c12.I * c12.J * c23.I) + (c11.I * c11.J * c12.I * c23.J) + (c11.I * c11.J * c12.J * c23.I) - (2 * b1X * c12.I * c12.J * c23.J) - (2 * c12.I * b1Y * c12.J * c23.I) - (2 * c12.I * c21.I * c12.J * c22.J) - (2 * c12.I * c12.J * c21.J * c22.I) - (2 * a1X * c12y2 * c23.I) - (2 * a1Y * c12x2 * c23.J) + (2 * b1X * c12y2 * c23.I) + (2 * c21.I * c12y2 * c22.I) - (c11y2 * c12.I * c23.I) - (c11x2 * c12.J * c23.J) + (c12x2 * ((2 * b1Y * c23.J) + (2 * c21.J * c22.J))),
                /* t^4 */ (2 * a1X * c12.I * c12.J * c22.J) + (2 * a1Y * c12.I * c12.J * c22.I) + (c11.I * c11.J * c12.I * c22.J) + (c11.I * c11.J * c12.J * c22.I) - (2 * b1X * c12.I * c12.J * c22.J) - (2 * c12.I * b1Y * c12.J * c22.I) - (2 * c12.I * c21.I * c12.J * c21.J) - (2 * a1X * c12y2 * c22.I) - (2 * a1Y * c12x2 * c22.J) + (2 * b1X * c12y2 * c22.I) - (c11y2 * c12.I * c22.I) - (c11x2 * c12.J * c22.J) + (c21x2 * c12y2) + (c12x2 * ((2 * b1Y * c22.J) + c21y2)),
                /* t^5 */ (2 * a1X * c12.I * c12.J * c21.J) + (2 * a1Y * c12.I * c21.I * c12.J) + (c11.I * c11.J * c12.I * c21.J) + (c11.I * c11.J * c21.I * c12.J) - (2 * b1X * c12.I * c12.J * c21.J) - (2 * c12.I * b1Y * c21.I * c12.J) - (2 * a1X * c21.I * c12y2) - (2 * a1Y * c12x2 * c21.J) + (2 * b1X * c21.I * c12y2) - (c11y2 * c12.I * c21.I) - (c11x2 * c12.J * c21.J) + (2 * c12x2 * b1Y * c21.J),
                /* t^6 */ (-2 * a1X * a1Y * c12.I * c12.J) - (a1X * c11.I * c11.J * c12.J) - (a1Y * c11.I * c11.J * c12.I) + (2 * a1X * c12.I * b1Y * c12.J) + (2 * a1Y * b1X * c12.I * c12.J) + (c11.I * b1X * c11.J * c12.J) + (c11.I * c11.J * c12.I * b1Y) - (2 * b1X * c12.I * b1Y * c12.J) - (2 * a1X * b1X * c12y2) + (a1X * c11y2 * c12.I) + (a1Y * c11x2 * c12.J) - (2 * a1Y * c12x2 * b1Y) - (b1X * c11y2 * c12.I) - (c11x2 * b1Y * c12.J) + (c10x2 * c12y2) + (c10y2 * c12x2) + (c20x2 * c12y2) + (c12x2 * c20y2)
                ).RootsInInterval(0, 1);

            foreach (var s in roots)
            {
                var point  = new Point2D((c23.I * s * s * s) + (c22.I * s * s) + (c21.I * s) + b1X, (c23.J * s * s * s) + (c22.J * s * s) + (c21.J * s) + b1Y);
                var xRoots = QuadraticRootsTests.QuadraticRoots(
                    /* c */ c12.I,
                    /* t^1 */ c11.I,
                    /* t^2 */ a1X - point.X,
                    epsilon);
                var yRoots = QuadraticRootsTests.QuadraticRoots(
                    /* c */ c12.J,
                    /* t^1 */ c11.J,
                    /* t^2 */ a1Y - point.Y,
                    epsilon);
                if (xRoots.Count > 0 && yRoots.Count > 0)
                {
                    foreach (var xRoot in xRoots)
                    {
                        if (0 <= xRoot && xRoot <= 1)
                        {
                            foreach (var yRoot in yRoots)
                            {
                                var t = xRoot - yRoot;
                                if ((t >= 0 ? t : -t) < epsilon)
                                {
                                    result.Items.Add(point);
                                    goto checkRoots;
                                }
                            }
                        }
                    }
                    checkRoots :;
                }
            }

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

            return(result);
        }
        public static Intersection QuadraticBezierSegmentCubicBezierSegmentIntersection1(
            double a1X, double a1Y, double a2X, double a2Y, double a3X, double a3Y,
            double b1X, double b1Y, double b2X, double b2Y, double b3X, double b3Y, double b4X, double b4Y,
            double epsilon = Epsilon)
        {
            var a   = new Vector2D(a2X, a2Y) * -2;
            var c12 = new Vector2D(a1X, a1Y) + a + new Vector2D(a3X, a3Y);

            a = new Vector2D(a1X, a1Y) * -2;
            var b   = new Vector2D(a2X, a2Y) * 2;
            var c11 = a + b;
            var c10 = new Vector2D(a1X, a1Y);

            a = new Vector2D(b1X, b1Y) * -1;
            b = new Vector2D(b2X, b2Y) * 3;
            var c   = new Vector2D(b3X, b3Y) * -3;
            var d   = a + b + c + new Vector2D(b4X, b4Y);
            var c23 = new Vector2D(d.I, d.J);

            a = new Vector2D(b1X, b1Y) * 3;
            b = new Vector2D(b2X, b2Y) * -6;
            c = new Vector2D(b3X, b3Y) * 3;
            d = a + b + c;
            var c22 = new Vector2D(d.I, d.J);

            a = new Vector2D(b1X, b1Y) * -3;
            b = new Vector2D(b2X, b2Y) * 3;
            c = a + b;
            var c21 = new Vector2D(c.I, c.J);
            var c20 = new Vector2D(b1X, b1Y);

            var c10x2 = c10.I * c10.I;
            var c10y2 = c10.J * c10.J;
            var c11x2 = c11.I * c11.I;
            var c11y2 = c11.J * c11.J;
            var c12x2 = c12.I * c12.I;
            var c12y2 = c12.J * c12.J;
            var c20x2 = c20.I * c20.I;
            var c20y2 = c20.J * c20.J;
            var c21x2 = c21.I * c21.I;
            var c21y2 = c21.J * c21.J;
            var c22x2 = c22.I * c22.I;
            var c22y2 = c22.J * c22.J;
            var c23x2 = c23.I * c23.I;
            var c23y2 = c23.J * c23.J;

            var roots = new Polynomial(
                (-2 * c12.I * c12.J * c22.I * c23.J) - (2 * c12.I * c12.J * c22.J * c23.I) + (2 * c12y2 * c22.I * c23.I) + (2 * c12x2 * c22.J * c23.J),
                (-2 * c12.I * c12.J * c23.I * c23.J) + (c12x2 * c23y2) + (c12y2 * c23x2),
                (-2 * c12.I * c21.I * c12.J * c23.J) - (2 * c12.I * c12.J * c21.J * c23.I) - (2 * c12.I * c12.J * c22.I * c22.J) + (2 * c21.I * c12y2 * c23.I) + (c12y2 * c22x2) + (c12x2 * ((2 * c21.J * c23.J) + c22y2)),
                (2 * c10.I * c12.I * c12.J * c23.J) + (2 * c10.J * c12.I * c12.J * c23.I) + (c11.I * c11.J * c12.I * c23.J) + (c11.I * c11.J * c12.J * c23.I) - (2 * c20.I * c12.I * c12.J * c23.J) - (2 * c12.I * c20.J * c12.J * c23.I) - (2 * c12.I * c21.I * c12.J * c22.J) - (2 * c12.I * c12.J * c21.J * c22.I) - (2 * c10.I * c12y2 * c23.I) - (2 * c10.J * c12x2 * c23.J) + (2 * c20.I * c12y2 * c23.I) + (2 * c21.I * c12y2 * c22.I) - (c11y2 * c12.I * c23.I) - (c11x2 * c12.J * c23.J) + (c12x2 * ((2 * c20.J * c23.J) + (2 * c21.J * c22.J))),
                (2 * c10.I * c12.I * c12.J * c22.J) + (2 * c10.J * c12.I * c12.J * c22.I) + (c11.I * c11.J * c12.I * c22.J) + (c11.I * c11.J * c12.J * c22.I) - (2 * c20.I * c12.I * c12.J * c22.J) - (2 * c12.I * c20.J * c12.J * c22.I) - (2 * c12.I * c21.I * c12.J * c21.J) - (2 * c10.I * c12y2 * c22.I) - (2 * c10.J * c12x2 * c22.J) + (2 * c20.I * c12y2 * c22.I) - (c11y2 * c12.I * c22.I) - (c11x2 * c12.J * c22.J) + (c21x2 * c12y2) + (c12x2 * ((2 * c20.J * c22.J) + c21y2)),
                (2 * c10.I * c12.I * c12.J * c21.J) + (2 * c10.J * c12.I * c21.I * c12.J) + (c11.I * c11.J * c12.I * c21.J) + (c11.I * c11.J * c21.I * c12.J) - (2 * c20.I * c12.I * c12.J * c21.J) - (2 * c12.I * c20.J * c21.I * c12.J) - (2 * c10.I * c21.I * c12y2) - (2 * c10.J * c12x2 * c21.J) + (2 * c20.I * c21.I * c12y2) - (c11y2 * c12.I * c21.I) - (c11x2 * c12.J * c21.J) + (2 * c12x2 * c20.J * c21.J),
                (-2 * c10.I * c10.J * c12.I * c12.J) - (c10.I * c11.I * c11.J * c12.J) - (c10.J * c11.I * c11.J * c12.I) + (2 * c10.I * c12.I * c20.J * c12.J) + (2 * c10.J * c20.I * c12.I * c12.J) + (c11.I * c20.I * c11.J * c12.J) + (c11.I * c11.J * c12.I * c20.J) - (2 * c20.I * c12.I * c20.J * c12.J) - (2 * c10.I * c20.I * c12y2) + (c10.I * c11y2 * c12.I) + (c10.J * c11x2 * c12.J) - (2 * c10.J * c12x2 * c20.J) - (c20.I * c11y2 * c12.I) - (c11x2 * c20.J * c12.J) + (c10x2 * c12y2) + (c10y2 * c12x2) + (c20x2 * c12y2) + (c12x2 * c20y2)
                ).RootsInInterval();

            var result = new Intersection(IntersectionStates.NoIntersection);

            for (var i = 0; i < roots.Length; i++)
            {
                var s      = roots[i];
                var xRoots = QuadraticRootsTests.QuadraticRoots(
                    c12.I,
                    c11.I,
                    c10.I - c20.I - (s * c21.I) - (s * s * c22.I) - (s * s * s * c23.I),
                    epsilon);
                var yRoots = QuadraticRootsTests.QuadraticRoots(
                    c12.J,
                    c11.J,
                    c10.J - c20.J - (s * c21.J) - (s * s * c22.J) - (s * s * s * c23.J),
                    epsilon);
                if (xRoots.Count > 0 && yRoots.Count > 0)
                {
                    for (var j = 0; j < xRoots.Count; j++)
                    {
                        var xRoot = xRoots[j];
                        if (0 <= xRoot && xRoot <= 1)
                        {
                            for (var k = 0; k < yRoots.Count; k++)
                            {
                                if (Abs(xRoot - yRoots[k]) < epsilon)
                                {
                                    result.Items.Add(((Point2D)c23 * s * s * s) + ((c22 * s * s) + ((c21 * s) + c20)));
                                    goto checkRoots;
                                }
                            }
                        }
                    }
                    checkRoots :;
                }
            }

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

            return(result);
        }
Пример #7
0
        public static Intersection QuadraticBezierSegmentQuadraticBezierSegmentIntersection00(
            double a1X, double a1Y, double a2X, double a2Y, double a3X, double a3Y,
            double b1X, double b1Y, double b2X, double b2Y, double b3X, double b3Y,
            double epsilon = Epsilon)
        {
            // Initialize the intersection.
            var result = new Intersection(IntersectionStates.NoIntersection);

            // ToDo: Break early if the AABB of the ends and handles do not intersect.
            // ToDo: Break early if the AABB of the curve does not intersect.

            // Parametric matrix form of the Bézier curve
            var xCoeffA = QuadraticBezierBernsteinBasisTests.QuadraticBezierBernsteinBasis(a1X, a2X, a3X);
            var yCoeffA = QuadraticBezierBernsteinBasisTests.QuadraticBezierBernsteinBasis(a1Y, a2Y, a3Y);
            var xCoeffB = QuadraticBezierBernsteinBasisTests.QuadraticBezierBernsteinBasis(b1X, b2X, b3X);
            var yCoeffB = QuadraticBezierBernsteinBasisTests.QuadraticBezierBernsteinBasis(b1Y, b2Y, b3Y);

            IList <double> roots = new List <double>();

            if (yCoeffA.C == 0)
            {
                var v0 = xCoeffA.C * (yCoeffA.A - yCoeffB.A);
                var v1 = v0 - (xCoeffA.B * yCoeffA.B);
                var v2 = v0 + v1;
                var v3 = yCoeffA.B * yCoeffA.B;

                roots = QuarticRootsTests.QuarticRoots(
                    /* t^4 */ xCoeffA.C * yCoeffB.C * yCoeffB.C,
                    /* t^3 */ 2 * xCoeffA.C * yCoeffB.B * yCoeffB.C,
                    /* t^2 */ (xCoeffA.C * yCoeffB.B * yCoeffB.B) - (xCoeffB.C * v3) - (yCoeffB.C * v0) - (yCoeffB.C * v1),
                    /* t^1 */ (-xCoeffB.B * v3) - (yCoeffB.B * v0) - (yCoeffB.B * v1),
                    /* C^0 */ ((xCoeffA.A - xCoeffB.A) * v3) + ((yCoeffA.A - yCoeffB.A) * v1),
                    epsilon);
            }
            else
            {
                var v0 = (xCoeffA.C * yCoeffB.C) - (yCoeffA.C * xCoeffB.C);
                var v1 = (xCoeffA.C * yCoeffB.B) - (xCoeffB.B * yCoeffA.C);
                var v2 = (xCoeffA.B * yCoeffA.C) - (yCoeffA.B * xCoeffA.C);
                var v3 = yCoeffA.A - yCoeffB.A;
                var v4 = (yCoeffA.C * (xCoeffA.A - xCoeffB.A)) - (xCoeffA.C * v3);
                var v5 = (-yCoeffA.B * v2) + (yCoeffA.C * v4);
                var v6 = v2 * v2;
                roots = QuarticRootsTests.QuarticRoots(
                    /* t^4 */ v0 * v0,
                    /* t^3 */ 2 * v0 * v1,
                    /* t^2 */ ((-yCoeffB.C * v6) + (yCoeffA.C * v1 * v1) + (yCoeffA.C * v0 * v4) + (v0 * v5)) / yCoeffA.C,
                    /* t^1 */ ((-yCoeffB.B * v6) + (yCoeffA.C * v1 * v4) + (v1 * v5)) / yCoeffA.C,
                    /* C^0 */ ((v3 * v6) + (v4 * v5)) / yCoeffA.C,
                    epsilon);
            }

            foreach (var s in roots)
            {
                var point = new Point2D(
                    (xCoeffB.C * s * s) + (xCoeffB.B * s) + xCoeffB.A,
                    (yCoeffB.C * s * s) + (yCoeffB.B * s) + yCoeffB.A);
                if (s >= 0 && s <= 1)
                {
                    var xRoots = QuadraticRootsTests.QuadraticRoots(
                        /* t^2 */ -xCoeffA.C,
                        /* t^1 */ -xCoeffA.B,
                        /* C^0 */ -xCoeffA.A + point.X,
                        epsilon);
                    var yRoots = QuadraticRootsTests.QuadraticRoots(
                        /* t^2 */ -yCoeffA.C,
                        /* t^1 */ -yCoeffA.B,
                        /* C^0 */ -yCoeffA.A + point.Y,
                        epsilon);

                    if (xRoots.Count > 0 && yRoots.Count > 0)
                    {
                        // Find the nearest matching x and y roots in the ranges 0 < x < 1; 0 < y < 1.
                        foreach (var xRoot in xRoots)
                        {
                            if (xRoot >= 0 && xRoot <= 1)
                            {
                                foreach (var yRoot in yRoots)
                                {
                                    var t = xRoot - yRoot;
                                    if ((t >= 0 ? t : -t) < epsilon)
                                    {
                                        result.AppendPoint(point);
                                        goto checkRoots; // Break through two levels of foreach loops to exit early. Using goto for performance.
                                    }
                                }
                            }
                        }
                        checkRoots :;
                    }
                }
            }

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

            return(result);
        }
Пример #8
0
        public static Intersection QuadraticBezierSegmentQuadraticBezierSegmentIntersection3(
            double a1X, double a1Y, double a2X, double a2Y, double a3X, double a3Y,
            double b1X, double b1Y, double b2X, double b2Y, double b3X, double b3Y,
            double epsilon = Epsilon)
        {
            var result = new Intersection(IntersectionStates.NoIntersection);

            // ToDo: Break early if the AABB bounding box of the curve does not intersect.

            var c12 = new Vector2D(a1X - (a2X * 2) + a3X, a1Y - (a2Y * 2) + a3Y);
            var c11 = new Vector2D(2 * (a2X - a1X), 2 * (a2Y - a1Y));
            var c22 = new Vector2D(b1X - (b2X * 2) + b3X, b1Y - (b2Y * 2) + b3Y);
            var c21 = new Vector2D(2 * (b2X - b1X), 2 * (b2Y - b1Y));

            var a = (c12.I * c11.J) - (c11.I * c12.J);
            var b = (c22.I * c11.J) - (c11.I * c22.J);
            var c = (c21.I * c11.J) - (c11.I * c21.J);
            var d = (c11.I * (a1Y - b1Y)) + (c11.J * (b1X - a1X));

            var e = (c22.I * c12.J) - (c12.I * c22.J);
            var f = (c21.I * c12.J) - (c12.I * c21.J);
            var g = (c12.I * (a1Y - b1Y)) + (c12.J * (b1X - a1X));

            var roots = QuarticRootsTests.QuarticRoots(
                /* C */ -e * e,
                /* t^1 */ -2 * e * f,
                /* t^2 */ (a * b) - (f * f) - (2 * e * g),
                /* t^3 */ (a * c) - (2 * f * g),
                /* t^4 */ (a * d) - (g * g),
                epsilon);

            foreach (var s in roots)
            {
                var point = new Point2D((c22.I * s * s) + (c21.I * s) + b1X, (c22.J * s * s) + (c21.J * s) + b1Y);
                if (0 <= s && s <= 1)
                {
                    var xRoots = QuadraticRootsTests.QuadraticRoots(
                        /* C */ -c12.I,
                        /* t^1 */ -c11.I,
                        /* t^2 */ -a1X + point.X,
                        epsilon);
                    var yRoots = QuadraticRootsTests.QuadraticRoots(
                        /* C */ -c12.J,
                        /* t^1 */ -c11.J,
                        /* t^2 */ -a1Y + point.Y,
                        epsilon);

                    if (xRoots.Count > 0 && yRoots.Count > 0)
                    {
                        // Find the nearest matching x and y roots in the ranges 0 < x < 1; 0 < y < 1.
                        foreach (var xRoot in xRoots)
                        {
                            if (xRoot >= 0 && xRoot <= 1)
                            {
                                foreach (var yRoot in yRoots)
                                {
                                    var t = xRoot - yRoot;
                                    if ((t >= 0 ? t : -t) < epsilon)
                                    {
                                        result.Items.Add(point);
                                        goto checkRoots; // Break through two levels of foreach loops. Using goto for performance.
                                    }
                                }
                            }
                        }
                        checkRoots :;
                    }
                }
            }

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

            return(result);
        }
Пример #9
0
        public static Intersection QuadraticBezierSegmentQuadraticBezierSegmentIntersection2(
            double a1X, double a1Y, double a2X, double a2Y, double a3X, double a3Y,
            double b1X, double b1Y, double b2X, double b2Y, double b3X, double b3Y,
            double epsilon = Epsilon)
        {
            var va  = new Vector2D(a2X, a2Y) * -2;
            var c12 = new Vector2D(a1X, a1Y) + va + new Vector2D(a3X, a3Y);

            va = new Vector2D(a1X, a1Y) * -2;
            var vb  = new Vector2D(a2X, a2Y) * 2;
            var c11 = va + vb;
            var c10 = new Vector2D(a1X, a1Y);

            va = new Vector2D(b2X, b2Y) * -2;
            var c22 = new Vector2D(b1X, b1Y) + va + new Vector2D(b3X, b3Y);

            va = new Vector2D(b1X, b1Y) * -2;
            vb = new Vector2D(b2X, b2Y) * 2;
            var c21 = va + vb;
            var c20 = new Vector2D(b1X, b1Y);

            var a = (c12.I * c11.J) - (c11.I * c12.J);
            var b = (c22.I * c11.J) - (c11.I * c22.J);
            var c = (c21.I * c11.J) - (c11.I * c21.J);
            var d = (c11.I * (c10.J - c20.J)) + (c11.J * (-c10.I + c20.I));
            var e = (c22.I * c12.J) - (c12.I * c22.J);
            var f = (c21.I * c12.J) - (c12.I * c21.J);
            var g = (c12.I * (c10.J - c20.J)) + (c12.J * (-c10.I + c20.I));

            var roots = QuarticRootsTests.QuarticRoots(
                -e * e,
                -2 * e * f,
                (a * b) - (f * f) - (2 * e * g),
                (a * c) - (2 * f * g),
                (a * d) - (g * g),
                epsilon);

            var result = new Intersection(IntersectionStates.NoIntersection);

            for (var i = 0; i < roots.Count; i++)
            {
                var s = roots[i];
                if (0 <= s && s <= 1)
                {
                    var xRoots = QuadraticRootsTests.QuadraticRoots(
                        -c12.I,
                        -c11.I,
                        -c10.I + c20.I + (s * c21.I) + (s * s * c22.I),
                        epsilon);
                    var yRoots = QuadraticRootsTests.QuadraticRoots(
                        -c12.J,
                        -c11.J,
                        -c10.J + c20.J + (s * c21.J) + (s * s * c22.J),
                        epsilon);
                    if (xRoots.Count > 0 && yRoots.Count > 0)
                    {
                        for (var j = 0; j < xRoots.Count; j++)
                        {
                            var xRoot = xRoots[j];
                            if (0 <= xRoot && xRoot <= 1)
                            {
                                for (var k = 0; k < yRoots.Count; k++)
                                {
                                    if (Abs(xRoot - yRoots[k]) < epsilon)
                                    {
                                        result.Items.Add(((Point2D)c22 * s * s) + ((c21 * s) + c20));
                                        goto checkRoots;
                                    }
                                }
                            }
                        }
                        checkRoots :;
                    }
                }
            }

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

            return(result);
        }
Пример #10
0
        public static Intersection QuadraticBezierSegmentQuadraticBezierSegmentIntersection1(
            double a1X, double a1Y, double a2X, double a2Y, double a3X, double a3Y,
            double b1X, double b1Y, double b2X, double b2Y, double b3X, double b3Y,
            double epsilon = Epsilon)
        {
            var result = new Intersection(IntersectionStates.NoIntersection);

            // ToDo: Break early if the AABB bounding box of the curve does not intersect.
            // ToDo: Figure out if the following can be broken out of the vector structs.

            var c12 = new Vector2D(a1X - (a2X * 2) + a3X, a1Y - (a2Y * 2) + a3Y);
            var c11 = new Vector2D(2 * (a2X - a1X), 2 * (a2Y - a1Y));
            // c10 is a1X and a1Y

            var c22 = new Vector2D(b1X - (b2X * 2) + b3X, b1Y - (b2Y * 2) + b3Y);
            var c21 = new Vector2D(2 * (b2X - b1X), 2 * (b2Y - b1Y));
            // c20 is b1X and b1Y

            var a = (c12.I * c11.J) - (c11.I * c12.J);

            var b = (c22.I * c11.J) - (c11.I * c22.J);
            var c = (c21.I * c11.J) - (c11.I * c21.J);
            var d = (c11.I * (a1Y - b1Y)) - (c11.J * (b1X - a1X));

            var e = (-c22.I * c12.J) - (c12.I * c22.J);
            var f = (c21.I * c12.J) - (c12.I * c21.J);
            var g = (c12.I * (a1Y - b1Y)) - (c12.J * (b1X - a1X));

            IList <double> roots;

            if ((a * d) - (g * g) == 0)
            {
                var v0 = (a * c) - (2 * f * g);
                var v1 = (a * b) - (f * f) - (2 * e * g);
                var v2 = -2 * e * f;
                var v3 = -e * e;
                roots = CubicRootsTests.CubicRoots(
                    /* t^3 */ -v3,
                    /* t^2 */ -v2,
                    /* t^1 */ -v1,
                    /* C */ -v0,
                    epsilon);
            }
            else
            {
                var v0 = (a * d) - (g * g);
                var v1 = (a * c) - (2 * f * g);
                var v2 = (a * b) - (f * f) - (2 * e * g);
                var v3 = -2 * e * f;
                var v4 = -e * e;
                roots = QuarticRootsTests.QuarticRoots(
                    /* t^4 */ -v4,
                    /* t^3 */ -v3,
                    /* t^2 */ -v2,
                    /* t^1 */ -v1,
                    /* C */ -v0,
                    epsilon);
            }

            //roots.Reverse();
            foreach (var s in roots)
            {
                var point = new Point2D(
                    (c22.I * s * s) + (c21.I * s) + b1X,
                    (c22.J * s * s) + (c21.J * s) + b1Y);
                if (s >= 0 && s <= 1)
                {
                    var v0     = a1X - point.X;
                    var v1     = c11.I;
                    var v2     = c12.I;
                    var xRoots = QuadraticRootsTests.QuadraticRoots(
                        /* t^2 */ -v2,
                        /* t^1 */ -v1,
                        /* C */ -v0,
                        epsilon);
                    v0 = a1Y - point.Y;
                    v1 = c11.J;
                    v2 = c12.J;
                    var yRoots = QuadraticRootsTests.QuadraticRoots(
                        /* t^2 */ -v2,
                        /* t^1 */ -v1,
                        /* C */ -v0,
                        epsilon);

                    if (xRoots.Count > 0 && yRoots.Count > 0)
                    {
                        // Find the nearest matching x and y roots in the ranges 0 < x < 1; 0 < y < 1.
                        foreach (var xRoot in xRoots)
                        {
                            if (xRoot >= 0 && xRoot <= 1)
                            {
                                foreach (var yRoot in yRoots)
                                {
                                    var t = xRoot - yRoot;
                                    if ((t >= 0 ? t : -t) < 0.1)
                                    {
                                        result.AppendPoint(point);
                                        goto checkRoots; // Break through two levels of foreach loops. Using goto for performance.
                                    }
                                }
                            }
                        }
                        checkRoots :;
                    }
                }
            }

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

            return(result);
        }
Пример #11
0
        public static Intersection QuadraticBezierSegmentQuadraticBezierSegmentIntersection0(
            double a1X, double a1Y, double a2X, double a2Y, double a3X, double a3Y,
            double b1X, double b1Y, double b2X, double b2Y, double b3X, double b3Y,
            double epsilon = Epsilon)
        {
            // Initialize the intersection.
            var result = new Intersection(IntersectionStates.NoIntersection);

            var xCoeffA = QuadraticBezierBernsteinBasisTests.QuadraticBezierBernsteinBasis(a1X, a2X, a3X);
            var yCoeffA = QuadraticBezierBernsteinBasisTests.QuadraticBezierBernsteinBasis(a1Y, a2Y, a3Y);
            var xCoeffB = QuadraticBezierBernsteinBasisTests.QuadraticBezierBernsteinBasis(b1X, b2X, b3X);
            var yCoeffB = QuadraticBezierBernsteinBasisTests.QuadraticBezierBernsteinBasis(b1Y, b2Y, b3Y);

            var a = (xCoeffA.C * yCoeffA.B) - (xCoeffA.B * yCoeffA.C);
            var b = (xCoeffB.C * yCoeffA.B) - (xCoeffA.B * yCoeffB.C);

            var c = (xCoeffB.B * yCoeffA.B) - (xCoeffA.B * yCoeffB.B);
            var d = (xCoeffA.B * (yCoeffA.A - yCoeffB.A)) - (yCoeffA.B * (xCoeffB.A - xCoeffA.A));
            var e = (xCoeffB.C * yCoeffA.C) - (xCoeffA.C * yCoeffB.C);
            var f = (xCoeffB.B * yCoeffA.C) - (xCoeffA.C * yCoeffB.B);
            var g = (xCoeffA.C * (yCoeffA.A - yCoeffB.A)) - (yCoeffA.C * (yCoeffB.A - xCoeffA.A));

            var roots = QuarticRootsTests.QuarticRoots(
                /* t^4 */ e * e,
                /* t^3 */ 2 * e * f,
                /* t^2 */ (-a * b) + (f * f) + (2 * e * g),
                /* t^1 */ (-a * c) + (2 * f * g),
                /* C */ (-a * d) + (g * g),
                epsilon);

            foreach (var s in roots)
            {
                var point = new Point2D(
                    (xCoeffB.C * s * s) + (xCoeffB.B * s) + xCoeffB.A,
                    (yCoeffB.C * s * s) + (yCoeffB.B * s) + yCoeffB.A);
                if (s >= 0 && s <= 1)
                {
                    var xRoots = QuadraticRootsTests.QuadraticRoots(
                        /* t^2 */ -xCoeffA.C,
                        /* t^1 */ -xCoeffA.B,
                        /* C */ -xCoeffA.A + point.X,
                        epsilon);
                    var yRoots = QuadraticRootsTests.QuadraticRoots(
                        /* t^2 */ -yCoeffA.C,
                        /* t^1 */ -yCoeffA.B,
                        /* C */ -yCoeffA.A + point.Y,
                        epsilon);

                    if (xRoots.Count > 0 && yRoots.Count > 0)
                    {
                        // Find the nearest matching x and y roots in the ranges 0 < x < 1; 0 < y < 1.
                        foreach (var xRoot in xRoots)
                        {
                            if (xRoot >= 0 && xRoot <= 1)
                            {
                                foreach (var yRoot in yRoots)
                                {
                                    var t = xRoot - yRoot;
                                    if ((t >= 0 ? t : -t) < 0.06) // ToDo: Find the error and replace 0.06 with epsilon.
                                    {
                                        result.AppendPoint(point);
                                        goto checkRoots; // Break through two levels of foreach loops. Using goto for performance.
                                    }
                                }
                            }
                        }
                        checkRoots :;
                    }
                }
            }

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

            return(result);
        }