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

plshade.c

Go to the documentation of this file.
00001 // $Id: plshade.c 11759 2011-06-01 17:41:34Z airwin $
00002 //
00003 //      Functions to shade regions on the basis of value.
00004 //      Can be used to shade contour plots or alone.
00005 //      Copyright 1993 Wesley Ebisuzaki
00006 //
00007 // Copyright (C) 2004  Alan W. Irwin
00008 //
00009 // This file is part of PLplot.
00010 //
00011 // PLplot is free software; you can redistribute it and/or modify
00012 // it under the terms of the GNU Library General Public License as published
00013 // by the Free Software Foundation; either version 2 of the License, or
00014 // (at your option) any later version.
00015 //
00016 // PLplot is distributed in the hope that it will be useful,
00017 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 // GNU Library General Public License for more details.
00020 //
00021 // You should have received a copy of the GNU Library General Public License
00022 // along with PLplot; if not, write to the Free Software
00023 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00024 //
00025 //
00026 
00027 //--------------------------------------------------------------------------
00028 // Call syntax for plshade():
00029 //
00030 // void plshade(PLFLT *a, PLINT nx, PLINT ny, char *defined,
00031 //      PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax,
00032 //      PLFLT shade_min, PLFLT shade_max,
00033 //      PLINT sh_color, PLINT sh_width, PLINT min_color, PLINT min_width,
00034 //      PLINT max_color, PLINT max_width, void (*fill)(), PLINT
00035 //      rectangular, ...)
00036 //
00037 // arguments:
00038 //
00039 //      PLFLT &(a[0][0])
00040 //
00041 // Contains array to be plotted. The array must have been declared as
00042 // PLFLT a[nx][ny].  See following note on fortran-style arrays.
00043 //
00044 //      PLINT nx, ny
00045 //
00046 // Dimension of array "a".
00047 //
00048 //      char &(defined[0][0])
00049 //
00050 // Contains array of flags, 1 = data is valid, 0 = data is not valid.
00051 // This array determines which sections of the data is to be plotted.
00052 // This argument can be NULL if all the values are valid.  Must have been
00053 // declared as char defined[nx][ny].
00054 //
00055 //      PLFLT xmin, xmax, ymin, ymax
00056 //
00057 // Defines the "grid" coordinates.  The data a[0][0] has a position of
00058 // (xmin,ymin).
00059 //
00060 //      void (*mapform)()
00061 //
00062 // Transformation from `grid' coordinates to world coordinates.  This
00063 // pointer to a function can be NULL in which case the grid coordinates
00064 // are the same as the world coordinates.
00065 //
00066 //      PLFLT shade_min, shade_max
00067 //
00068 // Defines the interval to be shaded. If shade_max <= shade_min, plshade
00069 // does nothing.
00070 //
00071 //      PLINT sh_cmap, PLFLT sh_color, PLINT sh_width
00072 //
00073 // Defines color map, color map index, and width used by the fill pattern.
00074 //
00075 //      PLINT min_color, min_width, max_color, max_width
00076 //
00077 // Defines pen color, width used by the boundary of shaded region. The min
00078 // values are used for the shade_min boundary, and the max values are used
00079 // on the shade_max boundary.  Set color and width to zero for no plotted
00080 // boundaries.
00081 //
00082 //      void (*fill)()
00083 //
00084 // Routine used to fill the region.  Use plfill.  Future version of plplot
00085 // may have other fill routines.
00086 //
00087 //      PLINT rectangular
00088 //
00089 // Flag. Set to 1 if rectangles map to rectangles after (*mapform)() else
00090 // set to zero. If rectangular is set to 1, plshade tries to save time by
00091 // filling large rectangles.  This optimization fails if (*mapform)()
00092 // distorts the shape of rectangles.  For example a plot in polor
00093 // coordinates has to have rectangular set to zero.
00094 //
00095 // Example mapform's:
00096 //
00097 // Grid to world coordinate transformation.
00098 // This example goes from a r-theta to x-y for a polar plot.
00099 //
00100 // void mapform(PLINT n, PLFLT *x, PLFLT *y) {
00101 //      int i;
00102 //      double r, theta;
00103 //      for (i = 0; i < n; i++) {
00104 //          r = x[i];
00105 //          theta = y[i];
00106 //          x[i] = r*cos(theta);
00107 //          y[i] = r*sin(theta);
00108 //      }
00109 // }
00110 //
00111 // Grid was in cm, convert to world coordinates in inches.
00112 // Expands in x direction.
00113 //
00114 // void mapform(PLINT n, PLFLT *x, PLFLT *y) {
00115 //      int i;
00116 //      for (i = 0; i < n; i++) {
00117 //              x[i] = (1.0 / 2.5) * x[i];
00118 //              y[i] = (1.0 / 2.5) * y[i];
00119 //      }
00120 // }
00121 //
00122 //--------------------------------------------------------------------------
00123 
00124 #include "plplotP.h"
00125 #include <float.h>
00126 
00127 #define MISSING_MIN_DEF      (PLFLT) 1.0
00128 #define MISSING_MAX_DEF      (PLFLT) -1.0
00129 
00130 
00131 #define NEG                  1
00132 #define POS                  8
00133 #define OK                   0
00134 #define UNDEF                64
00135 #define NUMBER_BISECTIONS    10
00136 
00137 #define linear( val1, val2, level )    ( ( level - val1 ) / ( val2 - val1 ) )
00138 
00139 // Global variables
00140 
00141 static PLFLT sh_max, sh_min;
00142 static int   min_points, max_points, n_point;
00143 static int   min_pts[4], max_pts[4];
00144 static PLINT pen_col_min, pen_col_max;
00145 static PLINT pen_wd_min, pen_wd_max;
00146 static PLFLT int_val;
00147 
00148 // Function prototypes
00149 
00150 static void
00151 set_cond( register int *cond, register PLFLT *a, register PLINT n );
00152 
00153 static int
00154 find_interval( PLFLT a0, PLFLT a1, PLINT c0, PLINT c1, PLFLT *x );
00155 
00156 static void
00157 selected_polygon( void ( *fill )( PLINT, const PLFLT *, const PLFLT * ),
00158                   PLINT ( *defined )( PLFLT, PLFLT ),
00159                   const PLFLT *x, const PLFLT *y, PLINT v1, PLINT v2, PLINT v3, PLINT v4 );
00160 
00161 static void
00162 exfill( void ( *fill )( PLINT, const PLFLT *, const PLFLT * ),
00163         PLINT ( *defined )( PLFLT, PLFLT ),
00164         int n, const PLFLT *x, const PLFLT *y );
00165 
00166 static void
00167 big_recl( int *cond_code, register int ny, int dx, int dy,
00168           int *ix, int *iy );
00169 
00170 static void
00171 draw_boundary( PLINT slope, PLFLT *x, PLFLT *y );
00172 
00173 static PLINT
00174 plctest( PLFLT *x, PLFLT level );
00175 
00176 static PLINT
00177 plctestez( PLFLT *a, PLINT nx, PLINT ny, PLINT ix,
00178            PLINT iy, PLFLT level );
00179 
00180 static void
00181 plshade_int( PLFLT ( *f2eval )( PLINT, PLINT, PLPointer ),
00182              PLPointer f2eval_data,
00183              PLFLT ( *c2eval )( PLINT, PLINT, PLPointer ),
00184              PLPointer c2eval_data,
00185              PLINT ( *defined )( PLFLT, PLFLT ),
00186              PLFLT missing_min, PLFLT missing_max,
00187              PLINT nx, PLINT ny,
00188              PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax,
00189              PLFLT shade_min, PLFLT shade_max,
00190              PLINT sh_cmap, PLFLT sh_color, PLINT sh_width,
00191              PLINT min_color, PLINT min_width,
00192              PLINT max_color, PLINT max_width,
00193              void ( *fill )( PLINT, const PLFLT *, const PLFLT * ), PLINT rectangular,
00194              void ( *pltr )( PLFLT, PLFLT, PLFLT *, PLFLT *, PLPointer ),
00195              PLPointer pltr_data );
00196 
00197 //--------------------------------------------------------------------------
00198 // plshades()
00199 //
00200 // Shade regions via a series of calls to plshade.
00201 // All arguments are the same as plshade except the following:
00202 // clevel is a pointer to an array of values representing
00203 // the shade edge values, nlevel-1 is
00204 // the number of different shades, (nlevel is the number of shade edges),
00205 // fill_width is the pattern fill width, and cont_color and cont_width
00206 // are the color and width of the contour drawn at each shade edge.
00207 // (if cont_color <= 0 or cont_width <=0, no such contours are drawn).
00208 //--------------------------------------------------------------------------
00209 
00210 void c_plshades( const PLFLT **a, PLINT nx, PLINT ny, PLINT ( *defined )( PLFLT, PLFLT ),
00211                  PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax,
00212                  const PLFLT *clevel, PLINT nlevel, PLINT fill_width,
00213                  PLINT cont_color, PLINT cont_width,
00214                  void ( *fill )( PLINT, const PLFLT *, const PLFLT * ), PLINT rectangular,
00215                  void ( *pltr )( PLFLT, PLFLT, PLFLT *, PLFLT *, PLPointer ),
00216                  PLPointer pltr_data )
00217 {
00218     plfshades( plf2ops_c(), a, nx, ny, defined,
00219         xmin, xmax, ymin, ymax,
00220         clevel, nlevel, fill_width,
00221         cont_color, cont_width,
00222         fill, rectangular,
00223         pltr, pltr_data );
00224 }
00225 
00226 //--------------------------------------------------------------------------
00227 // plfshades()
00228 //
00229 // Shade regions via a series of calls to plfshade1.
00230 // All arguments are the same as plfshade1 except the following:
00231 // clevel is a pointer to an array of values representing
00232 // the shade edge values, nlevel-1 is
00233 // the number of different shades, (nlevel is the number of shade edges),
00234 // fill_width is the pattern fill width, and cont_color and cont_width
00235 // are the color and width of the contour drawn at each shade edge.
00236 // (if cont_color <= 0 or cont_width <=0, no such contours are drawn).
00237 //--------------------------------------------------------------------------
00238 
00239 void
00240 plfshades( PLF2OPS zops, PLPointer zp, PLINT nx, PLINT ny,
00241            PLINT ( *defined )( PLFLT, PLFLT ),
00242            PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax,
00243            const PLFLT *clevel, PLINT nlevel, PLINT fill_width,
00244            PLINT cont_color, PLINT cont_width,
00245            void ( *fill )( PLINT, const PLFLT *, const PLFLT * ), PLINT rectangular,
00246            void ( *pltr )( PLFLT, PLFLT, PLFLT *, PLFLT *, PLPointer ),
00247            PLPointer pltr_data )
00248 {
00249     PLFLT shade_min, shade_max, shade_color;
00250     PLINT i, init_color, init_width;
00251     PLFLT color_min, color_max, color_range;
00252 
00253     // Color range to use
00254     color_min   = plsc->cmap1_min;
00255     color_max   = plsc->cmap1_max;
00256     color_range = color_max - color_min;
00257 
00258     for ( i = 0; i < nlevel - 1; i++ )
00259     {
00260         shade_min   = clevel[i];
00261         shade_max   = clevel[i + 1];
00262         shade_color = color_min + i / (PLFLT) ( nlevel - 2 ) * color_range;
00263         // The constants in order mean
00264         // (1) color map1,
00265         // (0, 0, 0, 0) all edge effects will be done with plcont rather
00266         // than the normal plshade drawing which gets partially blocked
00267         // when sequential shading is done as in the present case
00268 
00269         plfshade1( zops, zp, nx, ny, defined, xmin, xmax, ymin, ymax,
00270             shade_min, shade_max,
00271             1, shade_color, fill_width,
00272             0, 0, 0, 0,
00273             fill, rectangular, pltr, pltr_data );
00274     }
00275     if ( cont_color > 0 && cont_width > 0 )
00276     {
00277         init_color = plsc->icol0;
00278         init_width = plsc->width;
00279         plcol0( cont_color );
00280         plwid( cont_width );
00281         if ( pltr )
00282         {
00283             plfcont( zops->f2eval, zp, nx, ny, 1, nx, 1, ny, clevel, nlevel, pltr, pltr_data );
00284         }
00285         else
00286         {
00287             // For this case use the same interpretation that occurs internally
00288             // for plshade.  That is set up x and y grids that map from the
00289             // index ranges to xmin, xmax, ymin, ymax, and use those grids
00290             // for the plcont call.
00291             //
00292             PLcGrid cgrid1;
00293             PLFLT   *x, *y;
00294             cgrid1.nx = nx;
00295             cgrid1.ny = ny;
00296             x         = (PLFLT *) malloc( nx * sizeof ( PLFLT ) );
00297             if ( x == NULL )
00298                 plexit( "plfshades: Out of memory for x" );
00299             cgrid1.xg = x;
00300             for ( i = 0; i < nx; i++ )
00301                 cgrid1.xg[i] = xmin + ( xmax - xmin ) * (float) i / (float) ( nx - 1 );
00302             y = (PLFLT *) malloc( ny * sizeof ( PLFLT ) );
00303             if ( y == NULL )
00304                 plexit( "plfshades: Out of memory for y" );
00305             cgrid1.yg = y;
00306             for ( i = 0; i < ny; i++ )
00307                 cgrid1.yg[i] = ymin + ( ymax - ymin ) * (float) i / (float) ( ny - 1 );
00308             plfcont( zops->f2eval, zp, nx, ny, 1, nx, 1, ny, clevel, nlevel,
00309                 pltr1, (void *) &cgrid1 );
00310             free( x );
00311             free( y );
00312         }
00313         plcol0( init_color );
00314         plwid( init_width );
00315     }
00316 }
00317 
00318 //--------------------------------------------------------------------------
00319 // plshade()
00320 //
00321 // Shade region.
00322 // This interface to plfshade() assumes the 2d function array is passed
00323 // via a (PLFLT **), and is column-dominant (normal C ordering).
00324 //--------------------------------------------------------------------------
00325 
00326 void c_plshade( const PLFLT **a, PLINT nx, PLINT ny, PLINT ( *defined )( PLFLT, PLFLT ),
00327                 PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax,
00328                 PLFLT shade_min, PLFLT shade_max,
00329                 PLINT sh_cmap, PLFLT sh_color, PLINT sh_width,
00330                 PLINT min_color, PLINT min_width,
00331                 PLINT max_color, PLINT max_width,
00332                 void ( *fill )( PLINT, const PLFLT *, const PLFLT * ), PLINT rectangular,
00333                 void ( *pltr )( PLFLT, PLFLT, PLFLT *, PLFLT *, PLPointer ),
00334                 PLPointer pltr_data )
00335 {
00336     plshade_int( plf2eval1, (PLPointer) a,
00337         NULL, NULL,
00338 //           plc2eval, (PLPointer) &cgrid,
00339         defined, MISSING_MIN_DEF, MISSING_MAX_DEF, nx, ny, xmin,
00340         xmax, ymin, ymax, shade_min, shade_max,
00341         sh_cmap, sh_color, sh_width,
00342         min_color, min_width, max_color, max_width,
00343         fill, rectangular, pltr, pltr_data );
00344 }
00345 
00346 //--------------------------------------------------------------------------
00347 // plshade1()
00348 //
00349 // Shade region.
00350 // This interface to plfshade() assumes the 2d function array is passed
00351 // via a (PLFLT *), and is column-dominant (normal C ordering).
00352 //--------------------------------------------------------------------------
00353 
00354 void c_plshade1( const PLFLT *a, PLINT nx, PLINT ny, PLINT ( *defined )( PLFLT, PLFLT ),
00355                  PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax,
00356                  PLFLT shade_min, PLFLT shade_max,
00357                  PLINT sh_cmap, PLFLT sh_color, PLINT sh_width,
00358                  PLINT min_color, PLINT min_width,
00359                  PLINT max_color, PLINT max_width,
00360                  void ( *fill )( PLINT, const PLFLT *, const PLFLT * ), PLINT rectangular,
00361                  void ( *pltr )( PLFLT, PLFLT, PLFLT *, PLFLT *, PLPointer ),
00362                  PLPointer pltr_data )
00363 {
00364     PLfGrid grid;
00365 
00366     grid.f  = (PLFLT *) a;
00367     grid.nx = nx;
00368     grid.ny = ny;
00369 
00370     plshade_int( plf2eval, ( PLPointer ) & grid,
00371         NULL, NULL,
00372 //           plc2eval, (PLPointer) &cgrid,
00373         defined, MISSING_MIN_DEF, MISSING_MAX_DEF, nx, ny, xmin,
00374         xmax, ymin, ymax, shade_min, shade_max,
00375         sh_cmap, sh_color, sh_width,
00376         min_color, min_width, max_color, max_width,
00377         fill, rectangular, pltr, pltr_data );
00378 }
00379 
00380 //--------------------------------------------------------------------------
00381 // plfshade()
00382 //
00383 // Shade region.
00384 // Array values are determined by the input function and the passed data.
00385 //--------------------------------------------------------------------------
00386 
00387 void
00388 plfshade( PLFLT ( *f2eval )( PLINT, PLINT, PLPointer ),
00389           PLPointer f2eval_data,
00390           PLFLT ( *c2eval )( PLINT, PLINT, PLPointer ),
00391           PLPointer c2eval_data,
00392           PLINT nx, PLINT ny,
00393           PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax,
00394           PLFLT shade_min, PLFLT shade_max,
00395           PLINT sh_cmap, PLFLT sh_color, PLINT sh_width,
00396           PLINT min_color, PLINT min_width,
00397           PLINT max_color, PLINT max_width,
00398           void ( *fill )( PLINT, const PLFLT *, const PLFLT * ), PLINT rectangular,
00399           void ( *pltr )( PLFLT, PLFLT, PLFLT *, PLFLT *, PLPointer ),
00400           PLPointer pltr_data )
00401 {
00402     plshade_int( f2eval, f2eval_data, c2eval, c2eval_data,
00403         NULL, MISSING_MIN_DEF, MISSING_MAX_DEF,
00404         nx, ny, xmin, xmax, ymin, ymax,
00405         shade_min, shade_max, sh_cmap, sh_color, sh_width,
00406         min_color, min_width, max_color, max_width,
00407         fill, rectangular, pltr, pltr_data );
00408 }
00409 
00410 //--------------------------------------------------------------------------
00411 // plfshade1()
00412 //
00413 // Shade region.
00414 //
00415 // This function is a plf2ops variant of c_plfshade and c_plfshade1.  It
00416 // differs from plfshade in that it supports a "defined" callback (like
00417 // c_plshade and c_plfshade1) rather than a "defined mask" (like plfshade
00418 // even though it is not yet implemented).
00419 //--------------------------------------------------------------------------
00420 
00421 void
00422 plfshade1( PLF2OPS zops, PLPointer zp, PLINT nx, PLINT ny,
00423            PLINT ( *defined )( PLFLT, PLFLT ),
00424            PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax,
00425            PLFLT shade_min, PLFLT shade_max,
00426            PLINT sh_cmap, PLFLT sh_color, PLINT sh_width,
00427            PLINT min_color, PLINT min_width,
00428            PLINT max_color, PLINT max_width,
00429            void ( *fill )( PLINT, const PLFLT *, const PLFLT * ), PLINT rectangular,
00430            void ( *pltr )( PLFLT, PLFLT, PLFLT *, PLFLT *, PLPointer ),
00431            PLPointer pltr_data )
00432 {
00433     plshade_int( zops->f2eval, zp,
00434         NULL, NULL,
00435 //           plc2eval, (PLPointer) &cgrid,
00436         defined, MISSING_MIN_DEF, MISSING_MAX_DEF, nx, ny, xmin,
00437         xmax, ymin, ymax, shade_min, shade_max,
00438         sh_cmap, sh_color, sh_width,
00439         min_color, min_width, max_color, max_width,
00440         fill, rectangular, pltr, pltr_data );
00441 }
00442 
00443 //--------------------------------------------------------------------------
00444 // plshade_int()
00445 //
00446 // Shade region -- this routine does all the work
00447 //
00448 // This routine is internal so the arguments can and will change.
00449 // To retain some compatibility between versions, you must go through
00450 // some stub routine!
00451 //
00452 // 4/95
00453 //
00454 // new: missing_min, missing_max
00455 //
00456 //     if data <= missing_max and data >= missing_min
00457 //       then the data will beconsidered to be missing
00458 //     this allows 2nd way to set undefined points (good for ftn)
00459 //     if missing feature is not used, set missing_max < missing_min
00460 //
00461 // parameters:
00462 //
00463 // f2eval, f2eval_data:  data to plot
00464 // c2eval, c2eval_data:  defined mask (not implimented)
00465 // defined: defined mask (old API - implimented)
00466 // missing_min, missing_max: yet another way to set data to undefined
00467 // nx, ny: array dimensions
00468 // xmin, xmax, ymin, ymax: grid coordinates
00469 // shade_min, shade_max: shade region with values between ...
00470 // sh_cmap, sh_color, sh_width: shading parameters, width is only for hatching
00471 // min_color, min_width: line parameters for boundary (minimum)
00472 // max_color, max_width: line parameters for boundary (maximum)
00473 //     set min_width == 0 and max_width == 0 for no contours
00474 // fill: fill function, set to NULL for no shading (contour plot)
00475 // rectangular: flag set to 1 if pltr() maps rectangles to rectangles
00476 //     this helps optimize the plotting
00477 // pltr: function to map from grid to plot coordinates
00478 //
00479 //
00480 //--------------------------------------------------------------------------
00481 
00482 static void
00483 plshade_int( PLFLT ( *f2eval )( PLINT, PLINT, PLPointer ),
00484              PLPointer f2eval_data,
00485              PLFLT ( *c2eval )( PLINT, PLINT, PLPointer ),
00486              PLPointer c2eval_data,
00487              PLINT ( *defined )( PLFLT, PLFLT ),
00488              PLFLT missing_min, PLFLT missing_max,
00489              PLINT nx, PLINT ny,
00490              PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax,
00491              PLFLT shade_min, PLFLT shade_max,
00492              PLINT sh_cmap, PLFLT sh_color, PLINT sh_width,
00493              PLINT min_color, PLINT min_width,
00494              PLINT max_color, PLINT max_width,
00495              void ( *fill )( PLINT, const PLFLT *, const PLFLT * ), PLINT rectangular,
00496              void ( *pltr )( PLFLT, PLFLT, PLFLT *, PLFLT *, PLPointer ),
00497              PLPointer pltr_data )
00498 {
00499     PLINT init_width, n, slope = 0, ix, iy;
00500     int   count, i, j, nxny;
00501     PLFLT *a, *a0, *a1, dx, dy;
00502     PLFLT x[8], y[8], xp[2], tx, ty;
00503     int   *c, *c0, *c1;
00504 
00505     if ( plsc->level < 3 )
00506     {
00507         plabort( "plfshade: window must be set up first" );
00508         return;
00509     }
00510 
00511     if ( nx <= 0 || ny <= 0 )
00512     {
00513         plabort( "plfshade: nx and ny must be positive" );
00514         return;
00515     }
00516 
00517     if ( shade_min >= shade_max )
00518     {
00519         plabort( "plfshade: shade_max must exceed shade_min" );
00520         return;
00521     }
00522 
00523     if ( pltr == NULL && plsc->coordinate_transform == NULL )
00524         rectangular = 1;
00525 
00526     int_val    = shade_max - shade_min;
00527     init_width = plsc->width;
00528 
00529     pen_col_min = min_color;
00530     pen_col_max = max_color;
00531 
00532     pen_wd_min = min_width;
00533     pen_wd_max = max_width;
00534 
00535     plstyl( (PLINT) 0, NULL, NULL );
00536     plwid( sh_width );
00537     if ( fill != NULL )
00538     {
00539         switch ( sh_cmap )
00540         {
00541         case 0:
00542             plcol0( (PLINT) sh_color );
00543             break;
00544         case 1:
00545             plcol1( sh_color );
00546             break;
00547         default:
00548             plabort( "plfshade: invalid color map selection" );
00549             return;
00550         }
00551     }
00552     // alloc space for value array, and initialize
00553     // This is only a temporary kludge
00554     nxny = nx * ny;
00555     if ( ( a = (PLFLT *) malloc( nxny * sizeof ( PLFLT ) ) ) == NULL )
00556     {
00557         plabort( "plfshade: unable to allocate memory for value array" );
00558         return;
00559     }
00560 
00561     for ( ix = 0; ix < nx; ix++ )
00562         for ( iy = 0; iy < ny; iy++ )
00563             a[iy + ix * ny] = f2eval( ix, iy, f2eval_data );
00564 
00565     // alloc space for condition codes
00566 
00567     if ( ( c = (int *) malloc( nxny * sizeof ( int ) ) ) == NULL )
00568     {
00569         plabort( "plfshade: unable to allocate memory for condition codes" );
00570         free( a );
00571         return;
00572     }
00573 
00574     sh_min = shade_min;
00575     sh_max = shade_max;
00576 
00577     set_cond( c, a, nxny );
00578     dx = ( xmax - xmin ) / ( nx - 1 );
00579     dy = ( ymax - ymin ) / ( ny - 1 );
00580     a0 = a;
00581     a1 = a + ny;
00582     c0 = c;
00583     c1 = c + ny;
00584 
00585     for ( ix = 0; ix < nx - 1; ix++ )
00586     {
00587         for ( iy = 0; iy < ny - 1; iy++ )
00588         {
00589             count = c0[iy] + c0[iy + 1] + c1[iy] + c1[iy + 1];
00590 
00591             // No filling needs to be done for these cases
00592 
00593             if ( count >= UNDEF )
00594                 continue;
00595             if ( count == 4 * POS )
00596                 continue;
00597             if ( count == 4 * NEG )
00598                 continue;
00599 
00600             // Entire rectangle can be filled
00601 
00602             if ( count == 4 * OK )
00603             {
00604                 // find biggest rectangle that fits
00605                 if ( rectangular )
00606                 {
00607                     big_recl( c0 + iy, ny, nx - ix, ny - iy, &i, &j );
00608                 }
00609                 else
00610                 {
00611                     i = j = 1;
00612                 }
00613                 x[0] = x[1] = ix;
00614                 x[2] = x[3] = ix + i;
00615                 y[0] = y[3] = iy;
00616                 y[1] = y[2] = iy + j;
00617 
00618                 if ( pltr )
00619                 {
00620                     for ( i = 0; i < 4; i++ )
00621                     {
00622                         ( *pltr )( x[i], y[i], &tx, &ty, pltr_data );
00623                         x[i] = tx;
00624                         y[i] = ty;
00625                     }
00626                 }
00627                 else
00628                 {
00629                     for ( i = 0; i < 4; i++ )
00630                     {
00631                         x[i] = xmin + x[i] * dx;
00632                         y[i] = ymin + y[i] * dy;
00633                     }
00634                 }
00635                 if ( fill != NULL )
00636                     exfill( fill, defined, (PLINT) 4, x, y );
00637                 iy += j - 1;
00638                 continue;
00639             }
00640 
00641             // Only part of rectangle can be filled
00642 
00643             n_point = min_points = max_points = 0;
00644             n       = find_interval( a0[iy], a0[iy + 1], c0[iy], c0[iy + 1], xp );
00645             for ( j = 0; j < n; j++ )
00646             {
00647                 x[j] = ix;
00648                 y[j] = iy + xp[j];
00649             }
00650 
00651             i = find_interval( a0[iy + 1], a1[iy + 1],
00652                 c0[iy + 1], c1[iy + 1], xp );
00653 
00654             for ( j = 0; j < i; j++ )
00655             {
00656                 x[j + n] = ix + xp[j];
00657                 y[j + n] = iy + 1;
00658             }
00659             n += i;
00660 
00661             i = find_interval( a1[iy + 1], a1[iy], c1[iy + 1], c1[iy], xp );
00662             for ( j = 0; j < i; j++ )
00663             {
00664                 x[n + j] = ix + 1;
00665                 y[n + j] = iy + 1 - xp[j];
00666             }
00667             n += i;
00668 
00669             i = find_interval( a1[iy], a0[iy], c1[iy], c0[iy], xp );
00670             for ( j = 0; j < i; j++ )
00671             {
00672                 x[n + j] = ix + 1 - xp[j];
00673                 y[n + j] = iy;
00674             }
00675             n += i;
00676 
00677             if ( pltr )
00678             {
00679                 for ( i = 0; i < n; i++ )
00680                 {
00681                     ( *pltr )( x[i], y[i], &tx, &ty, pltr_data );
00682                     x[i] = tx;
00683                     y[i] = ty;
00684                 }
00685             }
00686             else
00687             {
00688                 for ( i = 0; i < n; i++ )
00689                 {
00690                     x[i] = xmin + x[i] * dx;
00691                     y[i] = ymin + y[i] * dy;
00692                 }
00693             }
00694 
00695             if ( min_points == 4 )
00696                 slope = plctestez( a, nx, ny, ix, iy, shade_min );
00697             if ( max_points == 4 )
00698                 slope = plctestez( a, nx, ny, ix, iy, shade_max );
00699 
00700             // n = number of end of line segments
00701             // min_points = number times shade_min meets edge
00702             // max_points = number times shade_max meets edge
00703 
00704             // special cases: check number of times a contour is in a box
00705 
00706             switch ( ( min_points << 3 ) + max_points )
00707             {
00708             case 000:
00709             case 020:
00710             case 002:
00711             case 022:
00712                 if ( fill != NULL && n > 0 )
00713                     exfill( fill, defined, n, x, y );
00714                 break;
00715             case 040:   // 2 contour lines in box
00716             case 004:
00717                 if ( n != 6 )
00718                     fprintf( stderr, "plfshade err n=%d !6", (int) n );
00719                 if ( slope == 1 && c0[iy] == OK )
00720                 {
00721                     if ( fill != NULL )
00722                         exfill( fill, defined, n, x, y );
00723                 }
00724                 else if ( slope == 1 )
00725                 {
00726                     selected_polygon( fill, defined, x, y, 0, 1, 2, -1 );
00727                     selected_polygon( fill, defined, x, y, 3, 4, 5, -1 );
00728                 }
00729                 else if ( c0[iy + 1] == OK )
00730                 {
00731                     if ( fill != NULL )
00732                         exfill( fill, defined, n, x, y );
00733                 }
00734                 else
00735                 {
00736                     selected_polygon( fill, defined, x, y, 0, 1, 5, -1 );
00737                     selected_polygon( fill, defined, x, y, 2, 3, 4, -1 );
00738                 }
00739                 break;
00740             case 044:
00741                 if ( n != 8 )
00742                     fprintf( stderr, "plfshade err n=%d !8", (int) n );
00743                 if ( slope == 1 )
00744                 {
00745                     selected_polygon( fill, defined, x, y, 0, 1, 2, 3 );
00746                     selected_polygon( fill, defined, x, y, 4, 5, 6, 7 );
00747                 }
00748                 else
00749                 {
00750                     selected_polygon( fill, defined, x, y, 0, 1, 6, 7 );
00751                     selected_polygon( fill, defined, x, y, 2, 3, 4, 5 );
00752                 }
00753                 break;
00754             case 024:
00755             case 042:
00756                 // 3 contours
00757                 if ( n != 7 )
00758                     fprintf( stderr, "plfshade err n=%d !7", (int) n );
00759 
00760                 if ( ( c0[iy] == OK || c1[iy + 1] == OK ) && slope == 1 )
00761                 {
00762                     if ( fill != NULL )
00763                         exfill( fill, defined, n, x, y );
00764                 }
00765                 else if ( ( c0[iy + 1] == OK || c1[iy] == OK ) && slope == 0 )
00766                 {
00767                     if ( fill != NULL )
00768                         exfill( fill, defined, n, x, y );
00769                 }
00770 
00771                 else if ( c0[iy] == OK )
00772                 {
00773                     selected_polygon( fill, defined, x, y, 0, 1, 6, -1 );
00774                     selected_polygon( fill, defined, x, y, 2, 3, 4, 5 );
00775                 }
00776                 else if ( c0[iy + 1] == OK )
00777                 {
00778                     selected_polygon( fill, defined, x, y, 0, 1, 2, -1 );
00779                     selected_polygon( fill, defined, x, y, 3, 4, 5, 6 );
00780                 }
00781                 else if ( c1[iy + 1] == OK )
00782                 {
00783                     selected_polygon( fill, defined, x, y, 0, 1, 5, 6 );
00784                     selected_polygon( fill, defined, x, y, 2, 3, 4, -1 );
00785                 }
00786                 else if ( c1[iy] == OK )
00787                 {
00788                     selected_polygon( fill, defined, x, y, 0, 1, 2, 3 );
00789                     selected_polygon( fill, defined, x, y, 4, 5, 6, -1 );
00790                 }
00791                 else
00792                 {
00793                     fprintf( stderr, "plfshade err logic case 024:042\n" );
00794                 }
00795                 break;
00796             default:
00797                 fprintf( stderr, "prog err switch\n" );
00798                 break;
00799             }
00800             draw_boundary( slope, x, y );
00801 
00802             if ( fill != NULL )
00803             {
00804                 plwid( sh_width );
00805                 if ( sh_cmap == 0 )
00806                     plcol0( (PLINT) sh_color );
00807                 else if ( sh_cmap == 1 )
00808                     plcol1( sh_color );
00809             }
00810         }
00811 
00812         a0  = a1;
00813         c0  = c1;
00814         a1 += ny;
00815         c1 += ny;
00816     }
00817 
00818     free( c );
00819     free( a );
00820     plwid( init_width );
00821 }
00822 
00823 //--------------------------------------------------------------------------
00824 // set_cond()
00825 //
00826 // Fills out condition code array.
00827 //--------------------------------------------------------------------------
00828 
00829 static void
00830 set_cond( register int *cond, register PLFLT *a, register PLINT n )
00831 {
00832     while ( n-- )
00833     {
00834         if ( *a < sh_min )
00835             *cond++ = NEG;
00836         else if ( *a > sh_max )
00837             *cond++ = POS;
00838         else
00839             *cond++ = OK;
00840         a++;
00841     }
00842 }
00843 
00844 //--------------------------------------------------------------------------
00845 // find_interval()
00846 //
00847 // Two points x(0) = a0, (condition code c0) x(1) = a1, (condition code c1)
00848 // return interval on the line that are shaded
00849 //
00850 // returns 0 : no points to be shaded 1 : x[0] <= x < 1 is the interval 2 :
00851 // x[0] <= x <= x[1] < 1 interval to be shaded n_point, max_points,
00852 // min_points are incremented location of min/max_points are stored
00853 //--------------------------------------------------------------------------
00854 
00855 static int
00856 find_interval( PLFLT a0, PLFLT a1, PLINT c0, PLINT c1, PLFLT *x )
00857 {
00858     register int n;
00859 
00860     n = 0;
00861     if ( c0 == OK )
00862     {
00863         x[n++] = 0.0;
00864         n_point++;
00865     }
00866     if ( c0 == c1 )
00867         return n;
00868 
00869     if ( c0 == NEG || c1 == POS )
00870     {
00871         if ( c0 == NEG )
00872         {
00873             x[n++] = linear( a0, a1, sh_min );
00874             min_pts[min_points++] = n_point++;
00875         }
00876         if ( c1 == POS )
00877         {
00878             x[n++] = linear( a0, a1, sh_max );
00879             max_pts[max_points++] = n_point++;
00880         }
00881     }
00882     if ( c0 == POS || c1 == NEG )
00883     {
00884         if ( c0 == POS )
00885         {
00886             x[n++] = linear( a0, a1, sh_max );
00887             max_pts[max_points++] = n_point++;
00888         }
00889         if ( c1 == NEG )
00890         {
00891             x[n++] = linear( a0, a1, sh_min );
00892             min_pts[min_points++] = n_point++;
00893         }
00894     }
00895     return n;
00896 }
00897 
00898 //--------------------------------------------------------------------------
00899 // selected_polygon()
00900 //
00901 // Draws a polygon from points in x[] and y[].
00902 // Point selected by v1..v4
00903 //--------------------------------------------------------------------------
00904 
00905 static void
00906 selected_polygon( void ( *fill )( PLINT, const PLFLT *, const PLFLT * ),
00907                   PLINT ( *defined )( PLFLT, PLFLT ),
00908                   const PLFLT *x, const PLFLT *y, PLINT v1, PLINT v2, PLINT v3, PLINT v4 )
00909 {
00910     register PLINT n = 0;
00911     PLFLT          xx[4], yy[4];
00912 
00913     if ( fill == NULL )
00914         return;
00915     if ( v1 >= 0 )
00916     {
00917         xx[n]   = x[v1];
00918         yy[n++] = y[v1];
00919     }
00920     if ( v2 >= 0 )
00921     {
00922         xx[n]   = x[v2];
00923         yy[n++] = y[v2];
00924     }
00925     if ( v3 >= 0 )
00926     {
00927         xx[n]   = x[v3];
00928         yy[n++] = y[v3];
00929     }
00930     if ( v4 >= 0 )
00931     {
00932         xx[n]   = x[v4];
00933         yy[n++] = y[v4];
00934     }
00935     exfill( fill, defined, n, (PLFLT *) xx, (PLFLT *) yy );
00936 }
00937 
00938 //--------------------------------------------------------------------------
00939 // bisect()
00940 //
00941 // Find boundary recursively by bisection.
00942 // (x1, y1) is in the defined region, while (x2, y2) in the undefined one.
00943 // The result is returned in
00944 //--------------------------------------------------------------------------
00945 
00946 static void
00947 bisect( PLINT ( *defined )( PLFLT, PLFLT ), PLINT niter,
00948         PLFLT x1, PLFLT y1, PLFLT x2, PLFLT y2, PLFLT* xb, PLFLT* yb )
00949 {
00950     PLFLT xm;
00951     PLFLT ym;
00952 
00953     if ( niter == 0 )
00954     {
00955         *xb = x1;
00956         *yb = y1;
00957         return;
00958     }
00959 
00960     xm = ( x1 + x2 ) / 2.;
00961     ym = ( y1 + y2 ) / 2.;
00962 
00963     if ( defined( xm, ym ) )
00964         bisect( defined, niter - 1, xm, ym, x2, y2, xb, yb );
00965     else
00966         bisect( defined, niter - 1, x1, y1, xm, ym, xb, yb );
00967 }
00968 
00969 //--------------------------------------------------------------------------
00970 // exfill()
00971 //
00972 // Fills a polygon from points in x[] and y[] with all points in
00973 // undefined regions dropped and replaced by points at the bisected
00974 // edge of the defined region.
00975 // Note, undefined regions that are confined to the areas between polygon
00976 // points are completely ignored.  Also, a range of undefined polygon points
00977 // are simply replaced with a straight line with accurately bisected end
00978 // points.  So this routine can produce problematic plotted results
00979 // if the polygon is not a lot smaller than the typical resolution of
00980 // the defined region.
00981 //--------------------------------------------------------------------------
00982 
00983 static void
00984 exfill( void ( *fill )( PLINT, const PLFLT *, const PLFLT * ),
00985         PLINT ( *defined )( PLFLT, PLFLT ),
00986         int n, const PLFLT *x, const PLFLT *y )
00987 {
00988     if ( n < 3 )
00989     {
00990         plabort( "exfill: Not enough points in object" );
00991         return;
00992     }
00993 
00994     if ( defined == NULL )
00995 
00996         ( *fill )( n, x, y );
00997 
00998     else
00999     {
01000         PLFLT *xx;
01001         PLFLT *yy;
01002         PLFLT xb, yb;
01003         PLINT count      = 0;
01004         PLINT im1        = n - 1;
01005         PLINT is_defined = defined( x[im1], y[im1] );
01006         PLINT i;
01007 
01008         // Slightly less than 2 n points are required for xx, yy, but
01009         // allocate room for 2 n to be safe.
01010         if ( ( xx = (PLFLT *) malloc( 2 * n * sizeof ( PLFLT ) ) ) == NULL )
01011             plexit( "exfill: out of memory for xx" );
01012         if ( ( yy = (PLFLT *) malloc( 2 * n * sizeof ( PLFLT ) ) ) == NULL )
01013             plexit( "exfill: out of memory for yy." );
01014 
01015         for ( i = 0; i < n; i++ )
01016         {
01017             // is_defined tells whether im1 point was in defined region.
01018             if ( defined( x[i], y[i] ) )
01019             {
01020                 if ( !is_defined )
01021                 {
01022                     // Cross from undefined (at im1) to defined region.
01023                     // Bisect for the first point inside the defined region
01024                     // and add it to xx, yy.
01025                     bisect( defined, NUMBER_BISECTIONS,
01026                         x[i], y[i], x[im1], y[im1], &xb, &yb );
01027                     xx[count]   = xb;
01028                     yy[count++] = yb;
01029                 }
01030                 // x[i], y[i] known to be in defined region so add this
01031                 // point to xx, yy.
01032                 xx[count]   = x[i];
01033                 yy[count++] = y[i];
01034                 is_defined  = 1;
01035             }
01036             else
01037             {
01038                 if ( is_defined )
01039                 {
01040                     // Cross from defined (at im1) to undefined region.
01041                     // Bisect for the last point in the defined region and
01042                     // add it to xx, yy.
01043                     bisect( defined, NUMBER_BISECTIONS,
01044                         x[im1], y[im1], x[i], y[i], &xb, &yb );
01045                     xx[count]   = xb;
01046                     yy[count++] = yb;
01047                     is_defined  = 0;
01048                 }
01049             }
01050             im1 = i;
01051         }
01052 
01053         if ( count >= 3 )
01054             ( *fill )( count, (const PLFLT *) xx, (const PLFLT *) yy );
01055 
01056         free( xx );
01057         free( yy );
01058     }
01059 }
01060 
01061 //--------------------------------------------------------------------------
01062 // big_recl()
01063 //
01064 // find a big rectangle for shading
01065 //
01066 // 2 goals: minimize calls to (*fill)()
01067 //  keep ratio 1:3 for biggest rectangle
01068 //
01069 // only called by plshade()
01070 //
01071 // assumed that a 1 x 1 square already fits
01072 //
01073 // c[] = condition codes
01074 // ny = c[1][0] == c[ny]  (you know what I mean)
01075 //
01076 // returns ix, iy = length of rectangle in grid units
01077 //
01078 // ix < dx - 1
01079 // iy < dy - 1
01080 //
01081 // If iy == 1 -> ix = 1 (so that cond code can be set to skip)
01082 //--------------------------------------------------------------------------
01083 
01084 #define RATIO    3
01085 #define COND( x, y )    cond_code[x * ny + y]
01086 
01087 static void
01088 big_recl( int *cond_code, register int ny, int dx, int dy,
01089           int *ix, int *iy )
01090 {
01091     int          ok_x, ok_y, j;
01092     register int i, x, y;
01093     register int *cond;
01094 
01095     // ok_x = ok to expand in x direction
01096     // x = current number of points in x direction
01097 
01098     ok_x = ok_y = 1;
01099     x    = y = 2;
01100 
01101     while ( ok_x || ok_y )
01102     {
01103 #ifdef RATIO
01104         if ( RATIO * x <= y || RATIO * y <= x )
01105             break;
01106 #endif
01107         if ( ok_y )
01108         {
01109             // expand in vertical
01110             ok_y = 0;
01111             if ( y == dy )
01112                 continue;
01113             cond = &COND( 0, y );
01114             for ( i = 0; i < x; i++ )
01115             {
01116                 if ( *cond != OK )
01117                     break;
01118                 cond += ny;
01119             }
01120             if ( i == x )
01121             {
01122                 // row is ok
01123                 y++;
01124                 ok_y = 1;
01125             }
01126         }
01127         if ( ok_x )
01128         {
01129             if ( y == 2 )
01130                 break;
01131             // expand in x direction
01132             ok_x = 0;
01133             if ( x == dx )
01134                 continue;
01135             cond = &COND( x, 0 );
01136             for ( i = 0; i < y; i++ )
01137             {
01138                 if ( *cond++ != OK )
01139                     break;
01140             }
01141             if ( i == y )
01142             {
01143                 // column is OK
01144                 x++;
01145                 ok_x = 1;
01146             }
01147         }
01148     }
01149 
01150     // found the largest rectangle of 'ix' by 'iy'
01151     *ix = --x;
01152     *iy = --y;
01153 
01154     // set condition code to UNDEF in interior of rectangle
01155 
01156     for ( i = 1; i < x; i++ )
01157     {
01158         cond = &COND( i, 1 );
01159         for ( j = 1; j < y; j++ )
01160         {
01161             *cond++ = UNDEF;
01162         }
01163     }
01164 }
01165 
01166 //--------------------------------------------------------------------------
01167 // draw_boundary()
01168 //
01169 // Draw boundaries of contour regions based on min_pts[], and max_pts[].
01170 //--------------------------------------------------------------------------
01171 
01172 static void
01173 draw_boundary( PLINT slope, PLFLT *x, PLFLT *y )
01174 {
01175     int i;
01176 
01177     if ( pen_col_min != 0 && pen_wd_min != 0 && min_points != 0 )
01178     {
01179         plcol0( pen_col_min );
01180         plwid( pen_wd_min );
01181         if ( min_points == 4 && slope == 0 )
01182         {
01183             // swap points 1 and 3
01184             i          = min_pts[1];
01185             min_pts[1] = min_pts[3];
01186             min_pts[3] = i;
01187         }
01188         pljoin( x[min_pts[0]], y[min_pts[0]], x[min_pts[1]], y[min_pts[1]] );
01189         if ( min_points == 4 )
01190         {
01191             pljoin( x[min_pts[2]], y[min_pts[2]], x[min_pts[3]],
01192                 y[min_pts[3]] );
01193         }
01194     }
01195     if ( pen_col_max != 0 && pen_wd_max != 0 && max_points != 0 )
01196     {
01197         plcol0( pen_col_max );
01198         plwid( pen_wd_max );
01199         if ( max_points == 4 && slope == 0 )
01200         {
01201             // swap points 1 and 3
01202             i          = max_pts[1];
01203             max_pts[1] = max_pts[3];
01204             max_pts[3] = i;
01205         }
01206         pljoin( x[max_pts[0]], y[max_pts[0]], x[max_pts[1]], y[max_pts[1]] );
01207         if ( max_points == 4 )
01208         {
01209             pljoin( x[max_pts[2]], y[max_pts[2]], x[max_pts[3]],
01210                 y[max_pts[3]] );
01211         }
01212     }
01213 }
01214 
01215 //--------------------------------------------------------------------------
01216 //
01217 // plctest( &(x[0][0]), PLFLT level)
01218 // where x was defined as PLFLT x[4][4];
01219 //
01220 // determines if the contours associated with level have
01221 // positive slope or negative slope in the box:
01222 //
01223 //  (2,3)   (3,3)
01224 //
01225 //  (2,2)   (3,2)
01226 //
01227 // this is heuristic and can be changed by the user
01228 //
01229 // return 1 if positive slope
01230 //        0 if negative slope
01231 //
01232 // algorithmn:
01233 //      1st test:
01234 //      find length of contours assuming positive and negative slopes
01235 //      if the length of the negative slope contours is much bigger
01236 //      than the positive slope, then the slope is positive.
01237 //      (and vice versa)
01238 //      (this test tries to minimize the length of contours)
01239 //
01240 //      2nd test:
01241 //      if abs((top-right corner) - (bottom left corner)) >
01242 //         abs((top-left corner) - (bottom right corner)) ) then
01243 //              return negatiave slope.
01244 //      (this test tries to keep the slope for different contour levels
01245 //      the same)
01246 //--------------------------------------------------------------------------
01247 
01248 #define X( a, b )    ( x[a * 4 + b] )
01249 #define POSITIVE_SLOPE    (PLINT) 1
01250 #define NEGATIVE_SLOPE    (PLINT) 0
01251 #define RATIO_SQ          6.0
01252 
01253 static PLINT
01254 plctest( PLFLT *x, PLFLT level )
01255 {
01256     int    i, j;
01257     double t[4], sorted[4], temp;
01258 
01259     sorted[0] = t[0] = X( 1, 1 );
01260     sorted[1] = t[1] = X( 2, 2 );
01261     sorted[2] = t[2] = X( 1, 2 );
01262     sorted[3] = t[3] = X( 2, 1 );
01263 
01264     for ( j = 1; j < 4; j++ )
01265     {
01266         temp = sorted[j];
01267         i    = j - 1;
01268         while ( i >= 0 && sorted[i] > temp )
01269         {
01270             sorted[i + 1] = sorted[i];
01271             i--;
01272         }
01273         sorted[i + 1] = temp;
01274     }
01275     // sorted[0] == min
01276 
01277     // find min contour
01278     temp = int_val * ceil( sorted[0] / int_val );
01279     if ( temp < sorted[1] )
01280     {
01281         // one contour line
01282         for ( i = 0; i < 4; i++ )
01283         {
01284             if ( t[i] < temp )
01285                 return i / 2;
01286         }
01287     }
01288 
01289     // find max contour
01290     temp = int_val * floor( sorted[3] / int_val );
01291     if ( temp > sorted[2] )
01292     {
01293         // one contour line
01294         for ( i = 0; i < 4; i++ )
01295         {
01296             if ( t[i] > temp )
01297                 return i / 2;
01298         }
01299     }
01300     // nothing better to do - be consistant
01301     return POSITIVE_SLOPE;
01302 }
01303 
01304 //--------------------------------------------------------------------------
01305 // plctestez
01306 //
01307 // second routine - easier to use
01308 // fills in x[4][4] and calls plctest
01309 //
01310 // test location a[ix][iy] (lower left corner)
01311 //--------------------------------------------------------------------------
01312 
01313 static PLINT
01314 plctestez( PLFLT *a, PLINT nx, PLINT ny, PLINT ix,
01315            PLINT iy, PLFLT level )
01316 {
01317     PLFLT x[4][4];
01318     int   i, j, ii, jj;
01319 
01320     for ( i = 0; i < 4; i++ )
01321     {
01322         ii = ix + i - 1;
01323         ii = MAX( 0, ii );
01324         ii = MIN( ii, nx - 1 );
01325         for ( j = 0; j < 4; j++ )
01326         {
01327             jj      = iy + j - 1;
01328             jj      = MAX( 0, jj );
01329             jj      = MIN( jj, ny - 1 );
01330             x[i][j] = a[ii * ny + jj];
01331         }
01332     }
01333     return plctest( &( x[0][0] ), level );
01334 }

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