コード例 #1
0
        public override unsafe SignedDistance SignedDistance(Vector2 origin, ref double param)
        {
            var qa          = _p[0] - origin;
            var ab          = _p[1] - _p[0];
            var br          = _p[0] + _p[2] - _p[1] - _p[1];
            var coefficient = stackalloc[]
            {
                Vector2.Dot(br, br),
                3 * Vector2.Dot(ab, br),
                2 * Vector2.Dot(ab, ab) + Vector2.Dot(qa, br),
                Vector2.Dot(qa, ab)
            };
            var t         = stackalloc double[3];
            var solutions = Equations.SolveCubic(t, coefficient);

            var minDistance = Arithmetic.NonZeroSign(Vector2.Cross(ab, qa)) * qa.Length(); // distance from A

            param = -Vector2.Dot(qa, ab) / Vector2.Dot(ab, ab);
            {
                var distance = Arithmetic.NonZeroSign(Vector2.Cross(_p[2] - _p[1], _p[2] - origin)) *
                               (_p[2] - origin).Length(); // distance from B
                if (Math.Abs(distance) < Math.Abs(minDistance))
                {
                    minDistance = distance;
                    param       = Vector2.Dot(origin - _p[1], _p[2] - _p[1]) /
                                  Vector2.Dot(_p[2] - _p[1], _p[2] - _p[1]);
                }
            }
            for (var i = 0; i < solutions; ++i)
            {
                if (t[i] > 0 && t[i] < 1)
                {
                    var endpoint = _p[0] + 2 * t[i] * ab + t[i] * t[i] * br;
                    var distance = Arithmetic.NonZeroSign(Vector2.Cross(_p[2] - _p[0], endpoint - origin)) *
                                   (endpoint - origin).Length();
                    if (Math.Abs(distance) <= Math.Abs(minDistance))
                    {
                        minDistance = distance;
                        param       = t[i];
                    }
                }
            }

            if (param >= 0 && param <= 1)
            {
                return(new SignedDistance(minDistance, 0));
            }
            if (param < .5)
            {
                return(new SignedDistance(minDistance, Math.Abs(Vector2.Dot(ab.Normalize(), qa.Normalize()))));
            }
            return(new SignedDistance(minDistance,
                                      Math.Abs(Vector2.Dot((_p[2] - _p[1]).Normalize(), (_p[2] - origin).Normalize()))));
        }
コード例 #2
0
        public override SignedDistance SignedDistance(Vector2 origin, ref double param)
        {
            var aq = origin - _p[0];
            var ab = _p[1] - _p[0];

            param = Vector2.Dot(aq, ab) / Vector2.Dot(ab, ab);
            var eq = _p[param > 0.5 ? 1 : 0] - origin;
            var endpointDistance = eq.Length();

            if (param > 0 && param < 1)
            {
                var orthoDistance = Vector2.Dot(ab.GetOrthonormal(), aq);
                if (Math.Abs(orthoDistance) < endpointDistance)
                {
                    return(new SignedDistance(orthoDistance, 0));
                }
            }

            return(new SignedDistance(Arithmetic.NonZeroSign(Vector2.Cross(aq, ab)) * endpointDistance,
                                      Math.Abs(Vector2.Dot(ab.Normalize(), eq.Normalize()))));
        }
コード例 #3
0
        public override SignedDistance SignedDistance(Vector2 origin, ref double param)
        {
            var qa  = _p[0] - origin;
            var ab  = _p[1] - _p[0];
            var br  = _p[2] - _p[1] - ab;
            var as_ = _p[3] - _p[2] - (_p[2] - _p[1]) - br;

            var epDir       = Direction(0);
            var minDistance = Arithmetic.NonZeroSign(Vector2.Cross(epDir, qa)) * qa.Length(); // distance from A

            param = -Vector2.Dot(qa, epDir) / Vector2.Dot(epDir, epDir);
            {
                epDir = Direction(1);
                var distance =
                    Arithmetic.NonZeroSign(Vector2.Cross(epDir, _p[3] - origin)) *
                    (_p[3] - origin).Length(); // distance from B
                if (Math.Abs(distance) < Math.Abs(minDistance))
                {
                    minDistance = distance;
                    param       = Vector2.Dot(origin + epDir - _p[3], epDir) / Vector2.Dot(epDir, epDir);
                }
            }
            // Iterative minimum distance search
            for (var i = 0; i <= MsdfgenCubicSearchStarts; ++i)
            {
                var t = (double)i / MsdfgenCubicSearchStarts;
                for (var step = 0;; ++step)
                {
                    var qpt      = Point(t) - origin;
                    var distance = Arithmetic.NonZeroSign(Vector2.Cross(Direction(t), qpt)) * qpt.Length();
                    if (Math.Abs(distance) < Math.Abs(minDistance))
                    {
                        minDistance = distance;
                        param       = t;
                    }

                    if (step == MsdfgenCubicSearchSteps)
                    {
                        break;
                    }
                    // Improve t
                    var d1 = 3 * as_ * t * t + 6 * br * t + 3 * ab;
                    var d2 = 6 * as_ * t + 6 * br;
                    t -= Vector2.Dot(qpt, d1) / (Vector2.Dot(d1, d1) + Vector2.Dot(qpt, d2));
                    if (t < 0 || t > 1)
                    {
                        break;
                    }
                }
            }

            if (param >= 0 && param <= 1)
            {
                return(new SignedDistance(minDistance, 0));
            }
            if (param < .5)
            {
                return(new SignedDistance(minDistance, Math.Abs(Vector2.Dot(Direction(0).Normalize(), qa.Normalize()))));
            }
            return(new SignedDistance(minDistance,
                                      Math.Abs(Vector2.Dot(Direction(1).Normalize(), (_p[3] - origin).Normalize()))));
        }