// outputs (p) cp cp p cp cp p cp cp p..
        public static void SplinePoints(IList <Point> ret, int count, Func <int, double> x, Func <int, double> y)
        {
            // flatten at resolution

            var    ea  = new Point(x(1) - x(0), y(1) - y(0));
            double eam = MathTool.Hypot(ea.X, ea.Y);

            ret.Add(new Point(x(0), y(0))); // output point[0]
            ret.Add(new Point(x(0), y(0))); // output a bogus control point

            for (int i = 2; i < count; ++i)
            {
                var    eb  = new Point(x(i) - x(i - 1), y(i) - y(i - 1));
                double ebm = MathTool.Hypot(eb.X, eb.Y);

                double dot = (ea.X * eb.X + ea.Y * eb.Y) / (eam * ebm);
                //double tension = 0.35*Math.Exp(0.5 * (dot + 1.0))/(Math.resolution-1);
                double tension = 0.5 * (dot + 1.0);
                tension = 1.0 + tension * (Math.E - 1.0);
                tension = 0.5 * Math.Log(tension);

                var d = new Point(x(i) - x(i - 2), y(i) - y(i - 2));

                double dm = MathTool.Hypot(d.X, d.Y);

                if (dm == 0)
                {
                    dm = double.PositiveInfinity;
                }

                ret.Add(new Point(x(i - 1) - eam * tension * d.X / dm, y(i - 1) - eam * tension * d.Y / dm));
                ret.Add(new Point(x(i - 1), y(i - 1)));
                ret.Add(new Point(x(i - 1) + ebm * tension * d.X / dm, y(i - 1) + ebm * tension * d.Y / dm));

                ea  = eb;
                eam = ebm;
            }

            ret.Add(new Point(x(count - 1), y(count - 1))); // output a bogus control point
            ret.Add(new Point(x(count - 1), y(count - 1))); // output point[0]
        }
Пример #2
0
        public static IList <int> StripCoincident(int count, Func <int, double> x, Func <int, double> y, double resolution)
        {
            IList <int> ret = new List <int>();

            for (int i = 0; i < count;)
            {
                double cx = x(i);
                double cy = y(i);

                int j = i;
                ret.Add(j);

                for (++i; i < count && MathTool.Hypot(x(j) - cx, y(j) - cy) < resolution; ++i)
                {
                    cx = (cx * (double)(i - j) + x(i)) / (double)(i - j + 1);
                    cy = (cy * (double)(i - j) + y(i)) / (double)(i - j + 1);
                }
            }

            return(ret);
        }
        /// <summary>
        /// Smooth a line into a PathFigure of quadratic and cubic bezier splines.
        /// </summary>
        /// <param name="count">Number of equator in line.</param>
        /// <param name="x">x coordinate of ith point.</param>
        /// <param name="y">y coordinate of ith point.</param>
        /// <returns>Smooth line.</returns>
        public static PathFigure Smooth(int count, Func <int, double> x, Func <int, double> y)
        {
            var pathFigure = new PathFigure()
            {
                StartPoint = new Point(x(0), y(0))
            };

            int n = count - 1;

            Point pa;
            Point pb = new Point(x(0), y(0));
            Point pc = new Point(x(0 + 1), y(0 + 1));
            Point pd = new Point(x(0 + 2), y(0 + 2));

            Point  eab;
            double mab;

            Point  ebc = new Point(pc.X - pb.X, pc.Y - pb.Y);
            double mbc = MathTool.Hypot(ebc.X, ebc.Y);

            Point  ecd = new Point(pd.X - pc.X, pd.Y - pc.Y);
            double mcd = MathTool.Hypot(ecd.X, ecd.Y);

            Point  tc;
            double sc;

            double alpha = 0.15;
            double beta  = 0.45;

            {
                // first quadratic patch

                tc = new Point(pd.X - pb.X, pd.Y - pb.Y); { double m = MathTool.Hypot(tc.X, tc.Y); tc.X /= m; tc.Y /= m; }
                sc = 0.5 + (ebc.X * ecd.X + ebc.Y * ecd.Y) / (2.0 * mbc * mcd);

                QuadraticBezierSegment segment = new QuadraticBezierSegment()
                {
                    Point1 = new Point(pc.X - tc.X * (alpha + beta * sc) * mbc, pc.Y - tc.Y * (alpha + beta * sc) * mbc),
                    Point2 = pc
                };

                if (double.IsNaN(segment.Point1.X) || double.IsNaN(segment.Point1.Y))
                {
                }

                if (double.IsNaN(segment.Point2.X) || double.IsNaN(segment.Point2.Y))
                {
                }

                pathFigure.Segments.Add(segment);
            }

            for (int i = 1; i < n - 1; ++i)
            {
                // intermediate cubic patches

                pa = pb;
                pb = pc;
                pc = pd;
                pd = new Point(x(i + 2), y(i + 2));

                eab = ebc;
                mab = mbc;

                ebc = ecd;
                mbc = mcd;

                ecd = new Point(pd.X - pc.X, pd.Y - pc.Y);
                mcd = MathTool.Hypot(ecd.X, ecd.Y);

                Point  tb = tc;
                double sb = sc;

                tc = new Point(pd.X - pb.X, pd.Y - pb.Y); { double m = MathTool.Hypot(tc.X, tc.Y); tc.X /= m; tc.Y /= m; }
                sc = 0.5 + (ebc.X * ecd.X + ebc.Y * ecd.Y) / (2.0 * mbc * mcd);

                BezierSegment segment = new BezierSegment()
                {
                    Point1 = new Point(pb.X + tb.X * (alpha + beta * sb) * mbc, pb.Y + tb.Y * (alpha + beta * sb) * mbc),
                    Point2 = new Point(pc.X - tc.X * (alpha + beta * sc) * mbc, pc.Y - tc.Y * (alpha + beta * sc) * mbc),
                    Point3 = pc
                };
                pathFigure.Segments.Add(segment);

                if (double.IsNaN(segment.Point1.X) || double.IsNaN(segment.Point1.Y))
                {
                }

                if (double.IsNaN(segment.Point2.X) || double.IsNaN(segment.Point2.Y))
                {
                }

                if (double.IsNaN(segment.Point3.X) || double.IsNaN(segment.Point3.Y))
                {
                }
            }

            {
                // last quadratic patch

                pa = pb;
                pb = pc;
                pc = pd;
                // pd
                eab = ebc;
                mab = mbc;

                ebc = ecd;
                mbc = mcd;

                Point  tb = tc;
                double sb = sc;

                QuadraticBezierSegment segment = new QuadraticBezierSegment()
                {
                    Point1 = new Point(pb.X + tb.X * (alpha + beta * sb) * mbc, pb.Y + tb.Y * (alpha + beta * sb) * mbc),
                    Point2 = pc
                };
                pathFigure.Segments.Add(segment);


                if (double.IsNaN(segment.Point1.X) || double.IsNaN(segment.Point1.Y))
                {
                }

                if (double.IsNaN(segment.Point2.X) || double.IsNaN(segment.Point2.Y))
                {
                }
            }

            return(pathFigure);
        }