예제 #1
0
        public static Intersection CubicBezierLineSegmentIntersection1(
            double p0x, double p0y,
            double p1x, double p1y,
            double p2x, double p2y,
            double p3x, double p3y,
            double l0x, double l0y,
            double l1x, double l1y,
            double epsilon = Epsilon)
        {
            _ = epsilon;
            // ToDo: Figure out why this can't handle intersection with horizontal lines.
            var I = new Intersection(IntersectionStates.NoIntersection);

            var A = l1y - l0y;                                 //A=y2-y1
            var B = l0x - l1x;                                 //B=x1-x2
            var C = (l0x * (l0y - l1y)) + (l0y * (l1x - l0x)); //C=x1*(y1-y2)+y1*(x2-x1)

            var xCoeff = CubicBezierBernsteinBasisTests.CubicBezierBernsteinBasis(p0x, p1x, p2x, p3x);
            var yCoeff = CubicBezierBernsteinBasisTests.CubicBezierBernsteinBasis(p0y, p1y, p2y, p3y);

            var r = CubicRootsTests.CubicRoots(
                /* t^3 */ (A * xCoeff.D) + (B * yCoeff.D),
                /* t^2 */ (A * xCoeff.C) + (B * yCoeff.C),
                /* t^1 */ (A * xCoeff.B) + (B * yCoeff.B),
                /* 1 */ (A * xCoeff.A) + (B * yCoeff.A) + C
                );

            /*verify the roots are in bounds of the linear segment*/
            for (var i = 0; i < 3; i++)
            {
                var t = r[i];

                var x = (xCoeff.D * t * t * t) + (xCoeff.C * t * t) + (xCoeff.B * t) + xCoeff.A;
                var y = (yCoeff.D * t * t * t) + (yCoeff.C * t * t) + (yCoeff.B * t) + yCoeff.A;

                /*above is intersection point assuming infinitely long line segment,
                 * make sure we are also in bounds of the line*/
                double m;
                m = (l1x - l0x) != 0 ? (x - l0x) / (l1x - l0x) : (y - l0y) / (l1y - l0y);

                /*in bounds?*/
                if (t < 0 || t > 1d || m < 0 || m > 1d)
                {
                    x = 0; // -100;  /*move off screen*/
                    y = 0; // -100;
                }
                else
                {
                    /*intersection point*/
                    I.AppendPoint(new Point2D(x, y));
                    I.State = IntersectionStates.Intersection;
                }
            }
            return(I);
        }
예제 #2
0
        public static (double X, double Y)? CubicBezierSelfIntersection1(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3)
        {
            var(xCurveA, xCurveB, xCurveC, xCurveD) = CubicBezierBernsteinBasisTests.CubicBezierBernsteinBasis(x0, x1, x2, x3);
            (var a, var b) = (xCurveD == 0d) ? (xCurveC, xCurveB) : (xCurveC / xCurveD, xCurveB / xCurveD);
            var(yCurveA, yCurveB, yCurveC, yCurveD) = CubicBezierBernsteinBasisTests.CubicBezierBernsteinBasis(y0, y1, y2, y3);
            (var p, var q) = (yCurveD == 0d) ? (yCurveC, yCurveB) : (yCurveC / yCurveD, yCurveB / yCurveD);

            if (a == p || q == b)
            {
                return(null);
            }

            var k = (q - b) / (a - p);

            var poly = new double[]
            {
                (-k * k * k) - (a * k * k) - (b * k),
                (3 * k * k) + (2 * k * a) + (2 * b),
                -3 * k,
                2
            };

            var roots = CubicRootsTests.CubicRoots(poly[3], poly[2], poly[1], poly[0])
                        .OrderByDescending(c => c).ToArray();

            if (roots.Length != 3)
            {
                return(null);
            }

            if (roots[0] >= 0d && roots[0] <= 1d && roots[2] >= 0d && roots[2] <= 1d)
            {
                return(InterpolateCubic2DTests.CubicInterpolate2D(roots[0], x0, y0, x1, y1, x2, y2, x3, y3));
            }

            return(null);
        }
