PageRenderTime 39ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/Main/src/DynamicDataDisplay/Common/BezierBuilder.cs

#
C# | 120 lines | 87 code | 15 blank | 18 comment | 12 complexity | c7bf63e199cd9415f49b0a541ab44208 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows;
  6. namespace Microsoft.Research.DynamicDataDisplay.Charts.NewLine
  7. {
  8. // todo check a license
  9. public static class BezierBuilder
  10. {
  11. public static IEnumerable<Point> GetBezierPoints(Point[] points)
  12. {
  13. if (points == null)
  14. throw new ArgumentNullException("points");
  15. Point[] firstControlPoints;
  16. Point[] secondControlPoints;
  17. int n = points.Length - 1;
  18. if (n < 1)
  19. throw new ArgumentException("At least two knot points required", "points");
  20. if (n == 1)
  21. { // Special case: Bezier curve should be a straight line.
  22. firstControlPoints = new Point[1];
  23. // 3P1 = 2P0 + P3
  24. firstControlPoints[0].X = (2 * points[0].X + points[1].X) / 3;
  25. firstControlPoints[0].Y = (2 * points[0].Y + points[1].Y) / 3;
  26. secondControlPoints = new Point[1];
  27. // P2 = 2P1 – P0
  28. secondControlPoints[0].X = 2 *
  29. firstControlPoints[0].X - points[0].X;
  30. secondControlPoints[0].Y = 2 *
  31. firstControlPoints[0].Y - points[0].Y;
  32. return Join(points, firstControlPoints, secondControlPoints);
  33. }
  34. // Calculate first Bezier control points
  35. // Right hand side vector
  36. double[] rhs = new double[n];
  37. // Set right hand side X values
  38. for (int i = 1; i < n - 1; ++i)
  39. rhs[i] = 4 * points[i].X + 2 * points[i + 1].X;
  40. rhs[0] = points[0].X + 2 * points[1].X;
  41. rhs[n - 1] = (8 * points[n - 1].X + points[n].X) / 2.0;
  42. // Get first control points X-values
  43. double[] x = GetFirstControlPoints(rhs);
  44. // Set right hand side Y values
  45. for (int i = 1; i < n - 1; ++i)
  46. rhs[i] = 4 * points[i].Y + 2 * points[i + 1].Y;
  47. rhs[0] = points[0].Y + 2 * points[1].Y;
  48. rhs[n - 1] = (8 * points[n - 1].Y + points[n].Y) / 2.0;
  49. // Get first control points Y-values
  50. double[] y = GetFirstControlPoints(rhs);
  51. // Fill output arrays.
  52. firstControlPoints = new Point[n];
  53. secondControlPoints = new Point[n];
  54. for (int i = 0; i < n; ++i)
  55. {
  56. // First control point
  57. firstControlPoints[i] = new Point(x[i], y[i]);
  58. // Second control point
  59. if (i < n - 1)
  60. secondControlPoints[i] = new Point(2 * points
  61. [i + 1].X - x[i + 1], 2 *
  62. points[i + 1].Y - y[i + 1]);
  63. else
  64. secondControlPoints[i] = new Point((points
  65. [n].X + x[n - 1]) / 2,
  66. (points[n].Y + y[n - 1]) / 2);
  67. }
  68. return Join(points, firstControlPoints, secondControlPoints);
  69. }
  70. private static IEnumerable<Point> Join(Point[] points, Point[] firstControlPoints, Point[] secondControlPoints)
  71. {
  72. var length = firstControlPoints.Length;
  73. for (int i = 0; i < length; i++)
  74. {
  75. yield return points[i];
  76. yield return firstControlPoints[i];
  77. yield return secondControlPoints[i];
  78. }
  79. yield return points[length];
  80. }
  81. /// <summary>
  82. /// Solves a tridiagonal system for one of coordinates (x or y)
  83. /// of first Bezier control points.
  84. /// </summary>
  85. /// <param name="rhs">Right hand side vector.</param>
  86. /// <returns>Solution vector.</returns>
  87. private static double[] GetFirstControlPoints(double[] rhs)
  88. {
  89. int n = rhs.Length;
  90. double[] x = new double[n]; // Solution vector.
  91. double[] tmp = new double[n]; // Temp workspace.
  92. double b = 2.0;
  93. x[0] = rhs[0] / b;
  94. for (int i = 1; i < n; i++) // Decomposition and forward substitution.
  95. {
  96. tmp[i] = 1 / b;
  97. b = (i < n - 1 ? 4.0 : 3.5) - tmp[i];
  98. x[i] = (rhs[i] - x[i - 1]) / b;
  99. }
  100. for (int i = 1; i < n; i++)
  101. x[n - i - 1] -= tmp[n - i] * x[n - i]; // Backsubstitution.
  102. return x;
  103. }
  104. }
  105. }