Regarding the interpolation of closed curves: you can also use periodic Bezier curves, they were considered at our seminar. There, the result is more traditional, in the form of a trigonometric polynomial, that is, the usual function of a real argument. In some cases, this may be more convenient than discrete splines (which are specified by the function of an integer argument).
/// <summary> /// Q- 1- , /// http://www.math.spbu.ru/ru/mmeh/AspDok/pub/2010/Chashnikov.pdf ( 6). /// </summary> /// <param name="n"> .</param> /// <param name="m"> .</param> /// <returns> Q- 1- .</returns> private static double[] CalculateQSpline(int n, int m) { var N = n * m; var qSpline = new double[N]; for (var j = 0; j < N; ++j) { if (j >= 0 && j <= n - 1) { qSpline[j] = (1.0 * n - j) / n; } if (j >= n && j <= N - n) { qSpline[j] = 0; } if (j >= N - n + 1 && j <= N - 1) { qSpline[j] = (1.0 * j - N + n) / n; } } return qSpline; }
/// <summary> /// , /// http://www.math.spbu.ru/ru/mmeh/AspDok/pub/2010/Chashnikov.pdf ( 7). /// </summary> /// <param name="vectors"> .</param> /// <param name="qSpline"> B- 1- .</param> /// <param name="r"> .</param> /// <param name="n"> .</param> /// <param name="m"> .</param> /// <returns></returns> private static Vector2[] CalculateSSpline(Vector2[] aVectors, double[] aQSpline, int r, int n, int m) { var N = n * m; var sSpline = new Vector2[r + 1][]; for (var i = 1; i <= r; ++i) { sSpline[i] = new Vector2[N]; } for (var j = 0; j < N; ++j) { sSpline[1][j] = new Vector2(0, 0); for (var p = 0; p < m; ++p) { sSpline[1][j] += aVectors[p] * aQSpline[GetPositiveIndex(j - p * n, N)]; } } for (var v = 2; v <= r; ++v) { for (var j = 0; j < N; ++j) { sSpline[v][j] = new Vector2(0, 0); for (var k = 0; k < N; ++k) { sSpline[v][j] += aQSpline[k] * sSpline[v - 1][GetPositiveIndex(j - k, N)]; } sSpline[v][j] /= n; } } return sSpline[r]; }
/// <summary> /// 2- . /// </summary> public class Vector2 { public double X; public double Y; /// <summary> /// -. /// </summary> public Vector2() { this.X = 0; this.Y = 0; } /// <summary> /// . . /// </summary> /// <param name="x"> .</param> /// <param name="y"> Y.</param> public Vector2(double x, double y) { this.X = x; this.Y = y; } /// <summary> /// . . /// </summary> /// <param name="v"> .</param> public Vector2(Vector2 v) { X = vX; Y = vY; } /// <summary> /// . /// </summary> /// <param name="a"> .</param> /// <param name="b"> .</param> /// <returns> .</returns> public static Vector2 operator +(Vector2 a, Vector2 b) { return new Vector2(aX + bX, aY + bY); } /// <summary> /// . /// </summary> /// <param name="a"> .</param> /// <param name="b"> .</param> /// <returns> .</returns> public static Vector2 operator -(Vector2 a, Vector2 b) { return new Vector2(aX - bX, aY - bY); } /// <summary> /// . /// </summary> /// <param name="a"> .</param> /// <returns> .</returns> public static Vector2 operator -(Vector2 a) { return new Vector2(-aX, -aY); } /// <summary> /// . /// </summary> /// <param name="a"> .</param> /// <param name="d">.</param> /// <returns> .</returns> public static Vector2 operator *(Vector2 a, double d) { return new Vector2(aX * d, aY * d); } /// <summary> /// . /// </summary> /// <param name="d">.</param> /// <param name="a"> .</param> /// <returns> .</returns> public static Vector2 operator *(double d, Vector2 a) { return a * d; } /// <summary> /// . /// </summary> /// <param name="a"> .</param> /// <param name="f">.</param> /// <returns> .</returns> public static Vector2 operator *(Vector2 a, float f) { return a * (double)f; } /// <summary> /// . /// </summary> /// <param name="f">.</param> /// <param name="a"> .</param> /// <returns> .</returns> public static Vector2 operator *(float f, Vector2 a) { return a * (double)f; } /// <summary> /// . /// </summary> /// <param name="a"> .</param> /// <param name="d">.</param> /// <returns> .</returns> public static Vector2 operator /(Vector2 a, double d) { return new Vector2(aX / d, aY / d); } /// <summary> /// . /// </summary> /// <param name="a"> .</param> /// <param name="f">.</param> /// <returns> .</returns> public static Vector2 operator /(Vector2 a, float f) { return a / (double)f; } }
/// <summary> /// . /// </summary> /// <param name="j"> .</param> /// <param name="N"> .</param> /// <returns> .</returns> private static int GetPositiveIndex(int j, int N) { if (j >= 0) { return j % N; } return N - 1 + ((j + 1) % N); }
/// <summary> /// , . /// http://dha.spb.ru/PDF/discreteSplines.pdf ( 6 7). /// </summary> /// <param name="aPoints"> .</param> /// <param name="r"> .</param> /// <param name="n"> .</param> /// <param name="m"> .</param> /// <returns> .</returns> private static Vector2[] RecalculateVectors(Vector2[] aPoints, int r, int n, int m) { var N = n * m; // . var tr = new double[m]; tr[0] = 1; for (var k = 1; k < m; ++k) { for (var q = 0; q < n; ++q) { tr[k] += Math.Pow(2 * n * Math.Sin((Math.PI * (q * m + k)) / N), -2 * r); } tr[k] *= Math.Pow(2 * Math.Sin((Math.PI * k) / m), 2 * r); } // . var zre = new Vector2[m]; var zim = new Vector2[m]; for (var j = 0; j < m; ++j) { zre[j] = new Vector2(0, 0); zim[j] = new Vector2(0, 0); for (var k = 0; k < m; ++k) { zre[j] += aPoints[k] * Math.Cos((-2 * Math.PI * j * k) / m); zim[j] += aPoints[k] * Math.Sin((-2 * Math.PI * j * k) / m); } } // . var result = new Vector2[m]; for (var p = 0; p < m; ++p) { result[p] = new Vector2(0, 0); for (var k = 0; k < m; ++k) { var d = (zre[k] * Math.Cos((2 * Math.PI * k * p) / m)) - (zim[k] * Math.Sin((2 * Math.PI * k * p) / m)); d *= 1.0 / tr[k]; result[p] += d; } result[p] /= m; } return result; }
/// <summary> /// N- . /// </summary> /// <param name="aPoints"> ( ). 2- .</param> /// <param name="r"> .</param> /// <param name="n"> .</param> /// <param name="aIsIncludeOriginalPoints">True - , false - .</param> /// <returns></returns> public static Vector2[] Calculate(Vector2[] aPoints, int r, int n = 5, bool aIsIncludeOriginalPoints = true) { if (aPoints == null) { throw new ArgumentNullException("aPoints"); } if (aPoints.Length <= 2) { throw new ArgumentException(" > 2."); } if (r <= 0) { throw new ArgumentException(" > 0."); } if (n < 1) { throw new ArgumentException(" >= 1."); } var m = aPoints.Length; var N = n * m; Vector2[] vectors; if (aIsIncludeOriginalPoints) { vectors = RecalculateVectors(aPoints, r, n, m); } else { vectors = new Vector2[m]; aPoints.CopyTo(vectors, 0); } var qSpline = CalculateQSpline(n, m); var resultPoints = CalculateSSpline(vectors, qSpline, r, n, m); return resultPoints; }
Source: https://habr.com/ru/post/309210/
All Articles