예제 #1
0
        private static FloatRgb Mix(FloatRgb a, FloatRgb b, double weight)
        {
            var output = new FloatRgb
            {
                R = Arithmetic.Mix(a.R, b.R, weight),
                G = Arithmetic.Mix(a.G, b.G, weight),
                B = Arithmetic.Mix(a.B, b.B, weight)
            };

            return(output);
        }
예제 #2
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()))));
        }
예제 #3
0
        public static void RenderSdf(Bitmap <float> output, Bitmap <FloatRgb> sdf, double pxRange)
        {
            int w = output.Width, h = output.Height;

            pxRange *= (double)(w + h) / (sdf.Width + sdf.Height);
            for (var y = 0; y < h; ++y)
            {
                for (var x = 0; x < w; ++x)
                {
                    var s = Sample(sdf, new Vector2((x + .5) / w, (y + .5) / h));
                    output[x, y] = DistVal(Arithmetic.Median(s.R, s.G, s.B), pxRange);
                }
            }
        }
예제 #4
0
        private static float Sample(Bitmap <float> bitmap, Vector2 pos)
        {
            int w = bitmap.Width, h = bitmap.Height;
            var x  = pos.X * w - .5;
            var y  = pos.Y * h - .5;
            var l  = (int)Math.Floor(x);
            var b  = (int)Math.Floor(y);
            var r  = l + 1;
            var t  = b + 1;
            var lr = x - l;
            var bt = y - b;

            l = Math.Clamp(l, 0, w - 1);
            r = Math.Clamp(r, 0, w - 1);
            b = Math.Clamp(b, 0, h - 1);
            t = Math.Clamp(t, 0, h - 1);
            return(Arithmetic.Mix(Arithmetic.Mix(bitmap[l, b], bitmap[r, b], lr),
                                  Arithmetic.Mix(bitmap[l, t], bitmap[r, t], lr), bt));
        }
예제 #5
0
        public override Vector2 Direction(double param)
        {
            var tangent = Arithmetic.Mix(Arithmetic.Mix(_p[1] - _p[0], _p[2] - _p[1], param),
                                         Arithmetic.Mix(_p[2] - _p[1], _p[3] - _p[2], param), param);

            if (!tangent)
            {
                if (param == 0)
                {
                    return(_p[2] - _p[0]);
                }
                if (param == 1)
                {
                    return(_p[3] - _p[1]);
                }
            }

            return(tangent);
        }
예제 #6
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()))));
        }
예제 #7
0
 public override void SplitInThirds(out EdgeSegment part1, out EdgeSegment part2, out EdgeSegment part3)
 {
     part1 = new CubicSegment(Color, _p[0], _p[0] == _p[1] ? _p[0] : Arithmetic.Mix(_p[0], _p[1], 1.0 / 3.0),
                              Arithmetic.Mix(Arithmetic.Mix(_p[0], _p[1], 1.0 / 3.0), Arithmetic.Mix(_p[1], _p[2], 1.0 / 3.0),
                                             1.0 / 3.0), Point(1.0 / 3.0));
     part2 = new CubicSegment(Color, Point(1.0 / 3.0),
                              Arithmetic.Mix(
                                  Arithmetic.Mix(Arithmetic.Mix(_p[0], _p[1], 1.0 / 3.0), Arithmetic.Mix(_p[1], _p[2], 1.0 / 3.0),
                                                 1.0 / 3.0),
                                  Arithmetic.Mix(Arithmetic.Mix(_p[1], _p[2], 1.0 / 3.0), Arithmetic.Mix(_p[2], _p[3], 1.0 / 3.0),
                                                 1.0 / 3.0), 2.0 / 3.0),
                              Arithmetic.Mix(
                                  Arithmetic.Mix(Arithmetic.Mix(_p[0], _p[1], 2.0 / 3.0), Arithmetic.Mix(_p[1], _p[2], 2.0 / 3.0),
                                                 2.0 / 3.0),
                                  Arithmetic.Mix(Arithmetic.Mix(_p[1], _p[2], 2.0 / 3.0), Arithmetic.Mix(_p[2], _p[3], 2.0 / 3.0),
                                                 2.0 / 3.0), 1.0 / 3.0),
                              Point(2.0 / 3.0));
     part3 = new CubicSegment(Color, Point(2.0 / 3.0),
                              Arithmetic.Mix(Arithmetic.Mix(_p[1], _p[2], 2.0 / 3.0), Arithmetic.Mix(_p[2], _p[3], 2.0 / 3.0),
                                             2.0 / 3.0),
                              _p[2] == _p[3] ? _p[3] : Arithmetic.Mix(_p[2], _p[3], 2.0 / 3.0), _p[3]);
 }
예제 #8
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()))));
        }
예제 #9
0
 public override void SplitInThirds(out EdgeSegment part1, out EdgeSegment part2, out EdgeSegment part3)
 {
     part1 = new QuadraticSegment(Color, _p[0], Arithmetic.Mix(_p[0], _p[1], 1.0 / 3.0), Point(1.0 / 3.0));
     part2 = new QuadraticSegment(Color, Point(1.0 / 3.0),
                                  Arithmetic.Mix(Arithmetic.Mix(_p[0], _p[1], 5.0 / 9.0), Arithmetic.Mix(_p[1], _p[2], 4.0 / 9.0), 0.5),
                                  Point(2 / 3.0));
     part3 = new QuadraticSegment(Color, Point(2.0 / 3.0), Arithmetic.Mix(_p[1], _p[2], 2.0 / 3.0), _p[2]);
 }
예제 #10
0
 public override Vector2 Direction(double param)
 {
     return(Arithmetic.Mix(_p[1] - _p[0], _p[2] - _p[1], param));
 }
예제 #11
0
 public override Vector2 Point(double param)
 {
     return(Arithmetic.Mix(Arithmetic.Mix(_p[0], _p[1], param), Arithmetic.Mix(_p[1], _p[2], param), param));
 }