private LinearInterpolationSurface(double[] values, IPlotFunction[] functions, LinearInterpolationSurfaceProjection projection)
        {
            int n = values.Length;

            if (functions.Length != n)
            {
                throw new ArgumentException();
            }

            List<Tuple<double, IPlotFunction>> pairs = new List<Tuple<double, IPlotFunction>>();
            for (int i = 0; i < n; i++)
            {
                pairs.Add(Tuple.Create<double, IPlotFunction>(values[i], functions[i]));
            }
            pairs.Sort((p1, p2) => p1.Item1.CompareTo(p2.Item1));

            for (int i = 0; i < n; i++)
            {
                values[i] = pairs[i].Item1;
                functions[i] = pairs[i].Item2;
            }

            Count = n;
            Values = new ImmutableList<double>(values);
            Functions = new ImmutableList<IPlotFunction>(functions);
            Projection = projection;
        }
 public LinearInterpolationSurface Add(double value, IPlotFunction function)
 {
     return new LinearInterpolationSurface(Values.Concat(new double[] { value }), Functions.Concat(new IPlotFunction[] { function }), Projection);
 }
 public IEnumerable<double> CreatePoints(IPlotFunction function)
 {
     return points;
 }
 public IEnumerable<double> CreatePoints(IPlotFunction function)
 {
     return generator.CreatePoints(function);
 }
            public IEnumerable<double> CreatePoints(IPlotFunction function)
            {
                if (function == null)
                {
                    throw new ArgumentNullException();
                }

                List<double> points = new List<double>(FunctionPlotSegment.CreatePoints(a, b, n));
                List<double> values = new List<double>();
                foreach (double x in points)
                {
                    values.Add(function.Value(x));
                }

                List<double> points2 = new List<double>();

                // Always keep the left-most point.
                points2.Add(a);
                //yield return a;

                int i0 = 0;
                while (i0 < n - 1)
                {
                    // Find the largest span of points such that deviations in the y-direction between the linear interpolation
                    // and the true function values of intermediate points are no more than the tolerance.

                    // Currently using this left end-point.
                    double xl = points[i0];
                    double yl = values[i0];

                    // Perform at least one step.
                    int i = i0 + 1;
                    while (i < n - 1)
                    {
                        // Test with this right end-point one more step ahead.
                        double xr = points[i + 1];
                        double yr = values[i + 1];

                        // And then recheck all points in the range between these points.
                        bool stop = false;
                        for (int j = i0 + 1; j < i + 1; j++)
                        {
                            double x = points[j];

                            // The true value.
                            double y0 = values[j];

                            // The interpolated value.
                            double lambda = (xr - x) / (xr - xl);
                            double y = (1.0 - lambda) * yr + lambda * yl;

                            if (Math.Abs(y - y0) > tolerance || double.IsNaN(y) || double.IsNaN(y0))
                            {
                                // Deviation too large. Stop the expansion of the range.
                                stop = true;
                                break;
                            }
                        }

                        if (stop)
                        {
                            break;
                        }

                        // We've confirmed that the range can be expanded by one more point.
                        i++;
                    }

                    points2.Add(points[i]);
                    //yield return points[i];

                    // Use this point as the next left end-point.
                    i0 = i;
                }

                return points2;
            }
 public FunctionPlot(IPlotFunction function, params FunctionPlotSegment[] segments)
     : this(function, (IEnumerable<FunctionPlotSegment>)segments)
 {
 }
 public FunctionPlot(IPlotFunction function, IEnumerable<FunctionPlotSegment> segments, params IFunctionPlotStyle[] styles)
 {
     Function = function;
     Segments = new ImmutableList<FunctionPlotSegment>(segments);
     Properties = new PlotProperties(styles);
 }
 public FunctionPlot(IPlotFunction function, double[] points, params IFunctionPlotStyle[] styles)
     : this(function, new FunctionPlotSegment[] { new FunctionPlotSegment(points) }, styles)
 {
 }
 public FunctionPlot(IPlotFunction function, double a, double b, int n, double tolerance, params IFunctionPlotStyle[] styles)
     : this(function, new FunctionPlotSegment[] { new FunctionPlotSegment(a, b, n, tolerance) }, styles)
 {
 }
 public FunctionPlot(IPlotFunction function, double a, double b, params IFunctionPlotStyle[] styles)
     : this(function, a, b, 1000, styles)
 {
 }
 public SmoothFunctionPlot(IPlotFunction function, double a, double b, int n, params IFunctionPlotStyle[] styles)
     : this(function, new FunctionPlotSegment[] { new FunctionPlotSegment(a, b, n) }, styles)
 {
 }
 public static PlotFunction Create(IPlotFunction f)
 {
     return Create(x => f.Value(x));
 }