예제 #3
0
        public static IList <double> QuarticRoots0(double a, double b, double c, double d, double e, double epsilon = Epsilon)
        {
            // If a is 0 the polynomial is cubic.
            if (a is 0d)
            {
                return(CubicRootsTests.CubicRoots(b, c, d, e, epsilon));
            }

            var A = b / a;
            var B = c / a;
            var C = d / a;
            var D = e / a;

            var resolveRoots = CubicRootsTests.CubicRoots(
                (-A * A * D) + (4d * B * D) - (C * C),
                (A * C) - (4d * D),
                -B,
                1d,
                epsilon);
            var y            = resolveRoots[0];
            var discriminant = (A * A * OneQuarter) - B + y;

            // 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 ee    = Sqrt(discriminant);
                var t1    = (3d * A * A * OneQuarter) - (ee * ee) - (2d * B);
                var t2    = ((4d * A * B) - (8d * C) - (A * A * A)) / (4d * ee);
                var plus  = t1 + t2;
                var minus = t1 - t2;
                if (Abs(plus) <= epsilon)
                {
                    plus = 0d;
                }

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

                if (plus >= 0d)
                {
                    var f = Sqrt(plus);
                    results.Add((-A * OneQuarter) + ((ee + f) * OneHalf));
                    results.Add((-A * OneQuarter) + ((ee - f) * OneHalf));
                }
                if (minus >= 0d)
                {
                    var f = Sqrt(minus);
                    results.Add((-A * OneQuarter) + ((f - ee) * OneHalf));
                    results.Add((-A * OneQuarter) - ((f + ee) * OneHalf));
                }
            }
            else if (discriminant < 0d)
            {
            }
            else
            {
                var t2 = (y * y) - (4d * D);
                if (t2 >= -epsilon)
                {
                    if (t2 < 0)
                    {
                        t2 = 0d;
                    }

                    t2 = 2d * Sqrt(t2);
                    var t1 = (3d * A * A * OneQuarter) - (2d * B);
                    if (t1 + t2 >= epsilon)
                    {
                        var d0 = Sqrt(t1 + t2);
                        results.Add((-A * OneQuarter) + (d0 * OneHalf));
                        results.Add((-A * OneQuarter) - (d0 * OneHalf));
                    }
                    if (t1 - t2 >= epsilon)
                    {
                        var d1 = Sqrt(t1 - t2);
                        results.Add((-A * OneQuarter) + (d1 * OneHalf));
                        results.Add((-A * OneQuarter) - (d1 * OneHalf));
                    }
                }
            }

            return(results.ToList());
        }
예제 #4
0
        public static IList <double> QuarticRootsStephanSmola(double a, double b, double c, double d, double e, double epsilon = Epsilon)
        {
            // If a is 0 the polynomial is cubic.
            if (a is 0d)
            {
                return(CubicRootsTests.CubicRoots(b, c, d, e, epsilon));
            }

            var delta = (256d * a * a * a * e * e * e) - (192d * a * a * b * d * e * e) - (128d * a * a * c * c * e * e) + (144d * a * a * c * d * d * e) - (27d * a * a * d * d * d * d) + (144d * a * b * b * c * e * e) - (6d * a * b * b * d * d * e) - (80d * a * b * c * c * d * e) + (18d * a * b * c * d * d * d) + (16d * a * c * c * c * c * e) - (4d * a * c * c * c * d * d) - (27d * b * b * b * b * e * e) + (18d * b * b * b * c * d * e) - (4d * b * b * b * d * d * d) - (4d * b * b * c * c * c * e) + (b * b * c * c * d * d);
            var P     = (8d * a * c) - (3d * b * b);
            var D     = (64d * a * a * a * e) - (16d * a * a * c * c) + (16d * a * b * b * c) - (16d * a * a * b * d) - (3d * b * b * b * b);
            var d0    = (c * c) - (3d * b * d) + (12d * a * e);
            var d1    = (2d * c * c * c) - (9d * b * c * d) + (27d * b * b * e) + (27d * a * d * d) - (72d * a * c * e);
            var p     = ((8 * a * c) - (3d * b * b)) / (8d * a * a);
            var q     = ((b * b * b) - (4d * a * b * c) + (8 * a * a * d)) / (8d * a * a * a);
            var Q     = 0d;
            var S     = 0d;

            var phi = Acos(d1 / (2d * Sqrt(d0 * d0 * d0)));

            if (double.IsNaN(phi) && (d1 == 0d))
            {
                // if (delta < 0) I guess the new test is ok because we're only interested in real roots
                Q  = d1 + Sqrt((d1 * d1) - (4d * d0 * d0 * d0));
                Q /= 2d;
                Q  = Cbrt(Q);
                S  = 0.5d * Sqrt((-2d / 3d * p) + (1d / (3d * a) * (Q + (d0 / Q))));
            }
            else
            {
                S = 0.5d * Sqrt((-2d / 3d * p) + (2d / (3d * a) * Sqrt(d0) * Cos(phi / 3d)));
            }

            var y = new List <double>();

            if (S != 0d)
            {
                var R = (-4d * S * S) - (2d * p) + (q / S);

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

                if (R > 0d)
                {
                    R = 0.5d * Sqrt(R);
                    y.Add((-b / (4 * a)) - S + R);
                    y.Add((-b / (4 * a)) - S - R);
                }
                else if (Abs(R) < epsilon)
                {
                    y.Add((-b / (4d * a)) - S);
                }

                R = (-4d * S * S) - (2d * p) - (q / S);

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

                if (R > 0d)
                {
                    R = 0.5d * Sqrt(R);
                    y.Add((-b / (4d * a)) + S + R);
                    y.Add((-b / (4d * a)) + S - R);
                }
                else if (R == 0d)
                {
                    y.Add((-b / (4d * a)) + S);
                }
            }

            return(y);
        }
예제 #5
0
        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);
        }
예제 #6
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);
        }