AkimaSpline.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. #include "stdafx.h"
  2. #include "AkimaSpline.h"
  3. #include <cmath>
  4. AkimaSpline::AkimaSpline()
  5. : m_c( NULL )
  6. {
  7. }
  8. AkimaSpline::~AkimaSpline()
  9. {
  10. delete m_c;
  11. }
  12. void AkimaSpline::fit( const std::vector< Point >& curve )
  13. {
  14. if ( m_c )
  15. {
  16. delete[] m_c;
  17. m_c = NULL;
  18. }
  19. int n = (int)curve.size();
  20. if ( n >= 5 )
  21. {
  22. int i;
  23. double* x = new double[ n ];
  24. double* y = new double[ n ];
  25. double* w = new double[ n ];
  26. double* diff = new double[ n ];
  27. double* d = new double[ n ];
  28. if ( !x || !y || !w || !diff || !d )
  29. {
  30. if ( x )
  31. delete[] x;
  32. if ( y )
  33. delete[] y;
  34. if ( w )
  35. delete[] w;
  36. if ( diff )
  37. delete[] diff;
  38. if ( d )
  39. delete[] d;
  40. return;
  41. }
  42. for ( i = 0; i < n; i++ )
  43. {
  44. x[ i ] = (double)curve[ i ].x;
  45. y[ i ] = (double)curve[ i ].y;
  46. }
  47. for ( i = 0; i < n - 1; i++ )
  48. {
  49. double delta = x[ i + 1 ] - x[ i ];
  50. if ( std::fabs( delta ) < 1e-5 )
  51. {
  52. delta = 0.1;
  53. }
  54. diff[ i ] = ( y[ i + 1 ] - y[ i ] ) / delta;
  55. }
  56. for ( i = 0; i < n - 1; i++ )
  57. {
  58. w[ i ] = std::fabs( diff[ i ] - diff[ i - 1 ] );
  59. }
  60. for ( i = 2; i < n - 2; i++ )
  61. {
  62. if ( ( std::fabs( w[ i - 1 ] ) + std::fabs( w[ i + 1 ] ) ) > 1e-5 )
  63. {
  64. d[ i ] = ( w[ i + 1 ] * diff[ i - 1 ] + w[ i - 1 ] * diff[ i ] ) /
  65. ( w[ i + 1 ] + w[ i - 1 ] );
  66. }
  67. else
  68. {
  69. d[ i ] = ( ( x[ i + 1 ] - x[ i ] ) * diff[ i - 1 ] +
  70. ( x[ i ] - x[ i - 1 ] ) * diff[ i ] ) /
  71. ( x[ i + 1 ] - x[ i - 1 ] );
  72. }
  73. }
  74. d[ 0 ] = diff3points( x[ 0 ], x[ 0 ], y[ 0 ],
  75. x[ 1 ], y[ 1 ],
  76. x[ 2 ], y[ 2 ] );
  77. d[ 1 ] = diff3points( x[ 1 ], x[ 0 ], y[ 0 ],
  78. x[ 1 ], y[ 1 ],
  79. x[ 2 ], y[ 2 ] );
  80. d[ n - 2 ] = diff3points( x[ n - 2 ], x[ n - 3 ], y[ n - 3 ],
  81. x[ n - 2 ], y[ n - 2 ],
  82. x[ n - 1 ], y[ n - 1 ] );
  83. d[ n - 1 ] = diff3points( x[ n - 1 ], x[ n - 3 ], y[ n - 3 ],
  84. x[ n - 2 ], y[ n - 2 ],
  85. x[ n - 1 ], y[ n - 1 ] );
  86. hermiteSpline( x, y, d, n );
  87. delete[] d;
  88. delete[] diff;
  89. delete[] w;
  90. delete[] y;
  91. delete[] x;
  92. }
  93. }
  94. std::vector< Point > AkimaSpline::getValues( int steps )
  95. {
  96. std::vector< Point > interp;
  97. if ( m_c )
  98. {
  99. int n = (int)m_c[ 2 ];
  100. double x = m_c[ 3 ];
  101. double r = m_c[ 3 + n - 1 ];
  102. std::vector< Point > pList;
  103. Point oldP;
  104. n *= steps;
  105. double s = ( r - x ) / (double)n;
  106. oldP.x = (int)( x + 0.5 );
  107. oldP.y = (int)( interpolate( x ) + 0.5 );
  108. interp.push_back( oldP );
  109. while ( n-- )
  110. {
  111. Point p;
  112. p.x = (int)( x + 0.5 );
  113. p.y = (int)( interpolate( x ) + 0.5 );
  114. x += s;
  115. if ( ( p.x != oldP.x ) || ( p.y != oldP.y ) )
  116. {
  117. interp.push_back( p );
  118. oldP = p;
  119. }
  120. }
  121. }
  122. return interp;
  123. }
  124. double AkimaSpline::diff3points( double t, double x0, double y0,
  125. double x1, double y1, double x2, double y2 )
  126. {
  127. double a = 0;
  128. double b = 0;
  129. t -= x0;
  130. x1 -= x0;
  131. x2 -= x0;
  132. a = ( y2 - y0 - x2 / x1 * ( y1 - y0 ) ) / ( x2 * x2 - x1 * x2 );
  133. b = ( y1 - y0 - a * x1 * x1 ) / x1;
  134. return 2.0 * a * t + b;
  135. }
  136. void AkimaSpline::hermiteSpline( double* x, double* y, double* d, int n )
  137. {
  138. if ( !x || !y || !d )
  139. {
  140. return;
  141. }
  142. int i = 0;
  143. int size = 3 + n + 4 * ( n - 1 );
  144. double delta = 0.0;
  145. double delta2 = 0.0;
  146. double delta3 = 0.0;
  147. m_c = new double[ size ];
  148. if ( !m_c )
  149. {
  150. return;
  151. }
  152. m_c[ 0 ] = size;
  153. m_c[ 1 ] = 3;
  154. m_c[ 2 ] = n;
  155. for ( i = 0; i < n; i++ )
  156. {
  157. m_c[ 3 + i ] = x[ i ];
  158. }
  159. for ( i = 0; i < n - 1; i++ )
  160. {
  161. delta = x[ i + 1 ] - x[ i ];
  162. delta2 = delta * delta;
  163. delta3 = delta * delta2;
  164. m_c[ 3 + n + 4 * i + 0] = y[ i ];
  165. m_c[ 3 + n + 4 * i + 1] = d[ i ];
  166. m_c[ 3 + n + 4 * i + 2] = ( 3 * ( y[ i + 1 ] - y[ i ] ) -
  167. 2 * d[ i ] * delta -
  168. d[ i + 1 ] * delta ) / delta2;
  169. m_c[ 3 + n + 4 * i + 3] = ( 2 * ( y[ i ] - y[ i + 1 ] ) +
  170. d[ i ] * delta +
  171. d[ i + 1 ] * delta ) / delta3;
  172. }
  173. }
  174. double AkimaSpline::interpolate( double t )
  175. {
  176. int n = (int)m_c[ 2 ];
  177. int l = 3;
  178. int r = 3 + n - 1;
  179. int m = 0;
  180. while ( l != ( r - 1 ) )
  181. {
  182. m = ( l + r ) / 2;
  183. if ( m_c[ m ] >= t )
  184. {
  185. r = m;
  186. }
  187. else
  188. {
  189. l = m;
  190. }
  191. }
  192. t -= m_c[ l ];
  193. m = 3 + n + 4 * ( l - 3 );
  194. return m_c[ m ] + t * ( m_c[ m + 1 ] + t * ( m_c[ m + 2 ] +
  195. t * m_c[ m + 3 ] ) );
  196. }