/// <summary> /// Evaluates the inverse complementary error function. /// </summary> /// <param name="p"></param> /// <returns></returns> public static double inverfc(double p) { if (p >= 2.0) { return(-100.0); } if (p <= 0.0) { return(100.0); } double pp = (p < 1.0) ? p : 2.0 - p; double t = Math.Sqrt(-2.0 * Math.Log(pp / 2.0)); double x = -0.70711 * ((2.30753 + t * 0.27061) / (1.0 + t * (0.99229 + t * 0.04481)) - t); for (int j = 0; j < 2; j++) { double err = erfc(x) - pp; x += err / (1.12837916709551257 * Math.Exp(-MathTool.Sqr(x)) - x * err); } return(p < 1.0 ? x : -x); }
public static Vector3D SphericalInterpolation(Vector3D start, Vector3D end, double p) { double cosΩ = MathTool.Clamp(Vector3D.DotProduct(start, end) / (start.Length * end.Length), -1.0, 1.0); double Ω = Math.Acos(cosΩ); return(SphericalInterpolation(start, end, Ω, Math.Sin(Ω), p)); }
public static double[] FromAHSVInterpolation(double[] minimum, double p, double[] maximum) { double[] b = minimum; double[] e = maximum; double b1 = b[1] >= 0 ? b[1] : e[1]; double e1 = e[1] >= 0 ? e[1] : b[1]; if (b1 >= 0 && e1 >= 0 && System.Math.Abs(e1 - b1) > 180) { if (e1 > b1) { b1 += 360; } else { e1 += 360; } } p = MathTool.Clamp(p, 0.0, 1.0); double[] ahsv = { b[0] * (1.0 - p) + e[0] * p, b1 *(1.0 - p) + e1 * p, b[2] * (1.0 - p) + e[2] * p, b[3] * (1.0 - p) + e[3] * p }; return(ahsv); }
public static Color FromARGBInterpolation(Color min, double p, Color max) { double q = MathTool.Clamp(p, 0.0, 1.0); #if false double amin = min.A / 255.0; double rmin = amin > 0 ? min.R * amin : min.R; double gmin = amin > 0 ? min.G * amin : min.G; double bmin = amin > 0 ? min.B * amin : min.B; double amax = max.A / 255.0; double rmax = amax > 0 ? max.R * amax : max.R; double gmax = amax > 0 ? max.G * amax : max.G; double bmax = amax > 0 ? max.B * amax : max.B; double a = amin * (1.0 - q) + amax * q; double r = (rmin * (1.0 - q) + rmax * q) / a; double g = (gmin * (1.0 - q) + gmax * q) / a; double b = (bmin * (1.0 - q) + bmax * q) / a; return(Color.FromArgb((byte)(a * 255.0), (byte)r, (byte)g, (byte)b)); #else double a = min.A * (1.0 - q) + max.A * q; double r = min.R * (1.0 - q) + max.R * q; double g = min.G * (1.0 - q) + max.G * q; double b = min.B * (1.0 - q) + max.B * q; return(Color.FromArgb((byte)a, (byte)r, (byte)g, (byte)b)); #endif }
public static void Clear(this WriteableBitmap bitmap, Color color, Rect rect) { int pixelRight = Math.Max(bitmap.PixelWidth - 1, 0); int pixelBottom = Math.Max(bitmap.PixelHeight - 1, 0); int left = (int)MathTool.Clamp(Math.Floor(rect.Left), 0.0, pixelRight); int right = (int)MathTool.Clamp(Math.Floor(rect.Right), 0.0, pixelRight); int top = (int)MathTool.Clamp(Math.Floor(rect.Top), 0.0, pixelBottom); int bottom = (int)MathTool.Clamp(Math.Floor(rect.Left), 0.0, pixelBottom); int stride = bitmap.PixelWidth - (left + right); int a = top * bitmap.PixelWidth + left; int c = (color.A << 24) + (color.R << 16) + (color.G << 8) + color.B; for (int i = top; i <= bottom; ++i) { for (int j = left; j <= right; ++j) { #if SILVERLIGHT bitmap.Pixels[i] = c; #else //bitmap.BackBuffer[i]=c; #endif } a += stride; } }
/// <summary> /// Calculates the moving standard deviation. /// </summary> /// <remarks> /// NaN items in the sequence are ignores. /// </remarks> /// <param name="sequence"></param> /// <param name="period"></param> /// <param name="strict">Require at least period good values</param> /// <returns>The moving standard deviation</returns> public static IEnumerable <double> StandardDeviation(IEnumerable <double> sequence, int period, bool strict = false) { double[] buffer = new double[period]; int cursor = 0; int count = 0; double sum = 0.0; double stddev = double.NaN; for (int i = 0; i < period; ++i) { buffer[i] = double.NaN; } foreach (double value in sequence) { if (!double.IsNaN(value)) { #region update buffer and sum if (double.IsNaN(buffer[cursor])) { count = Math.Min(count + 1, period); } else { sum -= buffer[cursor]; } buffer[cursor] = value; cursor = (cursor + 1) % period; sum += value; #endregion #region update stddev if (count > period || !strict) { double mean = sum / (double)count; double t = 0.0; for (int i = 0; i < period; ++i) { if (!double.IsNaN(buffer[i])) { t += MathTool.Sqr(buffer[i] - mean); } } stddev = Math.Sqrt(t / (double)count); } else { stddev = double.NaN; } #endregion } yield return(stddev); } }
public static List <int> Flatten(int index, int count, Func <int, double> X, Func <int, double> Y, double resolution) { List <int> ret = new List <int>(); Flatten(ret, X, Y, index, count - 1, MathTool.Sqr(resolution)); ret.Add(count - 1); return(ret); }
public static double GreatCircleDistance(Point start, Point end) { double cosφs = Math.Cos(MathTool.Radians(start.Y)); double sinφs = Math.Sin(MathTool.Radians(start.Y)); double sinφf = Math.Sin(MathTool.Radians(end.Y)); double cosφf = Math.Cos(MathTool.Radians(end.Y)); double cosΔλ = Math.Cos(MathTool.Radians(end.X - start.X)); double sinΔλ = Math.Sin(MathTool.Radians(end.X - start.X)); return(Math.Atan2(MathTool.Sqr(cosφf * sinΔλ) + MathTool.Sqr(cosφs * sinφf - sinφs * cosφf * cosΔλ), sinφs * sinφf + cosφs * cosφf * cosΔλ)); }
public static Color Lightened(this Color color, double p) { double[] ahsl = color.AHSL(); if (p < 0.0) { return(FromAHSL(ahsl[0], ahsl[1], ahsl[2], ahsl[3] * (1.0 - MathTool.Clamp(-p, 0.0, 1.0)))); } else { return(FromAHSL(ahsl[0], ahsl[1], ahsl[2], ahsl[3] + MathTool.Clamp(p, 0.0, 1.0) * (1.0 - ahsl[3]))); } }
// 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] }
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); }
private static int clipBezierCurve(Rect rc, Point p0, Point p1, Point p2, Point p3) { #region trivial inclusion and exclusion by axis aligned bounding rectangle double xmin = MathTool.Min(p0.X, p1.X, p2.X, p3.X); if (xmin > rc.Right) { return(-1); } double ymin = MathTool.Min(p0.Y, p1.Y, p2.Y, p3.Y); if (ymin > rc.Bottom) { return(-1); } double xmax = MathTool.Max(p0.X, p1.X, p2.X, p3.X); if (xmax < rc.Left) { return(-1); } double ymax = MathTool.Max(p0.Y, p1.Y, p2.Y, p3.Y); if (ymax < rc.Top) { return(-1); } if (xmin >= rc.Left && ymin <= rc.Bottom && xmax <= rc.Right && ymin >= rc.Top) { return(0); } #endregion double p30x = p3.X - p0.X; double p30y = p3.Y - p0.Y; double s1 = p30x * (p1.Y - p0.Y) - p30y * (p1.X - p0.X); double s2 = p30x * (p2.Y - p0.Y) - p30y * (p2.X - p0.X); if (Math.Sign(s1) == Math.Sign(s2) /* control points are on the same side of the support */) { if (rc.Contains(p0) || rc.Contains(p1) || rc.Contains(p2) || rc.Contains(p3)) { if (rc.Contains(p0) && rc.Contains(p1) && rc.Contains(p2) && rc.Contains(p3)) { return(0); // entire convex hull is contained in bounding rect } return(1); // some points are inside, sone points are outside } Point[] polygon = { p0, p1, p2, p3 }; Func <int, double> X = (i) => polygon[i].X; Func <int, double> Y = (i) => polygon[i].Y; if (GeometryTool.PolygonContains(4, X, Y, new Point(rc.Left, rc.Top)) || GeometryTool.PolygonContains(4, X, Y, new Point(rc.Left, rc.Bottom)) || GeometryTool.PolygonContains(4, X, Y, new Point(rc.Right, rc.Bottom)) || GeometryTool.PolygonContains(4, X, Y, new Point(rc.Right, rc.Top))) { return(1); // rc intersects curve - keep on clipping } return(-1); // rc does not intersect curve } else { // need the convex hull to work out which points to test, but for the moment, just // assume that the whole curve is clipped return(1); } }
public Brent(Func <double, double> function, double xa, double xb, double xc, double tolerance) { const int ITMAX = 100; const double CGOLD = 0.3819660; const double ZEPS = 0.00001;// Double.Epsilon;// *1.0e-3; double a = (xa < xc ? xa : xc); double b = (xa > xc ? xa : xc); double d = 0.0; double e = 0.0; double u; double fu; double v = xb; double fv = function(v); double w = v; double fw = fv; double x = v; double fx = fv; for (int i = 0; i < ITMAX; ++i) { double xm = 0.5 * (a + b); double tol1 = tolerance * Math.Abs(x) + ZEPS; double tol2 = 2.0 * tol1; if (Math.Abs(x - xm) <= (tol2 - 0.5 * (b - a))) { xmin = x; fmin = fx; return; } if (Math.Abs(e) > tol1) { double r = (x - w) * (fx - fv); double q = (x - v) * (fx - fw); double p = (x - v) * q - (x - w) * r; q = 2.0 * (q - r); if (q > 0.0) { p = -p; } q = Math.Abs(q); double etemp = e; e = d; if (Math.Abs(p) >= Math.Abs(0.5 * q * etemp) || p <= q * (a - x) || p >= q * (b - x)) { d = CGOLD * (e = (x >= xm ? a - x : b - x)); } else { d = p / q; u = x + d; if (u - a < tol2 || b - u < tol2) { d = MathTool.CopySign(tol1, xm - x); } } } else { d = CGOLD * (e = (x >= xm ? a - x : b - x)); } u = (Math.Abs(d) >= tol1 ? x + d : x + MathTool.CopySign(tol1, d)); fu = function(u); if (fu <= fx) { if (u >= x) { a = x; } else { b = x; } shift(ref v, ref w, ref x, u); shift(ref fv, ref fw, ref fx, fu); } else { if (u < x) { a = u; } else { b = u; } if (fu <= fw || w == x) { v = w; w = u; fv = fw; fw = fu; } else { if (fu <= fv || v == x || v == w) { v = u; fv = fu; } } } } //throw("Too many iterations in brent"); xmin = double.NaN; fmin = double.NaN; }
private static double Distance2(Point p0, Point p1) { return(MathTool.Sqr(p1.X - p0.X) + MathTool.Sqr(p1.Y - p0.Y)); }
public static double[] Minimise(Func <double[], double> function, double[] pp, double tolerance) { int n = pp.Length; int ITMAX = 200; double TINY = 1.0e-25; double[,] ximat = new double[n, n]; for (int i = 0; i < n; i++) { ximat[i, i] = 1.0; } double[] p = new double[n]; double[] pt = new double[n]; double[] ptt = new double[n]; double[] xi = new double[n]; double fret = function(p); for (int i = 0; i < n; ++i) { p[i] = pp[i]; pt[i] = p[i]; } for (int i = 0; ; ++i) { double fp = fret; double fptt; int ibig = 0; double del = 0.0; for (int j = 0; j < n; ++j) { for (int k = 0; k < n; ++k) { xi[k] = ximat[k, j]; } fptt = fret; fret = linmin(function, p, xi); if (fptt - fret > del) { del = fptt - fret; ibig = j + 1; } } if (2.0 * (fp - fret) <= tolerance * (Math.Abs(fp) + Math.Abs(fret)) + TINY) { return(p); } if (i == ITMAX) { return(null); //throw ("powell exceeding maximum iterations."); } for (int j = 0; j < n; j++) { ptt[j] = 2.0 * p[j] - pt[j]; xi[j] = p[j] - pt[j]; pt[j] = p[j]; } fptt = function(ptt); if (fptt < fp) { double t = 2.0 * (fp - 2.0 * fret + fptt) * MathTool.Sqr(fp - fret - del) - del * MathTool.Sqr(fp - fptt); if (t < 0.0) { fret = linmin(function, p, xi); for (int j = 0; j < n; j++) { ximat[j, ibig - 1] = ximat[j, n - 1]; ximat[j, n - 1] = xi[j]; } } } } }
private static IList <int> Flatten(IList <int> result, Func <int, double> X, Func <int, double> Y, int b, int e, double E2) { if (b >= e) { if (b == e) { result.Add(b); } return(result); } double Xb = X(b); double Yb = Y(b); double Xe = X(e); double Ye = Y(e); int si = -1; double se = E2; double L = MathTool.Hypot2(Xe - Xb, Ye - Yb); if (L == 0.0) { for (int i = b + 1; i < e; ++i) { double Xi = X(i); double Yi = Y(i); if (!double.IsNaN(Xi) && !double.IsNaN(Yi)) { double err = MathTool.Hypot2(Xe - X(i), Ye - Y(i)); if (err >= se) { se = err; si = i; } } } } else { double vx = Xe - Xb; double vy = Ye - Yb; for (int i = b + 1; i < e; ++i) { double Xi = X(i); double Yi = Y(i); if (!double.IsNaN(Xi) && !double.IsNaN(Yi)) { double err = double.NaN; double wx = Xi - Xb; double wy = Yi - Yb; double c1 = vx * wx + vy * wy; if (c1 <= 0.0) { err = MathTool.Hypot2(Xb - Xi, Yb - Yi); } else { double c2 = vx * vx + vy * vy; if (c2 <= c1) { err = MathTool.Hypot2(Xe - Xi, Ye - Yi); } else { double p = c1 / c2; err = MathTool.Hypot2(Xb + p * vx - Xi, Yb + p * vy - Yi); } } if (err >= se) { se = err; si = i; } } } } if (si == -1) { result.Add(b); // result.Add(e); } else { // the error point cannot be the first or last point - that wouldn't make any sense Debug.Assert(si != b); Debug.Assert(si != e); Flatten(result, X, Y, b, si, E2); // big error - flatten from b to si Flatten(result, X, Y, si, e, E2); // big error - flatten from si+1 to e } return(result); }
public static double[] Bracket(Func <double, double> function, double a, double b) { double xa; double xb; double xc; double fa; double fb; double fc; double GLIMIT = 100.0; double TINY = 1.0e-20; xa = a; fa = function(xa); xb = b; fb = function(xb); if (fb > fa) { swap(ref xa, ref xb); swap(ref fa, ref fb); } xc = xb + MathTool.PHI * (xb - xa); fc = function(xc); double fu; while (fb > fc) { double r = (xb - xa) * (fb - fc); double q = (xb - xc) * (fb - fa); double u = xb - ((xb - xc) * q - (xb - xa) * r) / (2.0 * MathTool.CopySign(Math.Max(Math.Abs(q - r), TINY), q - r)); double ulim = xb + GLIMIT * (xc - xb); if ((xb - u) * (u - xc) > 0.0) { fu = function(u); if (fu < fc) { xa = xb; fa = fb; xb = u; fb = fu; return(new double[] { xa, fa, xb, fb, xc, fc }); } if (fu > fb) { xc = u; fc = fu; return(new double[] { xa, fa, xb, fb, xc, fc }); } u = xc + MathTool.PHI * (xc - xb); fu = function(u); } else { if ((xc - u) * (u - ulim) > 0.0) { fu = function(u); if (fu < fc) { shift(ref xb, ref xc, ref u, u + MathTool.PHI * (u - xc)); shift(ref fb, ref fc, ref fu, function(u)); } } else { if ((u - ulim) * (ulim - xc) >= 0.0) { u = ulim; fu = function(u); } else { u = xc + MathTool.PHI * (xc - xb); fu = function(u); } } } shift(ref xa, ref xb, ref xc, u); shift(ref fa, ref fb, ref fc, fu); } return(new double[] { xa, fa, xb, fb, xc, fc }); }
/// <summary> /// Creates coefficients for the polynomial least squares fit y=a0+a1x+a2x^2.. /// </summary> /// <param name="n">Number of items in the categorySeries.</param> /// <param name="k">Polynomial order.</param> /// <param name="x">Delegate which returns the nth x value.</param> /// <param name="y">Delegate which returns the nth y value.</param> /// <remarks> /// If either of the x or y for a given point are NaN, the point is not taken /// into account for the fitting operation. Infinite values are valid, but /// are likely to result in significant numerical instability. /// <para> /// Weisstein, Eric W. "Least Squares Fitting--Polynomial." From MathWorld--A Wolfram Web Resource. /// http://mathworld.wolfram.com/LeastSquaresFittingPolynomial.html /// </para> /// </remarks> /// <returns>Polynomial coefficients a0, a1, .. ak as an array of doubles or null if no solution.</returns> public static double[] PolynomialFit(int n, int k, Func <int, double> x, Func <int, double> y) { double[] ps = new double[1 + 2 * k]; double[,] A = new double[k + 1, k + 1]; double[] B = new double[k + 1]; int N = 0; for (int i = 0; i < n; ++i) { double s = 1.0; double xi = x(i); if (!double.IsNaN(xi)) { for (int p = 0; p < ps.Length; ++p) { ps[p] += s; s *= xi; } if (!double.IsNaN(y(i))) { ++N; } } } if (N < k) { return(null); } for (int i = 0; i <= k; ++i) { for (int j = 0; j <= k; ++j) { A[i, j] = ps[i + j]; } } for (int i = 0; i < n; ++i) { double xi = x(i); if (!double.IsNaN(xi)) { for (int j = 0; j <= k; ++j) { double yi = y(i); if (!double.IsNaN(yi)) { B[j] += (Math.Pow(xi, j) * yi); } } } } return(MathTool.Solve(A, B) ? B : null); }