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

plgridd.c

Go to the documentation of this file.
00001 //
00002 // plgridd.c: Plot grids data from irregularly sampled data.
00003 // $Id: plgridd.c 11680 2011-03-27 17:57:51Z airwin $
00004 //
00005 // Copyright (C) 2004  Joao Cardoso
00006 // Copyright (C) 2004  Alan W. Irwin
00007 //
00008 // This file is part of PLplot.
00009 //
00010 // PLplot is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Library General Public License as published
00012 // by the Free Software Foundation; either version 2 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // PLplot is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Library General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Library General Public License
00021 // along with PLplot; if not, write to the Free Software
00022 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00023 //
00024 //
00025 
00026 #include "plplotP.h"
00027 
00028 #ifdef WITH_CSA
00029 #include "../lib/csa/csa.h"
00030 #endif
00031 #include "../lib/csa/nan.h" // this is handy
00032 
00033 #ifdef PL_HAVE_QHULL
00034 #include "../lib/nn/nn.h"
00035 #include <qhull/qhull_a.h>
00036 #endif
00037 
00038 // forward declarations
00039 static void
00040 grid_nnaidw( const PLFLT *x, const PLFLT *y, const PLFLT *z, int npts,
00041              const PLFLT *xg, int nptsx, const PLFLT *yg, int nptsy,
00042              PLF2OPS zops, PLPointer zgp );
00043 
00044 static void
00045 grid_nnli( const PLFLT *x, const PLFLT *y, const PLFLT *z, int npts,
00046            const PLFLT *xg, int nptsx, const PLFLT *yg, int nptsy,
00047            PLF2OPS zops, PLPointer zgp, PLFLT threshold );
00048 
00049 static void
00050 grid_nnidw( const PLFLT *x, const PLFLT *y, const PLFLT *z, int npts,
00051             const PLFLT *xg, int nptsx, const PLFLT *yg, int nptsy,
00052             PLF2OPS zops, PLPointer zgp, int knn_order );
00053 
00054 #ifdef WITH_CSA
00055 static void
00056 grid_csa( const PLFLT *x, const PLFLT *y, const PLFLT *z, int npts,
00057           const PLFLT *xg, int nptsx, const PLFLT *yg, int nptsy,
00058           PLF2OPS zops, PLPointer zgp );
00059 #endif
00060 
00061 #ifdef PL_HAVE_QHULL
00062 static void
00063 grid_nni( const PLFLT *x, const PLFLT *y, const PLFLT *z, int npts,
00064           const PLFLT *xg, int nptsx, const PLFLT *yg, int nptsy,
00065           PLF2OPS zops, PLPointer zgp, PLFLT wmin );
00066 
00067 static void
00068 grid_dtli( const PLFLT *x, const PLFLT *y, const PLFLT *z, int npts,
00069            const PLFLT *xg, int nptsx, const PLFLT *yg, int nptsy,
00070            PLF2OPS zops, PLPointer zgp );
00071 #endif
00072 
00073 static void
00074 dist1( PLFLT gx, PLFLT gy, const PLFLT *x, const PLFLT *y, int npts, int knn_order );
00075 static void
00076 dist2( PLFLT gx, PLFLT gy, const PLFLT *x, const PLFLT *y, int npts );
00077 
00078 #define KNN_MAX_ORDER    100
00079 
00080 typedef struct pt
00081 {
00082     PLFLT dist;
00083     int   item;
00084 }PT;
00085 
00086 static PT items[KNN_MAX_ORDER];
00087 
00088 //--------------------------------------------------------------------------
00089 //
00090 // plgriddata(): grids data from irregularly sampled data.
00091 //
00092 //    Real world data is frequently irregularly sampled, but most 3D plots
00093 //    require regularly gridded data. This function does exactly this
00094 //    using several methods:
00095 //    Irregularly sampled data x[npts], y[npts], z[npts] is gridded into
00096 //    zg[nptsx, nptsy] according to methode 'type' and grid information
00097 //    xg[nptsx], yg[nptsy].
00098 //
00099 //    'type' can be:
00100 //
00101 //       GRID_CSA:    Bivariate Cubic Spline approximation (1)
00102 //       GRID_NNIDW:  Nearest Neighbors Inverse Distance Weighted
00103 //       GRID_NNLI:   Nearest Neighbors Linear Interpolation
00104 //       GRID_NNAIDW: Nearest Neighbors Around Inverse Distance Weighted
00105 //       GRID_DTLI:   Delaunay Triangulation Linear Interpolation (2)
00106 //       GRID_NNI:    Natural Neighbors interpolation (2)
00107 //
00108 // (1): Copyright 2000-2002 CSIRO Marine Research, Pavel Sakov's csa library
00109 // (2): Copyright 2002 CSIRO Marine Research, Pavel Sakov's nn library
00110 //
00111 //--------------------------------------------------------------------------
00112 
00113 void
00114 c_plgriddata( const PLFLT *x, const PLFLT *y, const PLFLT *z, PLINT npts,
00115               const PLFLT *xg, PLINT nptsx, const PLFLT *yg, PLINT nptsy,
00116               PLFLT **zg, PLINT type, PLFLT data )
00117 {
00118     plfgriddata( x, y, z, npts, xg, nptsx, yg, nptsy, plf2ops_c(), (PLPointer) zg, type, data );
00119 }
00120 
00121 void
00122 plfgriddata( const PLFLT *x, const PLFLT *y, const PLFLT *z, PLINT npts,
00123              const PLFLT *xg, PLINT nptsx, const PLFLT *yg, PLINT nptsy,
00124              PLF2OPS zops, PLPointer zgp, PLINT type, PLFLT data )
00125 {
00126     int i, j;
00127 
00128     if ( npts < 1 || nptsx < 1 || nptsy < 1 )
00129     {
00130         plabort( "plgriddata: Bad array dimensions" );
00131         return;
00132     }
00133 
00134     // Check that points in xg and in yg are strictly increasing
00135 
00136     for ( i = 0; i < nptsx - 1; i++ )
00137     {
00138         if ( xg[i] >= xg[i + 1] )
00139         {
00140             plabort( "plgriddata: xg array must be strictly increasing" );
00141             return;
00142         }
00143     }
00144     for ( i = 0; i < nptsy - 1; i++ )
00145     {
00146         if ( yg[i] >= yg[i + 1] )
00147         {
00148             plabort( "plgriddata: yg array must be strictly increasing" );
00149             return;
00150         }
00151     }
00152 
00153     // clear array to return
00154     for ( i = 0; i < nptsx; i++ )
00155         for ( j = 0; j < nptsy; j++ )
00156             zops->set( zgp, i, j, 0.0 );
00157     // NaN signals a not processed grid point
00158 
00159     switch ( type )
00160     {
00161     case ( GRID_CSA ): //  Bivariate Cubic Spline Approximation
00162 #ifdef WITH_CSA
00163         grid_csa( x, y, z, npts, xg, nptsx, yg, nptsy, zops, zgp );
00164 #else
00165         plwarn( "plgriddata(): PLplot was configured to not use GRID_CSA.\n  Reverting to GRID_NNAIDW." );
00166         grid_nnaidw( x, y, z, npts, xg, nptsx, yg, nptsy, zops, zgp );
00167 #endif
00168         break;
00169 
00170     case ( GRID_NNIDW ): // Nearest Neighbors Inverse Distance Weighted
00171         grid_nnidw( x, y, z, npts, xg, nptsx, yg, nptsy, zops, zgp, (int) data );
00172         break;
00173 
00174     case ( GRID_NNLI ): // Nearest Neighbors Linear Interpolation
00175         grid_nnli( x, y, z, npts, xg, nptsx, yg, nptsy, zops, zgp, data );
00176         break;
00177 
00178     case ( GRID_NNAIDW ): // Nearest Neighbors "Around" Inverse Distance Weighted
00179         grid_nnaidw( x, y, z, npts, xg, nptsx, yg, nptsy, zops, zgp );
00180         break;
00181 
00182     case ( GRID_DTLI ): // Delaunay Triangulation Linear Interpolation
00183 #ifdef PL_HAVE_QHULL
00184         grid_dtli( x, y, z, npts, xg, nptsx, yg, nptsy, zops, zgp );
00185 #else
00186         plwarn( "plgriddata(): you must have the Qhull library installed to use GRID_DTLI.\n  Reverting to GRID_NNAIDW." );
00187         grid_nnaidw( x, y, z, npts, xg, nptsx, yg, nptsy, zops, zgp );
00188 #endif
00189         break;
00190 
00191     case ( GRID_NNI ): // Natural Neighbors
00192 #ifdef PL_HAVE_QHULL
00193         grid_nni( x, y, z, npts, xg, nptsx, yg, nptsy, zops, zgp, data );
00194 #else
00195         plwarn( "plgriddata(): you must have the Qhull library installed to use GRID_NNI.\n  Reverting to GRID_NNAIDW." );
00196         grid_nnaidw( x, y, z, npts, xg, nptsx, yg, nptsy, zops, zgp );
00197 #endif
00198         break;
00199 
00200     default:
00201         plabort( "plgriddata: unknown algorithm type" );
00202     }
00203 }
00204 
00205 #ifdef WITH_CSA
00206 //
00207 // Bivariate Cubic Spline Approximation using Pavel Sakov's csa package
00208 //
00209 // NaNs are returned where no interpolation can be done.
00210 //
00211 
00212 static void
00213 grid_csa( const PLFLT *x, const PLFLT *y, const PLFLT *z, int npts,
00214           const PLFLT *xg, int nptsx, const PLFLT *yg, int nptsy,
00215           PLF2OPS zops, PLPointer zgp )
00216 {
00217     PLFLT *xt, *yt, *zt;
00218     point *pin, *pgrid, *pt;
00219     csa   * a = NULL;
00220     int   i, j, nptsg;
00221 
00222     if ( ( pin = (point *) malloc( npts * sizeof ( point ) ) ) == NULL )
00223     {
00224         plexit( "grid_csa: Insufficient memory" );
00225     }
00226 
00227     xt = (PLFLT *) x;
00228     yt = (PLFLT *) y;
00229     zt = (PLFLT *) z;
00230     pt = pin;
00231     for ( i = 0; i < npts; i++ )
00232     {
00233         pt->x = (double) *xt++;
00234         pt->y = (double) *yt++;
00235         pt->z = (double) *zt++;
00236         pt++;
00237     }
00238 
00239     nptsg = nptsx * nptsy;
00240     if ( ( pgrid = (point *) malloc( nptsg * sizeof ( point ) ) ) == NULL )
00241     {
00242         plexit( "grid_csa: Insufficient memory" );
00243     }
00244 
00245     yt = (PLFLT *) yg;
00246     pt = pgrid;
00247     for ( j = 0; j < nptsy; j++ )
00248     {
00249         xt = (PLFLT *) xg;
00250         for ( i = 0; i < nptsx; i++ )
00251         {
00252             pt->x = (double) *xt++;
00253             pt->y = (double) *yt;
00254             pt++;
00255         }
00256         yt++;
00257     }
00258 
00259     a = csa_create();
00260     csa_addpoints( a, npts, pin );
00261     csa_calculatespline( a );
00262     csa_approximate_points( a, nptsg, pgrid );
00263 
00264     for ( i = 0; i < nptsx; i++ )
00265     {
00266         for ( j = 0; j < nptsy; j++ )
00267         {
00268             pt = &pgrid[j * nptsx + i];
00269             zops->set( zgp, i, j, (PLFLT) pt->z );
00270         }
00271     }
00272 
00273     csa_destroy( a );
00274     free( pin );
00275     free( pgrid );
00276 }
00277 #endif // WITH_CSA
00278 
00279 // Nearest Neighbors Inverse Distance Weighted, brute force approach.
00280 //
00281 // The z value at the grid position will be the weighted average
00282 // of the z values of the KNN points found. The weigth is the
00283 // inverse squared distance between the grid point and each
00284 // neighbor.
00285 //
00286 
00287 static void
00288 grid_nnidw( const PLFLT *x, const PLFLT *y, const PLFLT *z, int npts,
00289             const PLFLT *xg, int nptsx, const PLFLT *yg, int nptsy,
00290             PLF2OPS zops, PLPointer zgp, int knn_order )
00291 {
00292     int   i, j, k;
00293     PLFLT wi, nt;
00294 
00295     if ( knn_order > KNN_MAX_ORDER )
00296     {
00297         plabort( "plgriddata(): GRID_NNIDW: knn_order too big" ); // make sure it is smaller that KNN_MAX_ORDER
00298         return;
00299     }
00300 
00301     if ( knn_order == 0 )
00302     {
00303         plwarn( "plgriddata(): GRID_NNIDW: knn_order must be specified with 'data' arg. Using 15" );
00304         knn_order = 15;;
00305     }
00306 
00307     for ( i = 0; i < nptsx; i++ )
00308     {
00309         for ( j = 0; j < nptsy; j++ )
00310         {
00311             dist1( xg[i], yg[j], x, y, npts, knn_order );
00312 
00313 #ifdef GMS  // alternative weight coeficients. I Don't like the results
00314             // find the maximum distance
00315             md = items[0].dist;
00316             for ( k = 1; k < knn_order; k++ )
00317                 if ( items[k].dist > md )
00318                     md = items[k].dist;
00319 #endif
00320             zops->set( zgp, i, j, 0.0 );
00321             nt = 0.;
00322 
00323             for ( k = 0; k < knn_order; k++ )
00324             {
00325                 if ( items[k].item == -1 ) // not enough neighbors found ?!
00326                     continue;
00327 #ifdef GMS
00328                 wi = ( md - items[k].dist ) / ( md * items[k].dist );
00329                 wi = wi * wi;
00330 #else
00331                 wi = 1. / ( items[k].dist * items[k].dist );
00332 #endif
00333                 zops->add( zgp, i, j, wi * z[items[k].item] );
00334                 nt += wi;
00335             }
00336             if ( nt != 0. )
00337                 zops->div( zgp, i, j, nt );
00338             else
00339                 zops->set( zgp, i, j, NaN );
00340         }
00341     }
00342 }
00343 
00344 // Nearest Neighbors Linear Interpolation
00345 //
00346 // The z value at the grid position will be interpolated from the
00347 // plane passing through the 3 nearest neighbors.
00348 //
00349 
00350 static void
00351 grid_nnli( const PLFLT *x, const PLFLT *y, const PLFLT *z, int npts,
00352            const PLFLT *xg, int nptsx, const PLFLT *yg, int nptsy,
00353            PLF2OPS zops, PLPointer zgp, PLFLT threshold )
00354 {
00355     PLFLT xx[4], yy[4], zz[4], t, A, B, C, D, d1, d2, d3, max_thick;
00356     int   i, j, ii, excl, cnt, excl_item;
00357 
00358     if ( threshold == 0. )
00359     {
00360         plwarn( "plgriddata(): GRID_NNLI: threshold must be specified with 'data' arg. Using 1.001" );
00361         threshold = 1.001;
00362     }
00363     else if ( threshold > 2. || threshold < 1. )
00364     {
00365         plabort( "plgriddata(): GRID_NNLI: 1. < threshold < 2." );
00366         return;
00367     }
00368 
00369     for ( i = 0; i < nptsx; i++ )
00370     {
00371         for ( j = 0; j < nptsy; j++ )
00372         {
00373             dist1( xg[i], yg[j], x, y, npts, 3 );
00374 
00375             // see if the triangle is a thin one
00376             for ( ii = 0; ii < 3; ii++ )
00377             {
00378                 xx[ii] = x[items[ii].item];
00379                 yy[ii] = y[items[ii].item];
00380                 zz[ii] = z[items[ii].item];
00381             }
00382 
00383             d1 = sqrt( ( xx[1] - xx[0] ) * ( xx[1] - xx[0] ) + ( yy[1] - yy[0] ) * ( yy[1] - yy[0] ) );
00384             d2 = sqrt( ( xx[2] - xx[1] ) * ( xx[2] - xx[1] ) + ( yy[2] - yy[1] ) * ( yy[2] - yy[1] ) );
00385             d3 = sqrt( ( xx[0] - xx[2] ) * ( xx[0] - xx[2] ) + ( yy[0] - yy[2] ) * ( yy[0] - yy[2] ) );
00386 
00387             if ( d1 == 0. || d2 == 0. || d3 == 0. ) // coincident points
00388             {
00389                 zops->set( zgp, i, j, NaN );
00390                 continue;
00391             }
00392 
00393             // make d1 < d2
00394             if ( d1 > d2 )
00395             {
00396                 t = d1; d1 = d2; d2 = t;
00397             }
00398 
00399             // and d2 < d3
00400             if ( d2 > d3 )
00401             {
00402                 t = d2; d2 = d3; d3 = t;
00403             }
00404 
00405             if ( ( d1 + d2 ) / d3 < threshold ) // thin triangle!
00406             {
00407                 zops->set( zgp, i, j, NaN );    // deal with it later
00408             }
00409             else                                // calculate the plane passing through the three points
00410 
00411             {
00412                 A = yy[0] * ( zz[1] - zz[2] ) + yy[1] * ( zz[2] - zz[0] ) + yy[2] * ( zz[0] - zz[1] );
00413                 B = zz[0] * ( xx[1] - xx[2] ) + zz[1] * ( xx[2] - xx[0] ) + zz[2] * ( xx[0] - xx[1] );
00414                 C = xx[0] * ( yy[1] - yy[2] ) + xx[1] * ( yy[2] - yy[0] ) + xx[2] * ( yy[0] - yy[1] );
00415                 D = -A * xx[0] - B * yy[0] - C * zz[0];
00416 
00417                 // and interpolate (or extrapolate...)
00418                 zops->set( zgp, i, j, -xg[i] * A / C - yg[j] * B / C - D / C );
00419             }
00420         }
00421     }
00422 
00423     // now deal with NaNs resulting from thin triangles. The idea is
00424     // to use the 4 KNN points and exclude one at a time, creating
00425     // four triangles, evaluating their thickness and choosing the
00426     // most thick as the final one from where the interpolating
00427     // plane will be build.  Now that I'm talking of interpolating,
00428     // one should really check that the target point is interior to
00429     // the candidate triangle... otherwise one is extrapolating
00430     //
00431 
00432     {
00433         for ( i = 0; i < nptsx; i++ )
00434         {
00435             for ( j = 0; j < nptsy; j++ )
00436             {
00437                 if ( zops->is_nan( zgp, i, j ) )
00438                 {
00439                     dist1( xg[i], yg[j], x, y, npts, 4 );
00440 
00441                     // sort by distances. Not really needed!
00442                     // for (ii=3; ii>0; ii--) {
00443                     // for (jj=0; jj<ii; jj++) {
00444                     // if (items[jj].dist > items[jj+1].dist) {
00445                     // t = items[jj].dist;
00446                     // items[jj].dist = items[jj+1].dist;
00447                     // items[jj+1].dist = t;
00448                     // }
00449                     // }
00450                     // }
00451                     //
00452 
00453                     max_thick = 0.; excl_item = -1;
00454                     for ( excl = 0; excl < 4; excl++ ) // the excluded point
00455 
00456                     {
00457                         cnt = 0;
00458                         for ( ii = 0; ii < 4; ii++ )
00459                         {
00460                             if ( ii != excl )
00461                             {
00462                                 xx[cnt] = x[items[ii].item];
00463                                 yy[cnt] = y[items[ii].item];
00464                                 cnt++;
00465                             }
00466                         }
00467 
00468                         d1 = sqrt( ( xx[1] - xx[0] ) * ( xx[1] - xx[0] ) + ( yy[1] - yy[0] ) * ( yy[1] - yy[0] ) );
00469                         d2 = sqrt( ( xx[2] - xx[1] ) * ( xx[2] - xx[1] ) + ( yy[2] - yy[1] ) * ( yy[2] - yy[1] ) );
00470                         d3 = sqrt( ( xx[0] - xx[2] ) * ( xx[0] - xx[2] ) + ( yy[0] - yy[2] ) * ( yy[0] - yy[2] ) );
00471                         if ( d1 == 0. || d2 == 0. || d3 == 0. ) // coincident points
00472                             continue;
00473 
00474                         // make d1 < d2
00475                         if ( d1 > d2 )
00476                         {
00477                             t = d1; d1 = d2; d2 = t;
00478                         }
00479                         // and d2 < d3
00480                         if ( d2 > d3 )
00481                         {
00482                             t = d2; d2 = d3; d3 = t;
00483                         }
00484 
00485                         t = ( d1 + d2 ) / d3;
00486                         if ( t > max_thick )
00487                         {
00488                             max_thick = t;
00489                             excl_item = excl;
00490                         }
00491                     }
00492 
00493                     if ( excl_item == -1 ) // all points are coincident?
00494                         continue;
00495 
00496                     // one has the thicker triangle constructed from the 4 KNN
00497                     cnt = 0;
00498                     for ( ii = 0; ii < 4; ii++ )
00499                     {
00500                         if ( ii != excl_item )
00501                         {
00502                             xx[cnt] = x[items[ii].item];
00503                             yy[cnt] = y[items[ii].item];
00504                             zz[cnt] = z[items[ii].item];
00505                             cnt++;
00506                         }
00507                     }
00508 
00509                     A = yy[0] * ( zz[1] - zz[2] ) + yy[1] * ( zz[2] - zz[0] ) + yy[2] * ( zz[0] - zz[1] );
00510                     B = zz[0] * ( xx[1] - xx[2] ) + zz[1] * ( xx[2] - xx[0] ) + zz[2] * ( xx[0] - xx[1] );
00511                     C = xx[0] * ( yy[1] - yy[2] ) + xx[1] * ( yy[2] - yy[0] ) + xx[2] * ( yy[0] - yy[1] );
00512                     D = -A * xx[0] - B * yy[0] - C * zz[0];
00513 
00514                     // and interpolate (or extrapolate...)
00515                     zops->set( zgp, i, j, -xg[i] * A / C - yg[j] * B / C - D / C );
00516                 }
00517             }
00518         }
00519     }
00520 }
00521 
00522 //
00523 // Nearest Neighbors "Around" Inverse Distance Weighted, brute force approach.
00524 //
00525 // This uses the 1-KNN in each quadrant around the grid point, then
00526 // Inverse Distance Weighted is used as in GRID_NNIDW.
00527 //
00528 
00529 static void
00530 grid_nnaidw( const PLFLT *x, const PLFLT *y, const PLFLT *z, int npts,
00531              const PLFLT *xg, int nptsx, const PLFLT *yg, int nptsy, PLF2OPS zops, PLPointer zgp )
00532 {
00533     PLFLT d, nt;
00534     int   i, j, k;
00535 
00536     for ( i = 0; i < nptsx; i++ )
00537     {
00538         for ( j = 0; j < nptsy; j++ )
00539         {
00540             dist2( xg[i], yg[j], x, y, npts );
00541             zops->set( zgp, i, j, 0. );
00542             nt = 0.;
00543             for ( k = 0; k < 4; k++ )
00544             {
00545                 if ( items[k].item != -1 )                              // was found
00546                 {
00547                     d = 1. / ( items[k].dist * items[k].dist );         // 1/square distance
00548                     zops->add( zgp, i, j, d * z[items[k].item] );
00549                     nt += d;
00550                 }
00551             }
00552             if ( nt == 0. ) // no points found?!
00553                 zops->set( zgp, i, j, NaN );
00554             else
00555                 zops->div( zgp, i, j, nt );
00556         }
00557     }
00558 }
00559 
00560 #ifdef PL_HAVE_QHULL
00561 //
00562 // Delaunay Triangulation Linear Interpolation using Pavel Sakov's nn package
00563 //
00564 // The Delaunay Triangulation on the data points is build and for
00565 // each grid point the triangle where it is enclosed found and a
00566 // linear interpolation performed.
00567 //
00568 // Points exterior to the convex hull of the data points cannot
00569 // be interpolated and are set to NaN.
00570 //
00571 
00572 static void
00573 grid_dtli( const PLFLT *x, const PLFLT *y, const PLFLT *z, int npts,
00574            const PLFLT *xg, int nptsx, const PLFLT *yg, int nptsy, PLF2OPS zops, PLPointer zgp )
00575 {
00576     point *pin, *pgrid, *pt;
00577     PLFLT *xt, *yt, *zt;
00578     int   i, j, nptsg;
00579 
00580     if ( sizeof ( realT ) != sizeof ( double ) )
00581     {
00582         plabort( "plgridata: QHull was compiled for floats instead of doubles" );
00583         return;
00584     }
00585 
00586     if ( ( pin = (point *) malloc( npts * sizeof ( point ) ) ) == NULL )
00587     {
00588         plexit( "grid_dtli: Insufficient memory" );
00589     }
00590 
00591     xt = (PLFLT *) x;
00592     yt = (PLFLT *) y;
00593     zt = (PLFLT *) z;
00594     pt = pin;
00595     for ( i = 0; i < npts; i++ )
00596     {
00597         pt->x = (double) *xt++;
00598         pt->y = (double) *yt++;
00599         pt->z = (double) *zt++;
00600         pt++;
00601     }
00602 
00603     nptsg = nptsx * nptsy;
00604 
00605     if ( ( pgrid = (point *) malloc( nptsg * sizeof ( point ) ) ) == NULL )
00606     {
00607         plexit( "grid_dtli: Insufficient memory" );
00608     }
00609 
00610     yt = (PLFLT *) yg;
00611     pt = pgrid;
00612     for ( j = 0; j < nptsy; j++ )
00613     {
00614         xt = (PLFLT *) xg;
00615         for ( i = 0; i < nptsx; i++ )
00616         {
00617             pt->x = (double) *xt++;
00618             pt->y = (double) *yt;
00619             pt++;
00620         }
00621         yt++;
00622     }
00623 
00624     lpi_interpolate_points( npts, pin, nptsg, pgrid );
00625     for ( i = 0; i < nptsx; i++ )
00626     {
00627         for ( j = 0; j < nptsy; j++ )
00628         {
00629             pt = &pgrid[j * nptsx + i];
00630             zops->set( zgp, i, j, (PLFLT) pt->z );
00631         }
00632     }
00633 
00634     free( pin );
00635     free( pgrid );
00636 }
00637 
00638 //
00639 // Natural Neighbors using Pavel Sakov's nn package
00640 //
00641 // Points exterior to the convex hull of the data points cannot
00642 // be interpolated and are set to NaN.
00643 //
00644 
00645 static void
00646 grid_nni( const PLFLT *x, const PLFLT *y, const PLFLT *z, int npts,
00647           const PLFLT *xg, int nptsx, const PLFLT *yg, int nptsy, PLF2OPS zops, PLPointer zgp,
00648           PLFLT wmin )
00649 {
00650     PLFLT *xt, *yt, *zt;
00651     point *pin, *pgrid, *pt;
00652     int   i, j, nptsg;
00653     nn_rule = NON_SIBSONIAN;
00654 
00655     if ( sizeof ( realT ) != sizeof ( double ) )
00656     {
00657         plabort( "plgridata: QHull was compiled for floats instead of doubles" );
00658         return;
00659     }
00660 
00661     if ( wmin == 0. ) // only accept weights greater than wmin
00662     {
00663         plwarn( "plgriddata(): GRID_NNI: wmin must be specified with 'data' arg. Using -PLFLT_MAX" );
00664         wmin = -PLFLT_MAX;
00665     }
00666 
00667     if ( ( pin = (point *) malloc( npts * sizeof ( point ) ) ) == NULL )
00668     {
00669         plexit( "plgridata: Insufficient memory" );
00670     }
00671 
00672     xt = (PLFLT *) x;
00673     yt = (PLFLT *) y;
00674     zt = (PLFLT *) z;
00675     pt = pin;
00676     for ( i = 0; i < npts; i++ )
00677     {
00678         pt->x = (double) *xt++;
00679         pt->y = (double) *yt++;
00680         pt->z = (double) *zt++;
00681         pt++;
00682     }
00683 
00684     nptsg = nptsx * nptsy;
00685 
00686     if ( ( pgrid = (point *) malloc( nptsg * sizeof ( point ) ) ) == NULL )
00687     {
00688         plexit( "plgridata: Insufficient memory" );
00689     }
00690 
00691     yt = (PLFLT *) yg;
00692     pt = pgrid;
00693     for ( j = 0; j < nptsy; j++ )
00694     {
00695         xt = (PLFLT *) xg;
00696         for ( i = 0; i < nptsx; i++ )
00697         {
00698             pt->x = (double) *xt++;
00699             pt->y = (double) *yt;
00700             pt++;
00701         }
00702         yt++;
00703     }
00704 
00705     nnpi_interpolate_points( npts, pin, wmin, nptsg, pgrid );
00706     for ( i = 0; i < nptsx; i++ )
00707     {
00708         for ( j = 0; j < nptsy; j++ )
00709         {
00710             pt = &pgrid[j * nptsx + i];
00711             zops->set( zgp, i, j, (PLFLT) pt->z );
00712         }
00713     }
00714 
00715     free( pin );
00716     free( pgrid );
00717 }
00718 #endif // PL_HAVE_QHULL
00719 
00720 //
00721 // this function just calculates the K Nearest Neighbors of grid point
00722 // [gx, gy].
00723 //
00724 
00725 static void
00726 dist1( PLFLT gx, PLFLT gy, const PLFLT *x, const PLFLT *y, int npts, int knn_order )
00727 {
00728     PLFLT d, max_dist;
00729     int   max_slot, i, j;
00730 
00731     max_dist = PLFLT_MAX;
00732     max_slot = 0;
00733 
00734     for ( i = 0; i < knn_order; i++ )
00735     {
00736         items[i].dist = PLFLT_MAX;
00737         items[i].item = -1;
00738     }
00739 
00740     for ( i = 0; i < npts; i++ )
00741     {
00742         d = ( ( gx - x[i] ) * ( gx - x[i] ) + ( gy - y[i] ) * ( gy - y[i] ) ); // save sqrt() time
00743 
00744         if ( d < max_dist )
00745         {
00746             // found an item with a distance smaller than the
00747             // maximum distance found so far. Replace.
00748             //
00749 
00750             items[max_slot].dist = d;
00751             items[max_slot].item = i;
00752 
00753             // find new maximum distance
00754             max_dist = items[0].dist;
00755             max_slot = 0;
00756             for ( j = 1; j < knn_order; j++ )
00757             {
00758                 if ( items[j].dist > max_dist )
00759                 {
00760                     max_dist = items[j].dist;
00761                     max_slot = j;
00762                 }
00763             }
00764         }
00765     }
00766     for ( j = 0; j < knn_order; j++ )
00767         items[j].dist = sqrt( items[j].dist ); // now calculate the distance
00768 }
00769 
00770 //
00771 // This function searchs the 1-nearest neighbor in each quadrant around
00772 // the grid point.
00773 //
00774 
00775 static void
00776 dist2( PLFLT gx, PLFLT gy, const PLFLT *x, const PLFLT *y, int npts )
00777 {
00778     PLFLT d;
00779     int   i, quad;
00780 
00781     for ( i = 0; i < 4; i++ )
00782     {
00783         items[i].dist = PLFLT_MAX;
00784         items[i].item = -1;
00785     }
00786 
00787     for ( i = 0; i < npts; i++ )
00788     {
00789         d = ( ( gx - x[i] ) * ( gx - x[i] ) + ( gy - y[i] ) * ( gy - y[i] ) ); // save sqrt() time
00790 
00791         // trick to quickly compute a quadrant. The determined quadrants will be
00792         // miss-assigned, i.e., 1->2, 2->0, 3->1, 4->3, but that is not important,
00793         // speed is.
00794 
00795         quad = 2 * ( x[i] > gx ) + ( y[i] < gy );
00796 
00797         // try to use the octants around the grid point, as it will give smoother
00798         // (and slower) results.
00799         // Hint: use the quadrant info plus x[i]/y[i] to determine the octant
00800 
00801         if ( d < items[quad].dist )
00802         {
00803             items[quad].dist = d;
00804             items[quad].item = i;
00805         }
00806     }
00807 
00808     for ( i = 0; i < 4; i++ )
00809         if ( items[i].item != -1 )
00810             items[i].dist = sqrt( items[i].dist );
00811     // now calculate the distance
00812 }
00813 
00814 #ifdef NONN // another DTLI, based only on QHULL, not nn
00815 static void
00816 grid_adtli( const PLFLT *x, const PLFLT *y, const PLFLT *z, int npts,
00817             const PLFLT *xg, int nptsx, const PLFLT *yg, int nptsy, PLF2OPS zops, PLPointer zgp )
00818 {
00819     coordT  *points;          // array of coordinates for each point
00820     boolT   ismalloc = False; // True if qhull should free points
00821     char    flags[250];       // option flags for qhull
00822     facetT  *facet;           // set by FORALLfacets
00823     vertexT *vertex, **vertexp;
00824     facetT  *neighbor, **neighborp;
00825     int     curlong, totlong;  // memory remaining after qh_memfreeshort
00826     FILE    *outfile = NULL;
00827     FILE    *errfile = stderr; // error messages from qhull code
00828 
00829     int     exitcode;
00830     int     i, j, k, l;
00831     int     dim = 2;
00832     PLFLT   xt[3], yt[3], zt[3];
00833     PLFLT   A, B, C, D;
00834     coordT  point[3];
00835     boolT   isoutside;
00836     realT   bestdist;
00837     int     totpart = 0;
00838     int     numfacets, numsimplicial, numridges;
00839     int     totneighbors, numcoplanars, numtricoplanars;
00840 
00841     plwarn( "plgriddata: GRID_DTLI, If you have QHull knowledge, FIXME." );
00842 
00843     // Could pass extra args to qhull through the 'data' argument of
00844     // plgriddata()
00845     strcpy( flags, "qhull d Qbb Qt", 250 );
00846 
00847     if ( ( points = (coordT *) malloc( npts * ( dim + 1 ) * sizeof ( coordT ) ) ) == NULL )
00848     {
00849         plexit( "grid_adtli: Insufficient memory" );
00850     }
00851 
00852     for ( i = 0; i < npts; i++ )
00853     {
00854         points[i * dim]     = x[i];
00855         points[i * dim + 1] = y[i];
00856     }
00857 
00858 #if 1 // easy way
00859     exitcode = qh_new_qhull( dim, npts, points, ismalloc,
00860         flags, outfile, errfile );
00861 #else
00862     qh_init_A( stdin, stdout, stderr, 0, NULL );
00863     exitcode = setjmp( qh errexit );
00864     if ( !exitcode )
00865     {
00866         qh_initflags( flags );
00867         qh PROJECTdelaunay = True;
00868         qh_init_B( points, npts, dim, ismalloc );
00869         qh_qhull();
00870     }
00871 #endif
00872     if ( !exitcode )                // if no error
00873 
00874     {
00875 #if 0   // print the triangles vertices
00876         printf( "Triangles\n" );
00877         FORALLfacets {
00878             if ( !facet->upperdelaunay )
00879             {
00880                 FOREACHvertex_( facet->vertices )
00881                 printf( " %d", qh_pointid( vertex->point ) ); // vertices index
00882                 printf( "\n" );
00883             }
00884         }
00885 #endif
00886 
00887 #if 0   // print each triangle neighbors
00888         printf( "Neigbors\n" );
00889 
00890         qh_findgood_all( qh facet_list );
00891         qh_countfacets( qh facet_list, NULL, !qh_ALL, &numfacets, &numsimplicial,
00892             &totneighbors, &numridges, &numcoplanars, &numtricoplanars );
00893 
00894         FORALLfacets {
00895             if ( !facet->upperdelaunay )
00896             {
00897                 FOREACHneighbor_( facet )
00898                 printf( " %d", neighbor->visitid ? neighbor->visitid - 1 : -neighbor->id );
00899                 printf( "\n" );
00900             }
00901         }
00902 #endif
00903 
00904         // Without the setjmp(), Qhull will exit() after reporting an error
00905         exitcode = setjmp( qh errexit );
00906         if ( !exitcode )
00907         {
00908             qh NOerrexit = False;
00909             for ( i = 0; i < nptsx; i++ )
00910                 for ( j = 0; j < nptsy; j++ )
00911                 {
00912                     l        = 0;
00913                     point[0] = xg[i];
00914                     point[1] = yg[j];
00915                     qh_setdelaunay( 3, 1, point );
00916 
00917 
00918                     // several ways to find the triangle given a point follow.
00919                     // None but brute force works
00920 #if 0
00921                     facet = qh_findbestfacet( point, qh_ALL, &bestdist, &isoutside );
00922 #endif
00923 
00924 #if 0
00925                     facet = qh_findbest( point, qh facet_list, qh_ALL,
00926                         !qh_ISnewfacets, //qh_ALL
00927                         qh_NOupper,
00928                         &bestdist, &isoutside, &totpart );
00929 #endif
00930 
00931 #if 0
00932                     vertex = qh_nearvertex( facet, point, &bestdist );
00933 #endif
00934 
00935                     // Until someone implements a working qh_findbestfacet(),
00936                     // do an exautive search!
00937                     //
00938                     // As far as I understand it, qh_findbestfacet() and
00939                     // qh_findbest() fails when 'point' does not belongs to
00940                     // the convex hull, i.e., when the search becomes blocked
00941                     // when a facet is upperdelaunay (although the error
00942                     // message says that the facet may be upperdelaynay or
00943                     // flipped, I never found a flipped one).
00944                     //
00945                     // Another possibility is to implement the 'walking
00946                     // triangle algorithm
00947 
00948                     facet = qh_findfacet_all( point, &bestdist, &isoutside, &totpart );
00949 
00950                     if ( facet->upperdelaunay )
00951                         zops->set( zgp, i, j, NaN );
00952                     else
00953                     {
00954                         FOREACHvertex_( facet->vertices )
00955                         {
00956                             k     = qh_pointid( vertex->point );
00957                             xt[l] = x[k];
00958                             yt[l] = y[k];
00959                             zt[l] = z[k];
00960                             l++;
00961                         }
00962 
00963                         // calculate the plane passing through the three points
00964 
00965                         A = yt[0] * ( zt[1] - zt[2] ) + yt[1] * ( zt[2] - zt[0] ) + yt[2] * ( zt[0] - zt[1] );
00966                         B = zt[0] * ( xt[1] - xt[2] ) + zt[1] * ( xt[2] - xt[0] ) + zt[2] * ( xt[0] - xt[1] );
00967                         C = xt[0] * ( yt[1] - yt[2] ) + xt[1] * ( yt[2] - yt[0] ) + xt[2] * ( yt[0] - yt[1] );
00968                         D = -A * xt[0] - B * yt[0] - C * zt[0];
00969 
00970                         // and interpolate
00971                         zops->set( zgp, i, j, -xg[i] * A / C - yg[j] * B / C - D / C );
00972                     }
00973                 }
00974         }
00975         qh NOerrexit = True;
00976     }
00977 
00978     free( points );
00979     qh_freeqhull( !qh_ALL );               // free long memory
00980     qh_memfreeshort( &curlong, &totlong ); // free short memory and memory allocator
00981     if ( curlong || totlong )
00982         fprintf( errfile,
00983             "qhull: did not free %d bytes of long memory (%d pieces)\n",
00984             totlong, curlong );
00985 }
00986 #endif // NONN

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