/branches/v5_9_6_debian/lib/nn/nnai.c

# · C · 433 lines · 307 code · 63 blank · 63 comment · 31 complexity · 06a82b7b2b208650b7342dc970f1ec2a 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. /* *INDENT-OFF* */
  170. static void usage()
  171. {
  172. printf(
  173. "Usage: nn_test [-v|-V] [-n <nin> <nxout>]\n"
  174. "Options:\n"
  175. " -a -- use non-Sibsonian interpolation rule\n"
  176. " -n <nin> <nout>:\n"
  177. " <nin> -- number of input points (default = 10000)\n"
  178. " <nout> -- number of output points per side (default = 64)\n"
  179. " -v -- verbose\n"
  180. " -V -- very verbose\n"
  181. );
  182. }
  183. /* *INDENT-ON* */
  184. int main( int argc, char* argv[] )
  185. {
  186. int nin = NPOINTSIN;
  187. int nx = NX;
  188. int nout = 0;
  189. point * pin = NULL;
  190. delaunay * d = NULL;
  191. point * pout = NULL;
  192. nnai * nn = NULL;
  193. double * zin = NULL;
  194. double * xout = NULL;
  195. double * yout = NULL;
  196. double * zout = NULL;
  197. int cpi = -1; /* control point index */
  198. struct timeval tv0, tv1, tv2;
  199. struct timezone tz;
  200. int i;
  201. i = 1;
  202. while ( i < argc )
  203. {
  204. switch ( argv[i][1] )
  205. {
  206. case 'a':
  207. i++;
  208. nn_rule = NON_SIBSONIAN;
  209. break;
  210. case 'n':
  211. i++;
  212. if ( i >= argc )
  213. nn_quit( "no number of data points found after -i\n" );
  214. nin = atoi( argv[i] );
  215. i++;
  216. if ( i >= argc )
  217. nn_quit( "no number of ouput points per side found after -i\n" );
  218. nx = atoi( argv[i] );
  219. i++;
  220. break;
  221. case 'v':
  222. i++;
  223. nn_verbose = 1;
  224. break;
  225. case 'V':
  226. i++;
  227. nn_verbose = 2;
  228. break;
  229. default:
  230. usage();
  231. break;
  232. }
  233. }
  234. if ( nin < NMIN )
  235. nin = NMIN;
  236. if ( nx < NXMIN )
  237. nx = NXMIN;
  238. printf( "\nTest of Natural Neighbours array interpolator:\n\n" );
  239. printf( " %d data points\n", nin );
  240. printf( " %d output points\n", nx * nx );
  241. /*
  242. * generate data
  243. */
  244. printf( " generating data:\n" );
  245. fflush( stdout );
  246. pin = malloc( nin * sizeof ( point ) );
  247. zin = malloc( nin * sizeof ( double ) );
  248. for ( i = 0; i < nin; ++i )
  249. {
  250. point* p = &pin[i];
  251. p->x = (double) random() / RAND_MAX;
  252. p->y = (double) random() / RAND_MAX;
  253. p->z = franke( p->x, p->y );
  254. zin[i] = p->z;
  255. if ( nn_verbose )
  256. printf( " (%f, %f, %f)\n", p->x, p->y, p->z );
  257. }
  258. /*
  259. * triangulate
  260. */
  261. printf( " triangulating:\n" );
  262. fflush( stdout );
  263. d = delaunay_build( nin, pin, 0, NULL, 0, NULL );
  264. /*
  265. * generate output points
  266. */
  267. points_generate2( -0.1, 1.1, -0.1, 1.1, nx, nx, &nout, &pout );
  268. xout = malloc( nout * sizeof ( double ) );
  269. yout = malloc( nout * sizeof ( double ) );
  270. zout = malloc( nout * sizeof ( double ) );
  271. for ( i = 0; i < nout; ++i )
  272. {
  273. point* p = &pout[i];
  274. xout[i] = p->x;
  275. yout[i] = p->y;
  276. zout[i] = NaN;
  277. }
  278. cpi = ( nx / 2 ) * ( nx + 1 );
  279. gettimeofday( &tv0, &tz );
  280. /*
  281. * create interpolator
  282. */
  283. printf( " creating interpolator:\n" );
  284. fflush( stdout );
  285. nn = nnai_build( d, nout, xout, yout );
  286. fflush( stdout );
  287. gettimeofday( &tv1, &tz );
  288. {
  289. long dt = 1000000 * ( tv1.tv_sec - tv0.tv_sec ) + tv1.tv_usec - tv0.tv_usec;
  290. printf( " interpolator creation time = %ld us (%.2f us / point)\n", dt, (double) dt / nout );
  291. }
  292. /*
  293. * interpolate
  294. */
  295. printf( " interpolating:\n" );
  296. fflush( stdout );
  297. nnai_interpolate( nn, zin, zout );
  298. if ( nn_verbose )
  299. for ( i = 0; i < nout; ++i )
  300. printf( " (%f, %f, %f)\n", xout[i], yout[i], zout[i] );
  301. fflush( stdout );
  302. gettimeofday( &tv2, &tz );
  303. {
  304. long dt = 1000000.0 * ( tv2.tv_sec - tv1.tv_sec ) + tv2.tv_usec - tv1.tv_usec;
  305. printf( " interpolation time = %ld us (%.2f us / point)\n", dt, (double) dt / nout );
  306. }
  307. if ( !nn_verbose )
  308. printf( " control point: (%f, %f, %f) (expected z = %f)\n", xout[cpi], yout[cpi], zout[cpi], franke( xout[cpi], yout[cpi] ) );
  309. printf( " interpolating one more time:\n" );
  310. fflush( stdout );
  311. nnai_interpolate( nn, zin, zout );
  312. if ( nn_verbose )
  313. for ( i = 0; i < nout; ++i )
  314. printf( " (%f, %f, %f)\n", xout[i], yout[i], zout[i] );
  315. fflush( stdout );
  316. gettimeofday( &tv0, &tz );
  317. {
  318. long dt = 1000000.0 * ( tv0.tv_sec - tv2.tv_sec ) + tv0.tv_usec - tv2.tv_usec;
  319. printf( " interpolation time = %ld us (%.2f us / point)\n", dt, (double) dt / nout );
  320. }
  321. if ( !nn_verbose )
  322. printf( " control point: (%f, %f, %f) (expected z = %f)\n", xout[cpi], yout[cpi], zout[cpi], franke( xout[cpi], yout[cpi] ) );
  323. printf( " entering new data:\n" );
  324. fflush( stdout );
  325. for ( i = 0; i < nin; ++i )
  326. {
  327. point* p = &pin[i];
  328. p->z = p->x * p->x - p->y * p->y;
  329. zin[i] = p->z;
  330. if ( nn_verbose )
  331. printf( " (%f, %f, %f)\n", p->x, p->y, p->z );
  332. }
  333. printf( " interpolating:\n" );
  334. fflush( stdout );
  335. nnai_interpolate( nn, zin, zout );
  336. if ( nn_verbose )
  337. for ( i = 0; i < nout; ++i )
  338. printf( " (%f, %f, %f)\n", xout[i], yout[i], zout[i] );
  339. if ( !nn_verbose )
  340. printf( " control point: (%f, %f, %f) (expected z = %f)\n", xout[cpi], yout[cpi], zout[cpi], xout[cpi] * xout[cpi] - yout[cpi] * yout[cpi] );
  341. printf( " restoring data:\n" );
  342. fflush( stdout );
  343. for ( i = 0; i < nin; ++i )
  344. {
  345. point* p = &pin[i];
  346. p->z = franke( p->x, p->y );
  347. zin[i] = p->z;
  348. if ( nn_verbose )
  349. printf( " (%f, %f, %f)\n", p->x, p->y, p->z );
  350. }
  351. printf( " interpolating:\n" );
  352. fflush( stdout );
  353. nnai_interpolate( nn, zin, zout );
  354. if ( nn_verbose )
  355. for ( i = 0; i < nout; ++i )
  356. printf( " (%f, %f, %f)\n", xout[i], yout[i], zout[i] );
  357. if ( !nn_verbose )
  358. printf( " control point: (%f, %f, %f) (expected z = %f)\n", xout[cpi], yout[cpi], zout[cpi], franke( xout[cpi], yout[cpi] ) );
  359. printf( "\n" );
  360. nnai_destroy( nn );
  361. free( zin );
  362. free( xout );
  363. free( yout );
  364. free( zout );
  365. free( pout );
  366. delaunay_destroy( d );
  367. free( pin );
  368. return 0;
  369. }
  370. #endif