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 static PlotFunction Create(IPlotFunction f) { return Create(x => f.Value(x)); }