• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

nncommon.c

Go to the documentation of this file.
00001 //--------------------------------------------------------------------------
00002 //
00003 // File:           nncommon.c
00004 //
00005 // Created:        04/08/2000
00006 //
00007 // Author:         Pavel Sakov
00008 //                 CSIRO Marine Research
00009 //
00010 // Purpose:        Common stuff for NN interpolation library
00011 //
00012 // Description:    None
00013 //
00014 // Revisions:      15/11/2002 PS: Changed name from "utils.c"
00015 //                 28/02/2003 PS: Modified points_read() to do the job without
00016 //                   rewinding the file. This allows to read from stdin when
00017 //                   necessary.
00018 //                 09/04/2003 PS: Modified points_read() to read from a
00019 //                   file specified by name, not by handle.
00020 // Modified:       Andrew Ross 20/10/2008
00021 //                 Change <= comparison in circle_contains() to use EPSILON
00022 //                 to catch case where the point lies on the circle and there
00023 //                 is floating point rounding error in the radii.
00024 //
00025 //--------------------------------------------------------------------------
00026 
00027 #include <stdlib.h>
00028 #include <stdio.h>
00029 #include <stdarg.h>
00030 #include <assert.h>
00031 #include <math.h>
00032 #include <limits.h>
00033 #include <float.h>
00034 #include <string.h>
00035 #include <errno.h>
00036 #include "nan.h"
00037 #include "delaunay.h"
00038 
00039 #define BUFSIZE    1024
00040 
00041 #define EPSILON    1.0e-8
00042 
00043 int     nn_verbose      = 0;
00044 int     nn_test_vertice = -1;
00045 NN_RULE nn_rule         = SIBSON;
00046 
00047 #include "version.h"
00048 
00049 void nn_quit( char* format, ... )
00050 {
00051     va_list args;
00052 
00053     fflush( stdout );             // just in case, to have the exit message
00054                                   // last
00055 
00056     fprintf( stderr, "error: nn: " );
00057     va_start( args, format );
00058     vfprintf( stderr, format, args );
00059     va_end( args );
00060 
00061     exit( 1 );
00062 }
00063 
00064 int circle_build( circle* c, point* p1, point* p2, point* p3 )
00065 {
00066     double x1sq = p1->x * p1->x;
00067     double x2sq = p2->x * p2->x;
00068     double x3sq = p3->x * p3->x;
00069     double y1sq = p1->y * p1->y;
00070     double y2sq = p2->y * p2->y;
00071     double y3sq = p3->y * p3->y;
00072     double t1   = x3sq - x2sq + y3sq - y2sq;
00073     double t2   = x1sq - x3sq + y1sq - y3sq;
00074     double t3   = x2sq - x1sq + y2sq - y1sq;
00075     double D    = ( p1->x * ( p2->y - p3->y ) + p2->x * ( p3->y - p1->y ) + p3->x * ( p1->y - p2->y ) ) * 2.0;
00076 
00077     if ( D == 0.0 )
00078         return 0;
00079 
00080     c->x = ( p1->y * t1 + p2->y * t2 + p3->y * t3 ) / D;
00081     c->y = -( p1->x * t1 + p2->x * t2 + p3->x * t3 ) / D;
00082     c->r = hypot( c->x - p1->x, c->y - p1->y );
00083 
00084     return 1;
00085 }
00086 
00087 // This procedure has taken it final shape after a number of tries. The problem
00088 // was to have the calculated and stored radii being the same if (x,y) is
00089 // exactly on the circle border (i.e. not to use FCPU extended precision in
00090 // the radius calculation). This may have little effect in practice but was
00091 // important in some tests when both input and output data were placed
00092 // in rectangular grid nodes.
00093 //
00094 int circle_contains( circle* c, point* p )
00095 {
00096     return hypot( c->x - p->x, c->y - p->y ) <= c->r * ( 1.0 + EPSILON );
00097 }
00098 
00099 // Smoothes the input point array by averaging the input x,y and z values
00100 // for each cell within virtual rectangular nx by ny grid. The corners of the
00101 // grid are created from min and max values of the input array. It also frees
00102 // the original array and returns results and new dimension via original
00103 // data and size pointers.
00104 //
00105 // @param pn Pointer to number of points (input/output)
00106 // @param ppoints Pointer to array of points (input/output) [*pn]
00107 // @param nx Number of x nodes in decimation
00108 // @param ny Number of y nodes in decimation
00109 //
00110 void points_thin( int* pn, point** ppoints, int nx, int ny )
00111 {
00112     int    n           = *pn;
00113     point  * points    = *ppoints;
00114     double xmin        = DBL_MAX;
00115     double xmax        = -DBL_MAX;
00116     double ymin        = DBL_MAX;
00117     double ymax        = -DBL_MAX;
00118     int    nxy         = nx * ny;
00119     double * sumx      = calloc( nxy, sizeof ( double ) );
00120     double * sumy      = calloc( nxy, sizeof ( double ) );
00121     double * sumz      = calloc( nxy, sizeof ( double ) );
00122     int    * count     = calloc( nxy, sizeof ( int ) );
00123     double stepx       = 0.0;
00124     double stepy       = 0.0;
00125     int    nnew        = 0;
00126     point  * pointsnew = NULL;
00127     int    i, j, ii;
00128 
00129     if ( nn_verbose )
00130         fprintf( stderr, "thinned: %d points -> ", *pn );
00131 
00132     if ( nx < 1 || ny < 1 )
00133     {
00134         free( points );
00135         *ppoints = NULL;
00136         *pn      = 0;
00137         if ( nn_verbose )
00138             fprintf( stderr, "0 points" );
00139         free( sumx );
00140         free( sumy );
00141         free( sumz );
00142         free( count );
00143         return;
00144     }
00145 
00146     for ( ii = 0; ii < n; ++ii )
00147     {
00148         point* p = &points[ii];
00149 
00150         if ( p->x < xmin )
00151             xmin = p->x;
00152         if ( p->x > xmax )
00153             xmax = p->x;
00154         if ( p->y < ymin )
00155             ymin = p->y;
00156         if ( p->y > ymax )
00157             ymax = p->y;
00158     }
00159 
00160     stepx = ( nx > 1 ) ? ( xmax - xmin ) / nx : 0.0;
00161     stepy = ( ny > 1 ) ? ( ymax - ymin ) / ny : 0.0;
00162 
00163     for ( ii = 0; ii < n; ++ii )
00164     {
00165         point* p = &points[ii];
00166         int  index;
00167 
00168         //
00169         // Following is the portion of the code which really depends on the
00170         // floating point particulars. Do not be surprised if different
00171         // compilers/options give different results here.
00172         //
00173         i = ( nx == 1 ) ? 0 : ( p->x - xmin ) / stepx;
00174         j = ( ny == 1 ) ? 0 : ( p->y - ymin ) / stepy;
00175 
00176         if ( i == nx )
00177             i--;
00178         if ( j == ny )
00179             j--;
00180         index        = i + j * nx;
00181         sumx[index] += p->x;
00182         sumy[index] += p->y;
00183         sumz[index] += p->z;
00184         count[index]++;
00185     }
00186 
00187     for ( j = 0; j < ny; ++j )
00188     {
00189         for ( i = 0; i < nx; ++i )
00190         {
00191             int index = i + j * nx;
00192 
00193             if ( count[index] > 0 )
00194                 nnew++;
00195         }
00196     }
00197 
00198     pointsnew = malloc( nnew * sizeof ( point ) );
00199 
00200     ii = 0;
00201     for ( j = 0; j < ny; ++j )
00202     {
00203         for ( i = 0; i < nx; ++i )
00204         {
00205             int index = i + j * nx;
00206             int nn    = count[index];
00207 
00208             if ( nn > 0 )
00209             {
00210                 point* p = &pointsnew[ii];
00211 
00212                 p->x = sumx[index] / nn;
00213                 p->y = sumy[index] / nn;
00214                 p->z = sumz[index] / nn;
00215                 ii++;
00216             }
00217         }
00218     }
00219 
00220     if ( nn_verbose )
00221         fprintf( stderr, "%d points\n", nnew );
00222 
00223     free( sumx );
00224     free( sumy );
00225     free( sumz );
00226     free( count );
00227 
00228     free( points );
00229     *ppoints = pointsnew;
00230     *pn      = nnew;
00231 }
00232 
00233 // Generates rectangular grid nx by ny using min and max x and y values from
00234 // the input point array. Allocates space for the output point array, be sure
00235 // to free it when necessary!
00236 //
00237 // @param n Number of points
00238 // @param points Array of points [n]
00239 // @param nx Number of x nodes
00240 // @param ny Number of y nodes
00241 // @param zoom Zoom coefficient
00242 // @param nout Pointer to number of output points
00243 // @param pout Pointer to array of output points [*nout]
00244 //
00245 void points_generate1( int nin, point pin[], int nx, int ny, double zoom, int* nout, point** pout )
00246 {
00247     double xmin = DBL_MAX;
00248     double xmax = -DBL_MAX;
00249     double ymin = DBL_MAX;
00250     double ymax = -DBL_MAX;
00251     double stepx, stepy;
00252     double x0, xx, yy;
00253     int    i, j, ii;
00254 
00255     if ( nx < 1 || ny < 1 )
00256     {
00257         *pout = NULL;
00258         *nout = 0;
00259         return;
00260     }
00261 
00262     for ( ii = 0; ii < nin; ++ii )
00263     {
00264         point* p = &pin[ii];
00265 
00266         if ( p->x < xmin )
00267             xmin = p->x;
00268         if ( p->x > xmax )
00269             xmax = p->x;
00270         if ( p->y < ymin )
00271             ymin = p->y;
00272         if ( p->y > ymax )
00273             ymax = p->y;
00274     }
00275 
00276     if ( isnan( zoom ) || zoom <= 0.0 )
00277         zoom = 1.0;
00278 
00279     if ( zoom != 1.0 )
00280     {
00281         double xdiff2 = ( xmax - xmin ) / 2.0;
00282         double ydiff2 = ( ymax - ymin ) / 2.0;
00283         double xav    = ( xmax + xmin ) / 2.0;
00284         double yav    = ( ymax + ymin ) / 2.0;
00285 
00286         xmin = xav - xdiff2 * zoom;
00287         xmax = xav + xdiff2 * zoom;
00288         ymin = yav - ydiff2 * zoom;
00289         ymax = yav + ydiff2 * zoom;
00290     }
00291 
00292     *nout = nx * ny;
00293     *pout = malloc( *nout * sizeof ( point ) );
00294 
00295     stepx = ( nx > 1 ) ? ( xmax - xmin ) / ( nx - 1 ) : 0.0;
00296     stepy = ( ny > 1 ) ? ( ymax - ymin ) / ( ny - 1 ) : 0.0;
00297     x0    = ( nx > 1 ) ? xmin : ( xmin + xmax ) / 2.0;
00298     yy    = ( ny > 1 ) ? ymin : ( ymin + ymax ) / 2.0;
00299 
00300     ii = 0;
00301     for ( j = 0; j < ny; ++j )
00302     {
00303         xx = x0;
00304         for ( i = 0; i < nx; ++i )
00305         {
00306             point* p = &( *pout )[ii];
00307 
00308             p->x = xx;
00309             p->y = yy;
00310             xx  += stepx;
00311             ii++;
00312         }
00313         yy += stepy;
00314     }
00315 }
00316 
00317 // Generates rectangular grid nx by ny using specified min and max x and y
00318 // values. Allocates space for the output point array, be sure to free it
00319 // when necessary!
00320 //
00321 // @param xmin Min x value
00322 // @param xmax Max x value
00323 // @param ymin Min y value
00324 // @param ymax Max y value
00325 // @param nx Number of x nodes
00326 // @param ny Number of y nodes
00327 // @param nout Pointer to number of output points
00328 // @param pout Pointer to array of output points [*nout]
00329 //
00330 void points_generate2( double xmin, double xmax, double ymin, double ymax, int nx, int ny, int* nout, point** pout )
00331 {
00332     double stepx, stepy;
00333     double x0, xx, yy;
00334     int    i, j, ii;
00335 
00336     if ( nx < 1 || ny < 1 )
00337     {
00338         *pout = NULL;
00339         *nout = 0;
00340         return;
00341     }
00342 
00343     *nout = nx * ny;
00344     *pout = malloc( *nout * sizeof ( point ) );
00345 
00346     stepx = ( nx > 1 ) ? ( xmax - xmin ) / ( nx - 1 ) : 0.0;
00347     stepy = ( ny > 1 ) ? ( ymax - ymin ) / ( ny - 1 ) : 0.0;
00348     x0    = ( nx > 1 ) ? xmin : ( xmin + xmax ) / 2.0;
00349     yy    = ( ny > 1 ) ? ymin : ( ymin + ymax ) / 2.0;
00350 
00351     ii = 0;
00352     for ( j = 0; j < ny; ++j )
00353     {
00354         xx = x0;
00355         for ( i = 0; i < nx; ++i )
00356         {
00357             point* p = &( *pout )[ii];
00358 
00359             p->x = xx;
00360             p->y = yy;
00361             xx  += stepx;
00362             ii++;
00363         }
00364         yy += stepy;
00365     }
00366 }
00367 
00368 static int str2double( char* token, double* value )
00369 {
00370     char* end = NULL;
00371 
00372     if ( token == NULL )
00373     {
00374         *value = NaN;
00375         return 0;
00376     }
00377 
00378     *value = strtod( token, &end );
00379 
00380     if ( end == token )
00381     {
00382         *value = NaN;
00383         return 0;
00384     }
00385 
00386     return 1;
00387 }
00388 
00389 #define NALLOCATED_START    1024
00390 
00391 // Reads array of points from a columnar file.
00392 //
00393 // @param fname File name (can be "stdin" for standard input)
00394 // @param dim Number of dimensions (must be 2 or 3)
00395 // @param n Pointer to number of points (output)
00396 // @param points Pointer to array of points [*n] (output) (to be freed)
00397 //
00398 void points_read( char* fname, int dim, int* n, point** points )
00399 {
00400     FILE * f        = NULL;
00401     int  nallocated = NALLOCATED_START;
00402     char buf[BUFSIZE];
00403     char seps[] = " ,;\t";
00404     char * token;
00405 
00406     if ( dim < 2 || dim > 3 )
00407     {
00408         *n      = 0;
00409         *points = NULL;
00410         return;
00411     }
00412 
00413     if ( fname == NULL )
00414         f = stdin;
00415     else
00416     {
00417         if ( strcmp( fname, "stdin" ) == 0 || strcmp( fname, "-" ) == 0 )
00418             f = stdin;
00419         else
00420         {
00421             f = fopen( fname, "r" );
00422             if ( f == NULL )
00423                 nn_quit( "%s: %s\n", fname, strerror( errno ) );
00424         }
00425     }
00426 
00427     *points = malloc( nallocated * sizeof ( point ) );
00428     *n      = 0;
00429     while ( fgets( buf, BUFSIZE, f ) != NULL )
00430     {
00431         point* p;
00432 
00433         if ( *n == nallocated )
00434         {
00435             nallocated *= 2;
00436             *points     = realloc( *points, nallocated * sizeof ( point ) );
00437         }
00438 
00439         p = &( *points )[*n];
00440 
00441         if ( buf[0] == '#' )
00442             continue;
00443         if ( ( token = strtok( buf, seps ) ) == NULL )
00444             continue;
00445         if ( !str2double( token, &p->x ) )
00446             continue;
00447         if ( ( token = strtok( NULL, seps ) ) == NULL )
00448             continue;
00449         if ( !str2double( token, &p->y ) )
00450             continue;
00451         if ( dim == 2 )
00452             p->z = NaN;
00453         else
00454         {
00455             if ( ( token = strtok( NULL, seps ) ) == NULL )
00456                 continue;
00457             if ( !str2double( token, &p->z ) )
00458                 continue;
00459         }
00460         ( *n )++;
00461     }
00462 
00463     if ( *n == 0 )
00464     {
00465         free( *points );
00466         *points = NULL;
00467     }
00468     else
00469         *points = realloc( *points, *n * sizeof ( point ) );
00470 
00471     if ( f != stdin )
00472         if ( fclose( f ) != 0 )
00473             nn_quit( "%s: %s\n", fname, strerror( errno ) );
00474 }
00475 
00476 //* Scales Y coordinate so that the resulting set fits into square:
00477 //** xmax - xmin = ymax - ymin
00478 //*
00479 //* @param n Number of points
00480 //* @param points The points to scale
00481 //* @return Y axis compression coefficient
00482 //
00483 double points_scaletosquare( int n, point* points )
00484 {
00485     double xmin, ymin, xmax, ymax;
00486     double k;
00487     int    i;
00488 
00489     if ( n <= 0 )
00490         return NaN;
00491 
00492     xmin = xmax = points[0].x;
00493     ymin = ymax = points[0].y;
00494 
00495     for ( i = 1; i < n; ++i )
00496     {
00497         point* p = &points[i];
00498 
00499         if ( p->x < xmin )
00500             xmin = p->x;
00501         else if ( p->x > xmax )
00502             xmax = p->x;
00503         if ( p->y < ymin )
00504             ymin = p->y;
00505         else if ( p->y > ymax )
00506             ymax = p->y;
00507     }
00508 
00509     if ( xmin == xmax || ymin == ymax )
00510         return NaN;
00511     else
00512         k = ( ymax - ymin ) / ( xmax - xmin );
00513 
00514     for ( i = 0; i < n; ++i )
00515         points[i].y /= k;
00516 
00517     return k;
00518 }
00519 
00520 //* Compresses Y domain by a given multiple.
00521 //
00522 // @param n Number of points
00523 // @param points The points to scale
00524 // @param Y axis compression coefficient as returned by points_scaletosquare()
00525 //
00526 void points_scale( int n, point* points, double k )
00527 {
00528     int i;
00529 
00530     for ( i = 0; i < n; ++i )
00531         points[i].y /= k;
00532 }

Generated on Wed Oct 12 2011 20:42:21 for PLplot by  doxygen 1.7.1