/branches/v5_9_8_debian/lib/nn/nnai.c

# · C · 431 lines · 307 code · 63 blank · 61 comment · 31 complexity · ac2b119ef1d97506d2065074ad326574 MD5 · raw file

  1. //--------------------------------------------------------------------------
  2. //
  3. // File: nnai.c
  4. //
  5. // Created: 15/11/2002
  6. //
  7. // Author: Pavel Sakov
  8. // CSIRO Marine Research
  9. //
  10. // Purpose: Code for:
  11. // -- Natural Neighbours Array Interpolator
  12. //
  13. // Description: `nnai' is a tructure for conducting
  14. // consequitive Natural Neighbours interpolations on a given
  15. // spatial data set in a given array of points. It allows to
  16. // modify Z coordinate of data in between interpolations.
  17. // `nnai' is the fastest of the three Natural
  18. // Neighbours interpolators in `nn' library.
  19. //
  20. // Revisions: None
  21. //
  22. //--------------------------------------------------------------------------
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <math.h>
  27. #include "nn.h"
  28. #include "delaunay.h"
  29. #include "nan.h"
  30. typedef struct
  31. {
  32. int nvertices;
  33. int * vertices; // vertex indices [nvertices]
  34. double* weights; // vertex weights [nvertices]
  35. } nn_weights;
  36. struct nnai
  37. {
  38. delaunay * d;
  39. double wmin;
  40. double n; // number of output points
  41. double * x; // [n]
  42. double * y; // [n]
  43. nn_weights* weights;
  44. };
  45. void nn_quit( char* format, ... );
  46. void nnpi_calculate_weights( nnpi* nn );
  47. int nnpi_get_nvertices( nnpi* nn );
  48. int* nnpi_get_vertices( nnpi* nn );
  49. double* nnpi_get_weights( nnpi* nn );
  50. void nnpi_normalize_weights( nnpi* nn );
  51. void nnpi_reset( nnpi* nn );
  52. void nnpi_set_point( nnpi* nn, point* p );
  53. // Builds Natural Neighbours array interpolator. This includes calculation of
  54. // weights used in nnai_interpolate().
  55. //
  56. // @param d Delaunay triangulation
  57. // @return Natural Neighbours interpolation
  58. //
  59. nnai* nnai_build( delaunay* d, int n, double* x, double* y )
  60. {
  61. nnai * nn = malloc( sizeof ( nnai ) );
  62. nnpi * nnpi = nnpi_create( d );
  63. int * vertices;
  64. double* weights;
  65. int i;
  66. if ( n <= 0 )
  67. nn_quit( "nnai_create(): n = %d\n", n );
  68. nn->d = d;
  69. nn->n = n;
  70. nn->x = malloc( n * sizeof ( double ) );
  71. memcpy( nn->x, x, n * sizeof ( double ) );
  72. nn->y = malloc( n * sizeof ( double ) );
  73. memcpy( nn->y, y, n * sizeof ( double ) );
  74. nn->weights = malloc( n * sizeof ( nn_weights ) );
  75. for ( i = 0; i < n; ++i )
  76. {
  77. nn_weights* w = &nn->weights[i];
  78. point p;
  79. p.x = x[i];
  80. p.y = y[i];
  81. nnpi_reset( nnpi );
  82. nnpi_set_point( nnpi, &p );
  83. nnpi_calculate_weights( nnpi );
  84. nnpi_normalize_weights( nnpi );
  85. vertices = nnpi_get_vertices( nnpi );
  86. weights = nnpi_get_weights( nnpi );
  87. w->nvertices = nnpi_get_nvertices( nnpi );
  88. w->vertices = malloc( w->nvertices * sizeof ( int ) );
  89. memcpy( w->vertices, vertices, w->nvertices * sizeof ( int ) );
  90. w->weights = malloc( w->nvertices * sizeof ( double ) );
  91. memcpy( w->weights, weights, w->nvertices * sizeof ( double ) );
  92. }
  93. nnpi_destroy( nnpi );
  94. return nn;
  95. }
  96. // Destroys Natural Neighbours array interpolator.
  97. //
  98. // @param nn Structure to be destroyed
  99. //
  100. void nnai_destroy( nnai* nn )
  101. {
  102. int i;
  103. for ( i = 0; i < nn->n; ++i )
  104. {
  105. nn_weights* w = &nn->weights[i];
  106. free( w->vertices );
  107. free( w->weights );
  108. }
  109. free( nn->x );
  110. free( nn->y );
  111. free( nn->weights );
  112. free( nn );
  113. }
  114. // Conducts NN interpolation in a fixed array of output points using
  115. // data specified for a fixed array of input points. Uses pre-calculated
  116. // weights.
  117. //
  118. // @param nn NN array interpolator
  119. // @param zin input data [nn->d->npoints]
  120. // @param zout output data [nn->n]. Must be pre-allocated!
  121. //
  122. void nnai_interpolate( nnai* nn, double* zin, double* zout )
  123. {
  124. int i;
  125. for ( i = 0; i < nn->n; ++i )
  126. {
  127. nn_weights* w = &nn->weights[i];
  128. double z = 0.0;
  129. int j;
  130. for ( j = 0; j < w->nvertices; ++j )
  131. {
  132. double weight = w->weights[j];
  133. if ( weight < nn->wmin )
  134. {
  135. z = NaN;
  136. break;
  137. }
  138. z += weight * zin[w->vertices[j]];
  139. }
  140. zout[i] = z;
  141. }
  142. }
  143. //* Sets minimal allowed weight for Natural Neighbours interpolation.
  144. // @param nn Natural Neighbours array interpolator
  145. // @param wmin Minimal allowed weight
  146. //
  147. void nnai_setwmin( nnai* nn, double wmin )
  148. {
  149. nn->wmin = wmin;
  150. }
  151. // The rest of this file contains a number of test programs.
  152. //
  153. #if defined ( NNAI_TEST )
  154. #include <sys/time.h>
  155. #define NPOINTSIN 10000
  156. #define NMIN 10
  157. #define NX 101
  158. #define NXMIN 1
  159. #define SQ( x ) ( ( x ) * ( x ) )
  160. static double franke( double x, double y )
  161. {
  162. x *= 9.0;
  163. y *= 9.0;
  164. return 0.75 * exp( ( -SQ( x - 2.0 ) - SQ( y - 2.0 ) ) / 4.0 )
  165. + 0.75 * exp( -SQ( x - 2.0 ) / 49.0 - ( y - 2.0 ) / 10.0 )
  166. + 0.5 * exp( ( -SQ( x - 7.0 ) - SQ( y - 3.0 ) ) / 4.0 )
  167. - 0.2 * exp( -SQ( x - 4.0 ) - SQ( y - 7.0 ) );
  168. }
  169. static void usage()
  170. {
  171. printf(
  172. "Usage: nn_test [-v|-V] [-n <nin> <nxout>]\n"
  173. "Options:\n"
  174. " -a -- use non-Sibsonian interpolation rule\n"
  175. " -n <nin> <nout>:\n"
  176. " <nin> -- number of input points (default = 10000)\n"
  177. " <nout> -- number of output points per side (default = 64)\n"
  178. " -v -- verbose\n"
  179. " -V -- very verbose\n"
  180. );
  181. }
  182. int main( int argc, char* argv[] )
  183. {
  184. int nin = NPOINTSIN;
  185. int nx = NX;
  186. int nout = 0;
  187. point * pin = NULL;
  188. delaunay * d = NULL;
  189. point * pout = NULL;
  190. nnai * nn = NULL;
  191. double * zin = NULL;
  192. double * xout = NULL;
  193. double * yout = NULL;
  194. double * zout = NULL;
  195. int cpi = -1; // control point index
  196. struct timeval tv0, tv1, tv2;
  197. struct timezone tz;
  198. int i;
  199. i = 1;
  200. while ( i < argc )
  201. {
  202. switch ( argv[i][1] )
  203. {
  204. case 'a':
  205. i++;
  206. nn_rule = NON_SIBSONIAN;
  207. break;
  208. case 'n':
  209. i++;
  210. if ( i >= argc )
  211. nn_quit( "no number of data points found after -i\n" );
  212. nin = atoi( argv[i] );
  213. i++;
  214. if ( i >= argc )
  215. nn_quit( "no number of ouput points per side found after -i\n" );
  216. nx = atoi( argv[i] );
  217. i++;
  218. break;
  219. case 'v':
  220. i++;
  221. nn_verbose = 1;
  222. break;
  223. case 'V':
  224. i++;
  225. nn_verbose = 2;
  226. break;
  227. default:
  228. usage();
  229. break;
  230. }
  231. }
  232. if ( nin < NMIN )
  233. nin = NMIN;
  234. if ( nx < NXMIN )
  235. nx = NXMIN;
  236. printf( "\nTest of Natural Neighbours array interpolator:\n\n" );
  237. printf( " %d data points\n", nin );
  238. printf( " %d output points\n", nx * nx );
  239. //
  240. // generate data
  241. //
  242. printf( " generating data:\n" );
  243. fflush( stdout );
  244. pin = malloc( nin * sizeof ( point ) );
  245. zin = malloc( nin * sizeof ( double ) );
  246. for ( i = 0; i < nin; ++i )
  247. {
  248. point* p = &pin[i];
  249. p->x = (double) random() / RAND_MAX;
  250. p->y = (double) random() / RAND_MAX;
  251. p->z = franke( p->x, p->y );
  252. zin[i] = p->z;
  253. if ( nn_verbose )
  254. printf( " (%f, %f, %f)\n", p->x, p->y, p->z );
  255. }
  256. //
  257. // triangulate
  258. //
  259. printf( " triangulating:\n" );
  260. fflush( stdout );
  261. d = delaunay_build( nin, pin, 0, NULL, 0, NULL );
  262. //
  263. // generate output points
  264. //
  265. points_generate2( -0.1, 1.1, -0.1, 1.1, nx, nx, &nout, &pout );
  266. xout = malloc( nout * sizeof ( double ) );
  267. yout = malloc( nout * sizeof ( double ) );
  268. zout = malloc( nout * sizeof ( double ) );
  269. for ( i = 0; i < nout; ++i )
  270. {
  271. point* p = &pout[i];
  272. xout[i] = p->x;
  273. yout[i] = p->y;
  274. zout[i] = NaN;
  275. }
  276. cpi = ( nx / 2 ) * ( nx + 1 );
  277. gettimeofday( &tv0, &tz );
  278. //
  279. // create interpolator
  280. //
  281. printf( " creating interpolator:\n" );
  282. fflush( stdout );
  283. nn = nnai_build( d, nout, xout, yout );
  284. fflush( stdout );
  285. gettimeofday( &tv1, &tz );
  286. {
  287. long dt = 1000000 * ( tv1.tv_sec - tv0.tv_sec ) + tv1.tv_usec - tv0.tv_usec;
  288. printf( " interpolator creation time = %ld us (%.2f us / point)\n", dt, (double) dt / nout );
  289. }
  290. //
  291. // interpolate
  292. //
  293. printf( " interpolating:\n" );
  294. fflush( stdout );
  295. nnai_interpolate( nn, zin, zout );
  296. if ( nn_verbose )
  297. for ( i = 0; i < nout; ++i )
  298. printf( " (%f, %f, %f)\n", xout[i], yout[i], zout[i] );
  299. fflush( stdout );
  300. gettimeofday( &tv2, &tz );
  301. {
  302. long dt = 1000000.0 * ( tv2.tv_sec - tv1.tv_sec ) + tv2.tv_usec - tv1.tv_usec;
  303. printf( " interpolation time = %ld us (%.2f us / point)\n", dt, (double) dt / nout );
  304. }
  305. if ( !nn_verbose )
  306. printf( " control point: (%f, %f, %f) (expected z = %f)\n", xout[cpi], yout[cpi], zout[cpi], franke( xout[cpi], yout[cpi] ) );
  307. printf( " interpolating one more time:\n" );
  308. fflush( stdout );
  309. nnai_interpolate( nn, zin, zout );
  310. if ( nn_verbose )
  311. for ( i = 0; i < nout; ++i )
  312. printf( " (%f, %f, %f)\n", xout[i], yout[i], zout[i] );
  313. fflush( stdout );
  314. gettimeofday( &tv0, &tz );
  315. {
  316. long dt = 1000000.0 * ( tv0.tv_sec - tv2.tv_sec ) + tv0.tv_usec - tv2.tv_usec;
  317. printf( " interpolation time = %ld us (%.2f us / point)\n", dt, (double) dt / nout );
  318. }
  319. if ( !nn_verbose )
  320. printf( " control point: (%f, %f, %f) (expected z = %f)\n", xout[cpi], yout[cpi], zout[cpi], franke( xout[cpi], yout[cpi] ) );
  321. printf( " entering new data:\n" );
  322. fflush( stdout );
  323. for ( i = 0; i < nin; ++i )
  324. {
  325. point* p = &pin[i];
  326. p->z = p->x * p->x - p->y * p->y;
  327. zin[i] = p->z;
  328. if ( nn_verbose )
  329. printf( " (%f, %f, %f)\n", p->x, p->y, p->z );
  330. }
  331. printf( " interpolating:\n" );
  332. fflush( stdout );
  333. nnai_interpolate( nn, zin, zout );
  334. if ( nn_verbose )
  335. for ( i = 0; i < nout; ++i )
  336. printf( " (%f, %f, %f)\n", xout[i], yout[i], zout[i] );
  337. if ( !nn_verbose )
  338. printf( " control point: (%f, %f, %f) (expected z = %f)\n", xout[cpi], yout[cpi], zout[cpi], xout[cpi] * xout[cpi] - yout[cpi] * yout[cpi] );
  339. printf( " restoring data:\n" );
  340. fflush( stdout );
  341. for ( i = 0; i < nin; ++i )
  342. {
  343. point* p = &pin[i];
  344. p->z = franke( p->x, p->y );
  345. zin[i] = p->z;
  346. if ( nn_verbose )
  347. printf( " (%f, %f, %f)\n", p->x, p->y, p->z );
  348. }
  349. printf( " interpolating:\n" );
  350. fflush( stdout );
  351. nnai_interpolate( nn, zin, zout );
  352. if ( nn_verbose )
  353. for ( i = 0; i < nout; ++i )
  354. printf( " (%f, %f, %f)\n", xout[i], yout[i], zout[i] );
  355. if ( !nn_verbose )
  356. printf( " control point: (%f, %f, %f) (expected z = %f)\n", xout[cpi], yout[cpi], zout[cpi], franke( xout[cpi], yout[cpi] ) );
  357. printf( "\n" );
  358. nnai_destroy( nn );
  359. free( zin );
  360. free( xout );
  361. free( yout );
  362. free( zout );
  363. free( pout );
  364. delaunay_destroy( d );
  365. free( pin );
  366. return 0;
  367. }
  368. #endif