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

plot3d.c

Go to the documentation of this file.
00001 // $Id: plot3d.c 11760 2011-06-01 19:29:11Z airwin $
00002 //
00007 // Copyright (C) 2004  Alan W. Irwin
00008 // Copyright (C) 2004  Joao Cardoso
00009 // Copyright (C) 2004  Andrew Ross
00010 //
00011 // This file is part of PLplot.
00012 //
00013 // PLplot is free software; you can redistribute it and/or modify
00014 // it under the terms of the GNU Library General Public License as published
00015 // by the Free Software Foundation; either version 2 of the License, or
00016 // (at your option) any later version.
00017 //
00018 // PLplot is distributed in the hope that it will be useful,
00019 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00020 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021 // GNU Library General Public License for more details.
00022 //
00023 // You should have received a copy of the GNU Library General Public License
00024 // along with PLplot; if not, write to the Free Software
00025 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00026 //
00027 
00028 #include "plplotP.h"
00029 
00030 // Internal constants
00031 
00032 #define  BINC    50             // Block size for memory allocation
00033 
00034 static PLINT pl3mode = 0;       // 0 3d solid; 1 mesh plot
00035 static PLINT pl3upv  = 1;       // 1 update view; 0 no update
00036 
00037 static PLINT zbflg = 0, zbcol, zbwidth;
00038 static PLFLT zbtck;
00039 
00040 static PLINT *oldhiview = NULL;
00041 static PLINT *oldloview = NULL;
00042 static PLINT *newhiview = NULL;
00043 static PLINT *newloview = NULL;
00044 static PLINT *utmp      = NULL;
00045 static PLINT *vtmp      = NULL;
00046 static PLFLT *ctmp      = NULL;
00047 
00048 static PLINT mhi, xxhi, newhisize;
00049 static PLINT mlo, xxlo, newlosize;
00050 
00051 // Light source for shading
00052 static PLFLT xlight, ylight, zlight;
00053 static PLINT falsecolor = 0;
00054 static PLFLT fc_minz, fc_maxz;
00055 
00056 // Prototypes for static functions
00057 
00058 static void plgrid3( PLFLT );
00059 static void plnxtv( PLINT *, PLINT *, PLFLT*, PLINT, PLINT );
00060 static void plside3( PLFLT *, PLFLT *, PLF2OPS, PLPointer, PLINT, PLINT, PLINT );
00061 static void plt3zz( PLINT, PLINT, PLINT, PLINT,
00062                     PLINT, PLINT *, PLFLT *, PLFLT *, PLF2OPS, PLPointer,
00063                     PLINT, PLINT, PLINT *, PLINT *, PLFLT* );
00064 static void plnxtvhi( PLINT *, PLINT *, PLFLT*, PLINT, PLINT );
00065 static void plnxtvlo( PLINT *, PLINT *, PLFLT*, PLINT, PLINT );
00066 static void plnxtvhi_draw( PLINT *u, PLINT *v, PLFLT* c, PLINT n );
00067 
00068 static void savehipoint( PLINT, PLINT );
00069 static void savelopoint( PLINT, PLINT );
00070 static void swaphiview( void );
00071 static void swaploview( void );
00072 static void myexit( char * );
00073 static void myabort( char * );
00074 static void freework( void );
00075 static int  plabv( PLINT, PLINT, PLINT, PLINT, PLINT, PLINT );
00076 static void pl3cut( PLINT, PLINT, PLINT, PLINT, PLINT,
00077                     PLINT, PLINT, PLINT, PLINT *, PLINT * );
00078 static PLFLT plGetAngleToLight( PLFLT* x, PLFLT* y, PLFLT* z );
00079 static void plP_draw3d( PLINT x, PLINT y, PLFLT *c, PLINT j, PLINT move );
00080 static void plxyindexlimits( PLINT instart, PLINT inn,
00081                              PLINT *inarray_min, PLINT *inarray_max,
00082                              PLINT *outstart, PLINT *outn, PLINT outnmax,
00083                              PLINT *outarray_min, PLINT *outarray_max );
00084 
00085 
00086 // #define MJL_HACK 1
00087 #if MJL_HACK
00088 static void plP_fill3( PLINT x0, PLINT y0, PLINT x1, PLINT y1,
00089                        PLINT x2, PLINT y2, PLINT j );
00090 static void plP_fill4( PLINT x0, PLINT y0, PLINT x1, PLINT y1,
00091                        PLINT x2, PLINT y2, PLINT x3, PLINT y3, PLINT j );
00092 #endif
00093 
00094 //--------------------------------------------------------------------------
00095 // void plsetlightsource(x, y, z)
00096 //
00097 // Sets the position of the light source.
00098 //--------------------------------------------------------------------------
00099 
00100 void
00101 c_pllightsource( PLFLT x, PLFLT y, PLFLT z )
00102 {
00103     xlight = x;
00104     ylight = y;
00105     zlight = z;
00106 }
00107 
00108 //--------------------------------------------------------------------------
00109 // void plmesh(x, y, z, nx, ny, opt)
00110 //
00111 // Plots a mesh representation of the function z[x][y]. The x values
00112 // are stored as x[0..nx-1], the y values as y[0..ny-1], and the
00113 // z values are in the 2-d array z[][]. The integer "opt" specifies:
00114 // see plmeshc() below.
00115 //--------------------------------------------------------------------------
00116 
00117 void
00118 c_plmesh( const PLFLT *x, const PLFLT *y, const PLFLT **z, PLINT nx, PLINT ny, PLINT opt )
00119 {
00120     plfplot3dc( x, y, plf2ops_c(), (PLPointer) z, nx, ny, opt | MESH, NULL, 0 );
00121 }
00122 
00123 void
00124 plfmesh( const PLFLT *x, const PLFLT *y, PLF2OPS zops, PLPointer zp,
00125          PLINT nx, PLINT ny, PLINT opt )
00126 {
00127     plfplot3dc( x, y, zops, zp, nx, ny, opt | MESH, NULL, 0 );
00128 }
00129 
00130 //--------------------------------------------------------------------------
00131 // void plmeshc(x, y, z, nx, ny, opt, clevel, nlevel)
00132 //
00133 // Plots a mesh representation of the function z[x][y]. The x values
00134 // are stored as x[0..nx-1], the y values as y[0..ny-1], and the
00135 // z values are in the 2-d array z[][]. The integer "opt" specifies:
00136 //
00137 // DRAW_LINEX   draw lines parallel to the X axis
00138 // DRAW_LINEY   draw lines parallel to the Y axis
00139 // DRAW_LINEXY  draw lines parallel to both the X and Y axis
00140 // MAG_COLOR    draw the mesh with a color dependent of the magnitude
00141 // BASE_CONT    draw contour plot at bottom xy plane
00142 // TOP_CONT     draw contour plot at top xy plane (not yet)
00143 // DRAW_SIDES   draw sides
00144 //
00145 // or any bitwise combination, e.g. "MAG_COLOR | DRAW_LINEX"
00146 //
00147 //--------------------------------------------------------------------------
00148 
00149 void
00150 c_plmeshc( const PLFLT *x, const PLFLT *y, const PLFLT **z, PLINT nx, PLINT ny, PLINT opt,
00151            const PLFLT *clevel, PLINT nlevel )
00152 {
00153     plfplot3dc( x, y, plf2ops_c(), (PLPointer) z, nx, ny, opt | MESH, clevel, nlevel );
00154 }
00155 
00156 void
00157 plfmeshc( const PLFLT *x, const PLFLT *y, PLF2OPS zops, PLPointer zp,
00158           PLINT nx, PLINT ny, PLINT opt, const PLFLT *clevel, PLINT nlevel )
00159 {
00160     plfplot3dc( x, y, zops, zp, nx, ny, opt | MESH, clevel, nlevel );
00161 }
00162 
00163 // clipping helper for 3d polygons
00164 
00165 int
00166 plP_clip_poly( int Ni, PLFLT *Vi[3], int axis, PLFLT dir, PLFLT offset )
00167 {
00168     int   anyout = 0;
00169     PLFLT _in[PL_MAXPOLY], _T[3][PL_MAXPOLY];
00170     PLFLT *in, *T[3], *TT;
00171     int   No = 0;
00172     int   i, j, k;
00173 
00174     if ( Ni > PL_MAXPOLY )
00175     {
00176         in = (PLFLT *) malloc( sizeof ( PLFLT ) * Ni );
00177         TT = (PLFLT *) malloc( 3 * sizeof ( PLFLT ) * Ni );
00178 
00179         if ( in == NULL || TT == NULL )
00180         {
00181             plexit( "plP_clip_poly: insufficient memory for large polygon" );
00182         }
00183 
00184         T[0] = &TT[0];
00185         T[1] = &TT[Ni];
00186         T[2] = &TT[2 * Ni];
00187     }
00188     else
00189     {
00190         in   = _in;
00191         T[0] = &_T[0][0];
00192         T[1] = &_T[1][0];
00193         T[2] = &_T[2][0];
00194     }
00195 
00196     for ( i = 0; i < Ni; i++ )
00197     {
00198         in[i]   = Vi[axis][i] * dir + offset;
00199         anyout += in[i] < 0;
00200     }
00201 
00202     // none out
00203     if ( anyout == 0 )
00204         return Ni;
00205 
00206     // all out
00207     if ( anyout == Ni )
00208     {
00209         return 0;
00210     }
00211 
00212     // some out
00213     // copy over to a temp vector
00214     for ( i = 0; i < 3; i++ )
00215     {
00216         for ( j = 0; j < Ni; j++ )
00217         {
00218             T[i][j] = Vi[i][j];
00219         }
00220     }
00221     // copy back selectively
00222     for ( i = 0; i < Ni; i++ )
00223     {
00224         j = ( i + 1 ) % Ni;
00225 
00226         if ( in[i] >= 0 && in[j] >= 0 )
00227         {
00228             for ( k = 0; k < 3; k++ )
00229                 Vi[k][No] = T[k][j];
00230             No++;
00231         }
00232         else if ( in[i] >= 0 && in[j] < 0 )
00233         {
00234             PLFLT u = in[i] / ( in[i] - in[j] );
00235             for ( k = 0; k < 3; k++ )
00236                 Vi[k][No] = T[k][i] * ( 1 - u ) + T[k][j] * u;
00237             No++;
00238         }
00239         else if ( in[i] < 0 && in[j] >= 0 )
00240         {
00241             PLFLT u = in[i] / ( in[i] - in[j] );
00242             for ( k = 0; k < 3; k++ )
00243                 Vi[k][No] = T[k][i] * ( 1 - u ) + T[k][j] * u;
00244             No++;
00245             for ( k = 0; k < 3; k++ )
00246                 Vi[k][No] = T[k][j];
00247             No++;
00248         }
00249     }
00250 
00251     if ( Ni > PL_MAXPOLY )
00252     {
00253         free( in );
00254         free( TT );
00255     }
00256 
00257     return No;
00258 }
00259 
00260 // helper for plsurf3d, similar to c_plfill3()
00261 static void
00262 shade_triangle( PLFLT x0, PLFLT y0, PLFLT z0,
00263                 PLFLT x1, PLFLT y1, PLFLT z1,
00264                 PLFLT x2, PLFLT y2, PLFLT z2 )
00265 {
00266     int   i;
00267     // arrays for interface to core functions
00268     short u[6], v[6];
00269     PLFLT x[6], y[6], z[6];
00270     int   n;
00271     PLFLT xmin, xmax, ymin, ymax, zmin, zmax, zscale;
00272     PLFLT *V[3];
00273 
00274     plP_gdom( &xmin, &xmax, &ymin, &ymax );
00275     plP_grange( &zscale, &zmin, &zmax );
00276 
00277     x[0] = x0; x[1] = x1; x[2] = x2;
00278     y[0] = y0; y[1] = y1; y[2] = y2;
00279     z[0] = z0; z[1] = z1; z[2] = z2;
00280     n    = 3;
00281 
00282     V[0] = x; V[1] = y; V[2] = z;
00283 
00284     n = plP_clip_poly( n, V, 0, 1, -xmin );
00285     n = plP_clip_poly( n, V, 0, -1, xmax );
00286     n = plP_clip_poly( n, V, 1, 1, -ymin );
00287     n = plP_clip_poly( n, V, 1, -1, ymax );
00288     n = plP_clip_poly( n, V, 2, 1, -zmin );
00289     n = plP_clip_poly( n, V, 2, -1, zmax );
00290 
00291     if ( n > 0 )
00292     {
00293         if ( falsecolor )
00294             plcol1( ( ( z[0] + z[1] + z[2] ) / 3. - fc_minz ) / ( fc_maxz - fc_minz ) );
00295         else
00296             plcol1( plGetAngleToLight( x, y, z ) );
00297 
00298         for ( i = 0; i < n; i++ )
00299         {
00300             u[i] = plP_wcpcx( plP_w3wcx( x[i], y[i], z[i] ) );
00301             v[i] = plP_wcpcy( plP_w3wcy( x[i], y[i], z[i] ) );
00302         }
00303         u[n] = u[0];
00304         v[n] = v[0];
00305 
00306 #ifdef SHADE_DEBUG // show triangles
00307         plcol0( 1 );
00308         x[3] = x[0]; y[3] = y[0]; z[3] = z[0];
00309         plline3( 4, x, y, z );
00310 #else   // fill triangles
00311         plP_fill( u, v, n + 1 );
00312 #endif
00313     }
00314 }
00315 
00316 //--------------------------------------------------------------------------
00317 // void plsurf3d(x, y, z, nx, ny, opt, clevel, nlevel)
00318 //
00319 // Plots the 3-d surface representation of the function z[x][y].
00320 // The x values are stored as x[0..nx-1], the y values as y[0..ny-1],
00321 //  and the z values are in the 2-d array z[][].  The integer "opt" specifies:
00322 // see plsurf3dl() below.
00323 //--------------------------------------------------------------------------
00324 
00325 void
00326 c_plsurf3d( const PLFLT *x, const PLFLT *y, const PLFLT **z, PLINT nx, PLINT ny,
00327             PLINT opt, const PLFLT *clevel, PLINT nlevel )
00328 {
00329     plfsurf3d( x, y, plf2ops_c(), (PLPointer) z, nx, ny,
00330         opt, clevel, nlevel );
00331 }
00332 
00333 void
00334 plfsurf3d( const PLFLT *x, const PLFLT *y, PLF2OPS zops, PLPointer zp,
00335            PLINT nx, PLINT ny, PLINT opt, const PLFLT *clevel, PLINT nlevel )
00336 {
00337     PLINT i;
00338     PLINT *indexymin = (PLINT *) malloc( (size_t) ( nx * sizeof ( PLINT ) ) );
00339     PLINT *indexymax = (PLINT *) malloc( (size_t) ( nx * sizeof ( PLINT ) ) );
00340 
00341     if ( !indexymin || !indexymax )
00342         plexit( "plsurf3d: Out of memory." );
00343     for ( i = 0; i < nx; i++ )
00344     {
00345         indexymin[i] = 0;
00346         indexymax[i] = ny;
00347     }
00348     plfsurf3dl( x, y, zops, zp, nx, ny, opt, clevel, nlevel,
00349         0, nx, indexymin, indexymax );
00350     free_mem( indexymin );
00351     free_mem( indexymax );
00352 }
00353 
00354 //--------------------------------------------------------------------------
00355 // void plsurf3dl(x, y, z, nx, ny, opt, clevel, nlevel,
00356 // ixstart, ixn, indexymin, indexymax)
00357 //
00358 // Plots the 3-d surface representation of the function z[x][y].
00359 // The x values are stored as x[0..nx-1], the y values as y[0..ny-1],
00360 //  and the z values are in the 2-d array z[][].
00361 //
00362 //
00363 // BASE_CONT    draw contour plot at bottom xy plane
00364 // TOP_CONT     draw contour plot at top xy plane (not implemented)
00365 // SURF_CONT    draw contour at surface
00366 // FACETED      each square that makes up the surface is faceted
00367 // DRAW_SIDES   draw sides
00368 // MAG_COLOR    the surface is colored according to the value of z;
00369 //               if not defined, the surface is colored according to the
00370 //               intensity of the reflected light in the surface from a light
00371 //               source whose position is set using c_pllightsource()
00372 //
00373 // or any bitwise combination, e.g. "MAG_COLOR | SURF_CONT | SURF_BASE"
00374 //
00375 // indexymin and indexymax are arrays which specify the y index range
00376 // (following the convention that the upper range limit is one more than
00377 // actual index limit) for an x index range of ixstart, ixn.
00378 // This code is a complete departure from the approach taken in the old version
00379 // of this routine. Formerly to code attempted to use the logic for the hidden
00380 // line algorithm to draw the hidden surface. This was really hard. This code
00381 // below uses a simple back to front (painters) algorithm. All the
00382 // triangles are drawn.
00383 //
00384 // There are multitude of ways this code could be optimized. Given the
00385 // problems with the old code, I tried to focus on clarity here.
00386 //--------------------------------------------------------------------------
00387 
00388 void
00389 c_plsurf3dl( const PLFLT *x, const PLFLT *y, const PLFLT **z, PLINT nx, PLINT ny,
00390              PLINT opt, const PLFLT *clevel, PLINT nlevel,
00391              PLINT ixstart, PLINT ixn, const PLINT *indexymin, const PLINT *indexymax )
00392 {
00393     plfsurf3dl( x, y, plf2ops_c(), (PLPointer) z, nx, ny,
00394         opt, clevel, nlevel, ixstart, ixn, indexymin, indexymax );
00395 }
00396 
00397 void
00398 plfsurf3dl( const PLFLT *x, const PLFLT *y, PLF2OPS zops, PLPointer zp, PLINT nx, PLINT ny,
00399             PLINT opt, const PLFLT *clevel, PLINT nlevel,
00400             PLINT ixstart, PLINT ixn, const PLINT *indexymin, const PLINT *indexymax )
00401 {
00402     PLFLT      cxx, cxy, cyx, cyy, cyz;
00403     PLINT      i, j, k;
00404     PLINT      ixDir, ixOrigin, iyDir, iyOrigin, nFast, nSlow;
00405     PLINT      ixFast, ixSlow, iyFast, iySlow;
00406     PLINT      iFast, iSlow;
00407     PLFLT      xmin, xmax, ymin, ymax, zmin, zmax, zscale;
00408     PLFLT      xm, ym, zm;
00409     PLINT      ixmin = 0, ixmax = nx, iymin = 0, iymax = ny;
00410     PLFLT      xx[3], yy[3], zz[3];
00411     PLFLT      px[4], py[4], pz[4];
00412     CONT_LEVEL *cont, *clev;
00413     CONT_LINE  *cline;
00414     int        ct, ix, iy, iftriangle;
00415     PLINT      color = plsc->icol0, width = plsc->width;
00416     PLFLT      ( *getz )( PLPointer, PLINT, PLINT ) = zops->get;
00417 
00418     if ( plsc->level < 3 )
00419     {
00420         myabort( "plsurf3dl: Please set up window first" );
00421         return;
00422     }
00423 
00424     if ( nx <= 0 || ny <= 0 )
00425     {
00426         myabort( "plsurf3dl: Bad array dimensions." );
00427         return;
00428     }
00429 
00430     //
00431     // Don't use the data z value to scale the color, use the z axis
00432     // values set by plw3d()
00433     //
00434     // plMinMax2dGrid(z, nx, ny, &fc_maxz, &fc_minz);
00435     //
00436 
00437     fc_minz = plsc->ranmi;
00438     fc_maxz = plsc->ranma;
00439     if ( fc_maxz == fc_minz )
00440     {
00441         plwarn( "plsurf3dl: Maximum and minimum Z values are equal! \"fixing\"..." );
00442         fc_maxz = fc_minz + 1e-6;
00443     }
00444 
00445     if ( opt & MAG_COLOR )
00446         falsecolor = 1;
00447     else
00448         falsecolor = 0;
00449 
00450     plP_gdom( &xmin, &xmax, &ymin, &ymax );
00451     plP_grange( &zscale, &zmin, &zmax );
00452     if ( zmin > zmax )
00453     {
00454         PLFLT t = zmin;
00455         zmin = zmax;
00456         zmax = t;
00457     }
00458 
00459     // Check that points in x and in y are strictly increasing  and in range
00460 
00461     for ( i = 0; i < nx - 1; i++ )
00462     {
00463         if ( x[i] >= x[i + 1] )
00464         {
00465             myabort( "plsurf3dl: X array must be strictly increasing" );
00466             return;
00467         }
00468         if ( x[i] < xmin && x[i + 1] >= xmin )
00469             ixmin = i;
00470         if ( x[i + 1] > xmax && x[i] <= xmax )
00471             ixmax = i + 2;
00472     }
00473     for ( i = 0; i < ny - 1; i++ )
00474     {
00475         if ( y[i] >= y[i + 1] )
00476         {
00477             myabort( "plsurf3dl: Y array must be strictly increasing" );
00478             return;
00479         }
00480         if ( y[i] < ymin && y[i + 1] >= ymin )
00481             iymin = i;
00482         if ( y[i + 1] > ymax && y[i] <= ymax )
00483             iymax = i + 2;
00484     }
00485 
00486     // get the viewing parameters
00487     plP_gw3wc( &cxx, &cxy, &cyx, &cyy, &cyz );
00488 
00489     // we're going to draw from back to front
00490 
00491     // iFast will index the dominant (fastest changing) dimension
00492     // iSlow will index the slower changing dimension
00493     //
00494     // iX indexes the X dimension
00495     // iY indexes the Y dimension
00496 
00497     // get direction for X
00498     if ( cxy >= 0 )
00499     {
00500         ixDir    = 1;     // direction in X
00501         ixOrigin = ixmin; // starting point
00502     }
00503     else
00504     {
00505         ixDir    = -1;
00506         ixOrigin = ixmax - 1;
00507     }
00508     // get direction for Y
00509     if ( cxx >= 0 )
00510     {
00511         iyDir    = -1;
00512         iyOrigin = iymax - 1;
00513     }
00514     else
00515     {
00516         iyDir    = 1;
00517         iyOrigin = iymin;
00518     }
00519     // figure out which dimension is dominant
00520     if ( fabs( cxx ) > fabs( cxy ) )
00521     {
00522         // X is dominant
00523         nFast = ixmax - ixmin;  // samples in the Fast direction
00524         nSlow = iymax - iymin;  // samples in the Slow direction
00525 
00526         ixFast = ixDir; ixSlow = 0;
00527         iyFast = 0;     iySlow = iyDir;
00528     }
00529     else
00530     {
00531         nFast = iymax - iymin;
00532         nSlow = ixmax - ixmin;
00533 
00534         ixFast = 0;     ixSlow = ixDir;
00535         iyFast = iyDir; iySlow = 0;
00536     }
00537 
00538     // we've got to draw the background grid first, hidden line code has to draw it last
00539     if ( zbflg )
00540     {
00541         PLFLT bx[3], by[3], bz[3];
00542         PLFLT tick = zbtck, tp;
00543         PLINT nsub = 0;
00544 
00545         // get the tick spacing
00546         pldtik( zmin, zmax, &tick, &nsub, FALSE );
00547 
00548         // determine the vertices for the background grid line
00549         bx[0] = ( ixOrigin != ixmin && ixFast == 0 ) || ixFast > 0 ? xmax : xmin;
00550         by[0] = ( iyOrigin != iymin && iyFast == 0 ) || iyFast > 0 ? ymax : ymin;
00551         bx[1] = ixOrigin != ixmin ? xmax : xmin;
00552         by[1] = iyOrigin != iymin ? ymax : ymin;
00553         bx[2] = ( ixOrigin != ixmin && ixSlow == 0 ) || ixSlow > 0 ? xmax : xmin;
00554         by[2] = ( iyOrigin != iymin && iySlow == 0 ) || iySlow > 0 ? ymax : ymin;
00555 
00556         plwid( zbwidth );
00557         plcol0( zbcol );
00558         for ( tp = tick * floor( zmin / tick ) + tick; tp <= zmax; tp += tick )
00559         {
00560             bz[0] = bz[1] = bz[2] = tp;
00561             plline3( 3, bx, by, bz );
00562         }
00563         // draw the vertical line at the back corner
00564         bx[0] = bx[1];
00565         by[0] = by[1];
00566         bz[0] = zmin;
00567         plline3( 2, bx, by, bz );
00568         plwid( width );
00569         plcol0( color );
00570     }
00571 
00572     // If enabled, draw the contour at the base
00573 
00574     // The contour plotted at the base will be identical to the one obtained
00575     // with c_plcont(). The contour plotted at the surface is simple minded, but
00576     // can be improved by using the contour data available.
00577     //
00578 
00579     if ( clevel != NULL && opt & BASE_CONT )
00580     {
00581 #define NPTS    100
00582         int      np = NPTS;
00583         PLFLT    **zstore;
00584         PLcGrid2 cgrid2;
00585         PLFLT    *zz = (PLFLT *) malloc( NPTS * sizeof ( PLFLT ) );
00586         if ( zz == NULL )
00587             plexit( "plsurf3dl: Insufficient memory" );
00588 
00589         // get the contour lines
00590 
00591         // prepare cont_store input
00592         cgrid2.nx = nx;
00593         cgrid2.ny = ny;
00594         plAlloc2dGrid( &cgrid2.xg, nx, ny );
00595         plAlloc2dGrid( &cgrid2.yg, nx, ny );
00596         plAlloc2dGrid( &zstore, nx, ny );
00597 
00598         for ( i = ixstart; i < ixn; i++ )
00599         {
00600             for ( j = 0; j < indexymin[i]; j++ )
00601             {
00602                 cgrid2.xg[i][j] = x[i];
00603                 cgrid2.yg[i][j] = y[indexymin[i]];
00604                 zstore[i][j]    = getz( zp, i, indexymin[i] );
00605             }
00606             for ( j = indexymin[i]; j < indexymax[i]; j++ )
00607             {
00608                 cgrid2.xg[i][j] = x[i];
00609                 cgrid2.yg[i][j] = y[j];
00610                 zstore[i][j]    = getz( zp, i, j );
00611             }
00612             for ( j = indexymax[i]; j < ny; j++ )
00613             {
00614                 cgrid2.xg[i][j] = x[i];
00615                 cgrid2.yg[i][j] = y[indexymax[i] - 1];
00616                 zstore[i][j]    = getz( zp, i, indexymax[i] - 1 );
00617             }
00618         }
00619         // Fill cont structure with contours.
00620         cont_store( (const PLFLT **) zstore, nx, ny, ixstart + 1, ixn, 1, ny,
00621             clevel, nlevel, pltr2, (void *) &cgrid2, &cont );
00622 
00623         // Free the 2D input arrays to cont_store since not needed any more.
00624         plFree2dGrid( zstore, nx, ny );
00625         plFree2dGrid( cgrid2.xg, nx, ny );
00626         plFree2dGrid( cgrid2.yg, nx, ny );
00627 
00628         // follow the contour levels and lines
00629         clev = cont;
00630         do  // for each contour level
00631         {
00632             cline = clev->line;
00633             do  // there are several lines that make up the contour
00634             {
00635                 if ( cline->npts > np )
00636                 {
00637                     np = cline->npts;
00638                     if ( ( zz = (PLFLT *) realloc( zz, np * sizeof ( PLFLT ) ) ) == NULL )
00639                     {
00640                         plexit( "plsurf3dl: Insufficient memory" );
00641                     }
00642                 }
00643                 for ( j = 0; j < cline->npts; j++ )
00644                     zz[j] = plsc->ranmi;
00645                 if ( cline->npts > 0 )
00646                 {
00647                     plcol1( ( clev->level - fc_minz ) / ( fc_maxz - fc_minz ) );
00648                     plline3( cline->npts, cline->x, cline->y, zz );
00649                 }
00650                 cline = cline->next;
00651             }
00652             while ( cline != NULL );
00653             clev = clev->next;
00654         }
00655         while ( clev != NULL );
00656 
00657         cont_clean_store( cont ); // now release the memory
00658         free( zz );
00659     }
00660 
00661     // Now we can iterate over the grid drawing the quads
00662     for ( iSlow = 0; iSlow < nSlow - 1; iSlow++ )
00663     {
00664         for ( iFast = 0; iFast < nFast - 1; iFast++ )
00665         {
00666             // get the 4 corners of the Quad, which are
00667             //
00668             //       0--2
00669             //       |  |
00670             //       1--3
00671             //
00672 
00673             xm = ym = zm = 0.;
00674 
00675             iftriangle = 1;
00676             for ( i = 0; i < 2; i++ )
00677             {
00678                 for ( j = 0; j < 2; j++ )
00679                 {
00680                     // we're transforming from Fast/Slow coordinates to x/y coordinates
00681                     // note, these are the indices, not the values
00682                     ix = ixFast * ( iFast + i ) + ixSlow * ( iSlow + j ) + ixOrigin;
00683                     iy = iyFast * ( iFast + i ) + iySlow * ( iSlow + j ) + iyOrigin;
00684 
00685                     if ( ixstart <= ix && ix < ixn &&
00686                          indexymin[ix] <= iy && iy < indexymax[ix] )
00687                     {
00688                         xm += px[2 * i + j] = x[ix];
00689                         ym += py[2 * i + j] = y[iy];
00690                         zm += pz[2 * i + j] = getz( zp, ix, iy );
00691                     }
00692                     else
00693                     {
00694                         iftriangle = 0;
00695                         break;
00696                     }
00697                 }
00698                 if ( iftriangle == 0 )
00699                     break;
00700             }
00701 
00702             if ( iftriangle == 0 )
00703                 continue;
00704             // the "mean point" of the quad, common to all four triangles
00705             // -- perhaps not a good thing to do for the light shading
00706 
00707             xm /= 4.; ym /= 4.; zm /= 4.;
00708 
00709             // now draw the quad as four triangles
00710 
00711             for ( i = 1; i < 3; i++ )
00712             {
00713                 for ( j = 0; j < 4; j += 3 )
00714                 {
00715                     shade_triangle( px[j], py[j], pz[j], xm, ym, zm, px[i], py[i], pz[i] );
00716 
00717                     // after shading, see if the triangle crosses       one contour plane
00718 
00719 #define min3( a, b, c )    ( MIN( ( MIN( a, b ) ), c ) )
00720 #define max3( a, b, c )    ( MAX( ( MAX( a, b ) ), c ) )
00721 
00722                     if ( clevel != NULL && ( opt & SURF_CONT ) )
00723                     {
00724                         for ( k = 0; k < nlevel; k++ )
00725                         {
00726                             if ( clevel[k] >= min3( pz[i], zm, pz[j] ) && clevel[k] < max3( pz[i], zm, pz[j] ) )
00727                             {
00728                                 ct = 0;
00729                                 if ( clevel[k] >= MIN( pz[i], zm ) && clevel[k] < MAX( pz[i], zm ) ) // p0-pm
00730                                 {
00731                                     xx[ct] = ( ( clevel[k] - pz[i] ) * ( xm - px[i] ) ) / ( zm - pz[i] ) + px[i];
00732                                     yy[ct] = ( ( clevel[k] - pz[i] ) * ( ym - py[i] ) ) / ( zm - pz[i] ) + py[i];
00733                                     ct++;
00734                                 }
00735 
00736                                 if ( clevel[k] >= MIN( pz[i], pz[j] ) && clevel[k] < MAX( pz[i], pz[j] ) ) // p0-p1
00737                                 {
00738                                     xx[ct] = ( ( clevel[k] - pz[i] ) * ( px[j] - px[i] ) ) / ( pz[j] - pz[i] ) + px[i];
00739                                     yy[ct] = ( ( clevel[k] - pz[i] ) * ( py[j] - py[i] ) ) / ( pz[j] - pz[i] ) + py[i];
00740                                     ct++;
00741                                 }
00742 
00743                                 if ( clevel[k] >= MIN( pz[j], zm ) && clevel[k] < MAX( pz[j], zm ) ) // p1-pm
00744                                 {
00745                                     xx[ct] = ( ( clevel[k] - pz[j] ) * ( xm - px[j] ) ) / ( zm - pz[j] ) + px[j];
00746                                     yy[ct] = ( ( clevel[k] - pz[j] ) * ( ym - py[j] ) ) / ( zm - pz[j] ) + py[j];
00747                                     ct++;
00748                                 }
00749 
00750                                 if ( ct == 2 )
00751                                 {
00752                                     // yes, xx and yy are the intersection points of the triangle with
00753                                     // the contour line -- draw a straight line betweeen the points
00754                                     // -- at the end this will make up the contour line
00755 
00756                                     if ( opt & SURF_CONT )
00757                                     {
00758                                         // surface contour with color set by user
00759                                         plcol0( color );
00760                                         zz[0] = zz[1] = clevel[k];
00761                                         plline3( 2, xx, yy, zz );
00762                                     }
00763 
00764                                     // don't break; one triangle can span various contour levels
00765                                 }
00766                                 else
00767                                     plwarn( "plsurf3dl: ***ERROR***\n" );
00768                             }
00769                         }
00770                     }
00771                 }
00772             }
00773         }
00774     }
00775 
00776     if ( opt & FACETED )
00777     {
00778         plcol0( 0 );
00779         plfplot3dcl( x, y, zops, zp, nx, ny, MESH | DRAW_LINEXY, NULL, 0,
00780             ixstart, ixn, indexymin, indexymax );
00781     }
00782 
00783     if ( opt & DRAW_SIDES ) // the sides look ugly !!!
00784     {                       // draw one more row with all the Z's set to zmin
00785         PLFLT zscale, zmin, zmax;
00786 
00787         plP_grange( &zscale, &zmin, &zmax );
00788 
00789         iSlow      = nSlow - 1;
00790         iftriangle = 1;
00791         for ( iFast = 0; iFast < nFast - 1; iFast++ )
00792         {
00793             for ( i = 0; i < 2; i++ )
00794             {
00795                 ix = ixFast * ( iFast + i ) + ixSlow * iSlow + ixOrigin;
00796                 iy = iyFast * ( iFast + i ) + iySlow * iSlow + iyOrigin;
00797                 if ( ixstart <= ix && ix < ixn &&
00798                      indexymin[ix] <= iy && iy < indexymax[ix] )
00799                 {
00800                     px[2 * i] = x[ix];
00801                     py[2 * i] = y[iy];
00802                     pz[2 * i] = getz( zp, ix, iy );
00803                 }
00804                 else
00805                 {
00806                     iftriangle = 0;
00807                     break;
00808                 }
00809             }
00810             if ( iftriangle == 0 )
00811                 break;
00812             // now draw the quad as two triangles (4 might be better)
00813 
00814             shade_triangle( px[0], py[0], pz[0], px[2], py[2], pz[2], px[0], py[0], zmin );
00815             shade_triangle( px[2], py[2], pz[2], px[2], py[2], zmin, px[0], py[0], zmin );
00816         }
00817 
00818         iFast      = nFast - 1;
00819         iftriangle = 1;
00820         for ( iSlow = 0; iSlow < nSlow - 1; iSlow++ )
00821         {
00822             for ( i = 0; i < 2; i++ )
00823             {
00824                 ix = ixFast * iFast + ixSlow * ( iSlow + i ) + ixOrigin;
00825                 iy = iyFast * iFast + iySlow * ( iSlow + i ) + iyOrigin;
00826                 if ( ixstart <= ix && ix < ixn &&
00827                      indexymin[ix] <= iy && iy < indexymax[ix] )
00828                 {
00829                     px[2 * i] = x[ix];
00830                     py[2 * i] = y[iy];
00831                     pz[2 * i] = getz( zp, ix, iy );
00832                 }
00833                 else
00834                 {
00835                     iftriangle = 0;
00836                     break;
00837                 }
00838             }
00839             if ( iftriangle == 0 )
00840                 break;
00841 
00842             // now draw the quad as two triangles (4 might be better)
00843             shade_triangle( px[0], py[0], pz[0], px[2], py[2], pz[2], px[0], py[0], zmin );
00844             shade_triangle( px[2], py[2], pz[2], px[2], py[2], zmin, px[0], py[0], zmin );
00845         }
00846     }
00847 }
00848 
00849 //--------------------------------------------------------------------------
00850 // void plot3d(x, y, z, nx, ny, opt, side)
00851 //
00852 // Plots a 3-d representation of the function z[x][y]. The x values
00853 // are stored as x[0..nx-1], the y values as y[0..ny-1], and the z
00854 // values are in the 2-d array z[][]. The integer "opt" specifies:
00855 // see plot3dcl() below
00856 //--------------------------------------------------------------------------
00857 
00858 void
00859 c_plot3d( const PLFLT *x, const PLFLT *y, const PLFLT **z,
00860           PLINT nx, PLINT ny, PLINT opt, PLBOOL side )
00861 {
00862     plfplot3dc( x, y, plf2ops_c(), (PLPointer) z, nx, ny, opt | ( side != 0 ? DRAW_SIDES : 0 ), NULL, 0 );
00863 }
00864 
00865 void
00866 plfplot3d( const PLFLT *x, const PLFLT *y, PLF2OPS zops, PLPointer zp,
00867            PLINT nx, PLINT ny, PLINT opt, PLBOOL side )
00868 {
00869     plfplot3dc( x, y, zops, zp, nx, ny, opt | ( side != 0 ? DRAW_SIDES : 0 ), NULL, 0 );
00870 }
00871 
00872 //--------------------------------------------------------------------------
00873 // void plot3dc(x, y, z, nx, ny, opt, clevel, nlevel)
00874 //
00875 // Plots a 3-d representation of the function z[x][y]. The x values
00876 // are stored as x[0..nx-1], the y values as y[0..ny-1], and the z
00877 // values are in the 2-d array z[][]. The integer "opt" specifies:
00878 // see plot3dcl() below
00879 //--------------------------------------------------------------------------
00880 
00881 void
00882 c_plot3dc( const PLFLT *x, const PLFLT *y, const PLFLT **z,
00883            PLINT nx, PLINT ny, PLINT opt,
00884            const PLFLT *clevel, PLINT nlevel )
00885 {
00886     plfplot3dcl( x, y, plf2ops_c(), (PLPointer) z, nx, ny, opt, clevel, nlevel, 0, 0, NULL, NULL );
00887 }
00888 
00889 void
00890 plfplot3dc( const PLFLT *x, const PLFLT *y, PLF2OPS zops, PLPointer zp,
00891             PLINT nx, PLINT ny, PLINT opt, const PLFLT *clevel, PLINT nlevel )
00892 {
00893     plfplot3dcl( x, y, zops, zp, nx, ny, opt, clevel, nlevel, 0, 0, NULL, NULL );
00894 }
00895 
00896 //--------------------------------------------------------------------------
00897 // void plot3dcl(x, y, z, nx, ny, opt, clevel, nlevel,
00898 //       ixstart, ixn, indexymin, indexymax)
00899 //
00900 // Plots a 3-d representation of the function z[x][y]. The x values
00901 // are stored as x[0..nx-1], the y values as y[0..ny-1], and the z
00902 // values are in the 2-d array z[][]. The integer "opt" specifies:
00903 //
00904 //  DRAW_LINEX :  Draw lines parallel to x-axis
00905 //  DRAW_LINEY :  Draw lines parallel to y-axis
00906 //  DRAW_LINEXY:  Draw lines parallel to both axes
00907 //  MAG_COLOR:    Magnitude coloring of wire frame
00908 //  BASE_CONT:    Draw contour at bottom xy plane
00909 //  TOP_CONT:     Draw contour at top xy plane (not yet)
00910 //  DRAW_SIDES:   Draw sides around the plot
00911 //  MESH:       Draw the "under" side of the plot
00912 //
00913 // or any bitwise combination, e.g. "MAG_COLOR | DRAW_LINEX"
00914 // indexymin and indexymax are arrays which specify the y index limits
00915 // (following the convention that the upper range limit is one more than
00916 // actual index limit) for an x index range of ixstart, ixn.
00917 //--------------------------------------------------------------------------
00918 
00919 void
00920 c_plot3dcl( const PLFLT *x, const PLFLT *y, const PLFLT **z,
00921             PLINT nx, PLINT ny, PLINT opt,
00922             const PLFLT *clevel, PLINT nlevel,
00923             PLINT ixstart, PLINT ixn, const PLINT *indexymin, const PLINT *indexymax )
00924 {
00925     plfplot3dcl( x, y, plf2ops_c(), (PLPointer) z, nx, ny,
00926         opt, clevel, nlevel, ixstart, ixn, indexymin, indexymax );
00927 }
00928 
00929 //--------------------------------------------------------------------------
00968 //--------------------------------------------------------------------------
00969 
00970 void
00971 plfplot3dcl( const PLFLT *x, const PLFLT *y, PLF2OPS zops, PLPointer zp,
00972              PLINT nx, PLINT ny, PLINT opt,
00973              const PLFLT *clevel, PLINT nlevel,
00974              PLINT ixstart, PLINT ixn, const PLINT *indexymin, const PLINT *indexymax )
00975 {
00976     PLFLT cxx, cxy, cyx, cyy, cyz;
00977     PLINT init, i, ix, iy, color, width;
00978     PLFLT xmin, xmax, ymin, ymax, zmin, zmax, zscale;
00979     PLINT ixmin   = 0, ixmax = nx - 1, iymin = 0, iymax = ny - 1;
00980     PLINT clipped = 0, base_cont = 0, side = 0;
00981     PLFLT ( *getz )( PLPointer, PLINT, PLINT ) = zops->get;
00982     PLFLT *_x, *_y, **_z;
00983     PLFLT *x_modified, *y_modified;
00984 
00985     pl3mode = 0;
00986 
00987     if ( plsc->level < 3 )
00988     {
00989         myabort( "plot3dcl: Please set up window first" );
00990         return;
00991     }
00992 
00993     if ( ( opt & 3 ) == 0 )
00994     {
00995         myabort( "plot3dcl: Bad option" );
00996         return;
00997     }
00998 
00999     if ( nx <= 0 || ny <= 0 )
01000     {
01001         myabort( "plot3dcl: Bad array dimensions." );
01002         return;
01003     }
01004 
01005     plP_gdom( &xmin, &xmax, &ymin, &ymax );
01006     plP_grange( &zscale, &zmin, &zmax );
01007     if ( zmin > zmax )
01008     {
01009         PLFLT t = zmin;
01010         zmin = zmax;
01011         zmax = t;
01012     }
01013 
01014 // Check that points in x and in y are strictly increasing
01015 
01016     for ( i = 0; i < nx - 1; i++ )
01017     {
01018         if ( x[i] >= x[i + 1] )
01019         {
01020             myabort( "plot3dcl: X array must be strictly increasing" );
01021             return;
01022         }
01023     }
01024     for ( i = 0; i < ny - 1; i++ )
01025     {
01026         if ( y[i] >= y[i + 1] )
01027         {
01028             myabort( "plot3dcl: Y array must be strictly increasing" );
01029             return;
01030         }
01031     }
01032 
01033     if ( opt & MESH )
01034         pl3mode = 1;
01035 
01036     if ( opt & DRAW_SIDES )
01037         side = 1;
01038 
01039     // figure out the part of the data to use
01040     if ( xmin < x[0] )
01041         xmin = x[0];
01042     if ( xmax > x[nx - 1] )
01043         xmax = x[nx - 1];
01044     if ( ymin < y[0] )
01045         ymin = y[0];
01046     if ( ymax > y[ny - 1] )
01047         ymax = y[ny - 1];
01048     for ( ixmin = 0; ixmin < nx - 1 && x[ixmin + 1] < xmin; ixmin++ )
01049     {
01050     }
01051     for ( ixmax = nx - 1; ixmax > 0 && x[ixmax - 1] > xmax; ixmax-- )
01052     {
01053     }
01054     for ( iymin = 0; iymin < ny - 1 && y[iymin + 1] < ymin; iymin++ )
01055     {
01056     }
01057     for ( iymax = ny - 1; iymax > 0 && y[iymax - 1] > ymax; iymax-- )
01058     {
01059     }
01060     //fprintf(stderr, "(%d,%d) %d %d %d %d\n", nx, ny, ixmin, ixmax, iymin, iymax);
01061     // do we need to clip?
01062     if ( ixmin > 0 || ixmax < nx - 1 || iymin > 0 || iymax < ny - 1 )
01063     {
01064         // adjust the input so it stays within bounds
01065         int _nx = ixmax - ixmin + 1;
01066         int _ny = iymax - iymin + 1;
01067         PLFLT ty0, ty1, tx0, tx1;
01068         int i, j;
01069 
01070         if ( _nx <= 1 || _ny <= 1 )
01071         {
01072             myabort( "plot3dcl: selected x or y range has no data" );
01073             return;
01074         }
01075 
01076         // allocate storage for new versions of the input vectors
01077         if ( ( ( _x = (PLFLT *) malloc( _nx * sizeof ( PLFLT ) ) ) == NULL ) ||
01078              ( ( _y = (PLFLT *) malloc( _ny * sizeof ( PLFLT ) ) ) == NULL ) ||
01079              ( ( _z = (PLFLT **) malloc( _nx * sizeof ( PLFLT* ) ) ) == NULL ) )
01080         {
01081             plexit( "c_plot3dcl: Insufficient memory" );
01082         }
01083 
01084         clipped = 1;
01085 
01086         // copy over the independent variables
01087         _x[0]       = xmin;
01088         _x[_nx - 1] = xmax;
01089         for ( i = 1; i < _nx - 1; i++ )
01090             _x[i] = x[ixmin + i];
01091         _y[0]       = ymin;
01092         _y[_ny - 1] = ymax;
01093         for ( i = 1; i < _ny - 1; i++ )
01094             _y[i] = y[iymin + i];
01095 
01096         // copy the data array so we can interpolate around the edges
01097         for ( i = 0; i < _nx; i++ )
01098         {
01099             if ( ( _z[i] = (PLFLT *) malloc( _ny * sizeof ( PLFLT ) ) ) == NULL )
01100             {
01101                 plexit( "c_plot3dcl: Insufficient memory" );
01102             }
01103         }
01104 
01105         // interpolation factors for the 4 edges
01106         ty0 = ( _y[0] - y[iymin] ) / ( y[iymin + 1] - y[iymin] );
01107         ty1 = ( _y[_ny - 1] - y[iymax - 1] ) / ( y[iymax] - y[iymax - 1] );
01108         tx0 = ( _x[0] - x[ixmin] ) / ( x[ixmin + 1] - x[ixmin] );
01109         tx1 = ( _x[_nx - 1] - x[ixmax - 1] ) / ( x[ixmax] - x[ixmax - 1] );
01110         for ( i = 0; i < _nx; i++ )
01111         {
01112             if ( i == 0 )
01113             {
01114                 _z[i][0] = getz( zp, ixmin, iymin ) * ( 1 - ty0 ) * ( 1 - tx0 ) + getz( zp, ixmin, iymin + 1 ) * ( 1 - tx0 ) * ty0
01115                            + getz( zp, ixmin + 1, iymin ) * tx0 * ( 1 - ty0 ) + getz( zp, ixmin + 1, iymin + 1 ) * tx0 * ty0;
01116                 for ( j = 1; j < _ny - 1; j++ )
01117                     _z[i][j] = getz( zp, ixmin, iymin + j ) * ( 1 - tx0 ) + getz( zp, ixmin + 1, iymin + j ) * tx0;
01118                 _z[i][_ny - 1] = getz( zp, ixmin, iymax - 1 ) * ( 1 - tx0 ) * ( 1 - ty1 ) + getz( zp, ixmin, iymax ) * ( 1 - tx0 ) * ty1
01119                                  + getz( zp, ixmin + 1, iymax - 1 ) * tx0 * ( 1 - ty1 ) + getz( zp, ixmin + 1, iymax ) * tx0 * ty1;
01120             }
01121             else if ( i == _nx - 1 )
01122             {
01123                 _z[i][0] = getz( zp, ixmax - 1, iymin ) * ( 1 - tx1 ) * ( 1 - ty0 ) + getz( zp, ixmax - 1, iymin + 1 ) * ( 1 - tx1 ) * ty0
01124                            + getz( zp, ixmax, iymin ) * tx1 * ( 1 - ty0 ) + getz( zp, ixmax, iymin + 1 ) * tx1 * ty0;
01125                 for ( j = 1; j < _ny - 1; j++ )
01126                     _z[i][j] = getz( zp, ixmax - 1, iymin + j ) * ( 1 - tx1 ) + getz( zp, ixmax, iymin + j ) * tx1;
01127                 _z[i][_ny - 1] = getz( zp, ixmax - 1, iymax - 1 ) * ( 1 - tx1 ) * ( 1 - ty1 ) + getz( zp, ixmax, iymax ) * ( 1 - tx1 ) * ty1
01128                                  + getz( zp, ixmax, iymax - 1 ) * tx1 * ( 1 - ty1 ) + getz( zp, ixmax, iymax ) * tx1 * ty1;
01129             }
01130             else
01131             {
01132                 _z[i][0] = getz( zp, ixmin + i, iymin ) * ( 1 - ty0 ) + getz( zp, ixmin + i, iymin + 1 ) * ty0;
01133                 for ( j = 1; j < _ny - 1; j++ )
01134                     _z[i][j] = getz( zp, ixmin + i, iymin + j );
01135                 _z[i][_ny - 1] = getz( zp, ixmin + i, iymax - 1 ) * ( 1 - ty1 ) + getz( zp, ixmin + i, iymax ) * ty1;
01136             }
01137             for ( j = 0; j < _ny; j++ )
01138             {
01139                 if ( _z[i][j] < zmin )
01140                     _z[i][j] = zmin;
01141                 else if ( _z[i][j] > zmax )
01142                     _z[i][j] = zmax;
01143             }
01144         }
01145         // replace the input with our clipped versions
01146         zp   = (PLPointer) _z;
01147         getz = plf2ops_c()->get;
01148         nx   = _nx;
01149         ny   = _ny;
01150         // Do not want to modify input x and y (const modifier)
01151         x_modified = _x;
01152         y_modified = _y;
01153     }
01154     else
01155     {
01156         x_modified = (PLFLT *) x;
01157         y_modified = (PLFLT *) y;
01158     }
01159 
01160     // From here on must use x_modified and y_modified rather than
01161     // x and y.
01162     if ( ( opt & BASE_CONT ) || ( opt & TOP_CONT ) || ( opt && MAG_COLOR ) )
01163     {
01164         //
01165         // Don't use the data z value to scale the color, use the z axis
01166         // values set by plw3d()
01167         //
01168         // plMinMax2dGrid(z, nx, ny, &fc_maxz, &fc_minz);
01169         //
01170 
01171         fc_minz = plsc->ranmi;
01172         fc_maxz = plsc->ranma;
01173 
01174         if ( fc_maxz == fc_minz )
01175         {
01176             plwarn( "plot3dcl: Maximum and minimum Z values are equal! \"fixing\"..." );
01177             fc_maxz = fc_minz + 1e-6;
01178         }
01179     }
01180 
01181     if ( opt & BASE_CONT )    // If enabled, draw the contour at the base.
01182     {
01183         if ( clevel != NULL && nlevel != 0 )
01184         {
01185             base_cont = 1;
01186             // even if MESH is not set, "set it",
01187             // as the base contour can only be done in this case
01188             pl3mode = 1;
01189         }
01190     }
01191 
01192     if ( opt & MAG_COLOR )    // If enabled, use magnitude colored wireframe
01193     {
01194         if ( ( ctmp = (PLFLT *) malloc( (size_t) ( 2 * MAX( nx, ny ) * sizeof ( PLFLT ) ) ) ) == NULL )
01195         {
01196             plexit( "c_plot3dcl: Insufficient memory" );
01197         }
01198     }
01199     else
01200         ctmp = NULL;
01201 
01202     // next logic only knows opt = 1 | 2 | 3, make sure that it only gets that
01203     opt &= DRAW_LINEXY;
01204 
01205     // Allocate work arrays
01206 
01207     utmp = (PLINT *) malloc( (size_t) ( 2 * MAX( nx, ny ) * sizeof ( PLINT ) ) );
01208     vtmp = (PLINT *) malloc( (size_t) ( 2 * MAX( nx, ny ) * sizeof ( PLINT ) ) );
01209 
01210     if ( !utmp || !vtmp )
01211         myexit( "plot3dcl: Out of memory." );
01212 
01213     plP_gw3wc( &cxx, &cxy, &cyx, &cyy, &cyz );
01214     init = 1;
01215 // Call 3d line plotter.  Each viewing quadrant
01216 // (perpendicular to x-y plane) must be handled separately.
01217     if ( cxx >= 0.0 && cxy <= 0.0 )
01218     {
01219         if ( opt == DRAW_LINEY )
01220             plt3zz( 1, ny, 1, -1, -opt, &init, x_modified, y_modified, zops, zp, nx, ny, utmp, vtmp, ctmp );
01221         else
01222         {
01223             for ( iy = 2; iy <= ny; iy++ )
01224                 plt3zz( 1, iy, 1, -1, -opt, &init, x_modified, y_modified, zops, zp, nx, ny, utmp, vtmp, ctmp );
01225         }
01226         if ( opt == DRAW_LINEX )
01227             plt3zz( 1, ny, 1, -1, opt, &init, x_modified, y_modified, zops, zp, nx, ny, utmp, vtmp, ctmp );
01228         else
01229         {
01230             for ( ix = 1; ix <= nx - 1; ix++ )
01231                 plt3zz( ix, ny, 1, -1, opt, &init, x_modified, y_modified, zops, zp, nx, ny, utmp, vtmp, ctmp );
01232         }
01233     }
01234 
01235     else if ( cxx <= 0.0 && cxy <= 0.0 )
01236     {
01237         if ( opt == DRAW_LINEX )
01238             plt3zz( nx, ny, -1, -1, opt, &init, x_modified, y_modified, zops, zp, nx, ny, utmp, vtmp, ctmp );
01239         else
01240         {
01241             for ( ix = 2; ix <= nx; ix++ )
01242                 plt3zz( ix, ny, -1, -1, opt, &init, x_modified, y_modified, zops, zp, nx, ny, utmp, vtmp, ctmp );
01243         }
01244         if ( opt == DRAW_LINEY )
01245             plt3zz( nx, ny, -1, -1, -opt, &init, x_modified, y_modified, zops, zp, nx, ny, utmp, vtmp, ctmp );
01246         else
01247         {
01248             for ( iy = ny; iy >= 2; iy-- )
01249                 plt3zz( nx, iy, -1, -1, -opt, &init, x_modified, y_modified, zops, zp, nx, ny, utmp, vtmp, ctmp );
01250         }
01251     }
01252 
01253     else if ( cxx <= 0.0 && cxy >= 0.0 )
01254     {
01255         if ( opt == DRAW_LINEY )
01256             plt3zz( nx, 1, -1, 1, -opt, &init, x_modified, y_modified, zops, zp, nx, ny, utmp, vtmp, ctmp );
01257         else
01258         {
01259             for ( iy = ny - 1; iy >= 1; iy-- )
01260                 plt3zz( nx, iy, -1, 1, -opt, &init, x_modified, y_modified, zops, zp, nx, ny, utmp, vtmp, ctmp );
01261         }
01262         if ( opt == DRAW_LINEX )
01263             plt3zz( nx, 1, -1, 1, opt, &init, x_modified, y_modified, zops, zp, nx, ny, utmp, vtmp, ctmp );
01264         else
01265         {
01266             for ( ix = nx; ix >= 2; ix-- )
01267                 plt3zz( ix, 1, -1, 1, opt, &init, x_modified, y_modified, zops, zp, nx, ny, utmp, vtmp, ctmp );
01268         }
01269     }
01270 
01271     else if ( cxx >= 0.0 && cxy >= 0.0 )
01272     {
01273         if ( opt == DRAW_LINEX )
01274             plt3zz( 1, 1, 1, 1, opt, &init, x_modified, y_modified, zops, zp, nx, ny, utmp, vtmp, ctmp );
01275         else
01276         {
01277             for ( ix = nx - 1; ix >= 1; ix-- )
01278                 plt3zz( ix, 1, 1, 1, opt, &init, x_modified, y_modified, zops, zp, nx, ny, utmp, vtmp, ctmp );
01279         }
01280         if ( opt == DRAW_LINEY )
01281             plt3zz( 1, 1, 1, 1, -opt, &init, x_modified, y_modified, zops, zp, nx, ny, utmp, vtmp, ctmp );
01282         else
01283         {
01284             for ( iy = 1; iy <= ny - 1; iy++ )
01285                 plt3zz( 1, iy, 1, 1, -opt, &init, x_modified, y_modified, zops, zp, nx, ny, utmp, vtmp, ctmp );
01286         }
01287     }
01288 
01289     // draw contour at the base. Not 100%! Why?
01290 
01291     if ( base_cont )
01292     {
01293         int np = NPTS, j;
01294         CONT_LEVEL *cont, *clev;
01295         CONT_LINE *cline;
01296 
01297         PLINT *uu = (PLINT *) malloc( NPTS * sizeof ( PLINT ) );
01298         PLINT *vv = (PLINT *) malloc( NPTS * sizeof ( PLINT ) );
01299         // prepare cont_store input
01300         PLFLT **zstore;
01301         PLcGrid2 cgrid2;
01302 
01303         if ( ( uu == NULL ) || ( vv == NULL ) )
01304         {
01305             plexit( "c_plot3dcl: Insufficient memory" );
01306         }
01307 
01308         cgrid2.nx = nx;
01309         cgrid2.ny = ny;
01310         plAlloc2dGrid( &cgrid2.xg, nx, ny );
01311         plAlloc2dGrid( &cgrid2.yg, nx, ny );
01312         plAlloc2dGrid( &zstore, nx, ny );
01313 
01314         for ( i = 0; i < nx; i++ )
01315         {
01316             for ( j = 0; j < ny; j++ )
01317             {
01318                 cgrid2.xg[i][j] = x_modified[i];
01319                 cgrid2.yg[i][j] = y_modified[j];
01320                 zstore[i][j]    = getz( zp, i, j );
01321             }
01322         }
01323 
01324         pl3upv = 0;
01325 
01326         // Fill cont structure with contours.
01327         cont_store( (const PLFLT **) zstore, nx, ny, 1, nx, 1, ny,
01328             clevel, nlevel, pltr2, (void *) &cgrid2, &cont );
01329 
01330         // Free the 2D input arrays to cont_store since not needed any more.
01331         plFree2dGrid( zstore, nx, ny );
01332         plFree2dGrid( cgrid2.xg, nx, ny );
01333         plFree2dGrid( cgrid2.yg, nx, ny );
01334 
01335         // follow the contour levels and lines
01336         clev = cont;
01337         do  // for each contour level
01338         {
01339             cline = clev->line;
01340             do  // there are several lines that make up each contour
01341             {
01342                 int cx, i, k, l, m, start, end;
01343                 PLFLT tx, ty;
01344                 if ( cline->npts > np )
01345                 {
01346                     np = cline->npts;
01347                     if ( ( ( uu = (PLINT *) realloc( uu, np * sizeof ( PLINT ) ) ) == NULL ) ||
01348                          ( ( vv = (PLINT *) realloc( vv, np * sizeof ( PLINT ) ) ) == NULL ) )
01349                     {
01350                         plexit( "c_plot3dcl: Insufficient memory" );
01351                     }
01352                 }
01353 
01354                 // the hidden line plotter plnxtv() only works OK if the x points are in increasing order.
01355                 // As this does not always happens, the situation must be detected and the line segment
01356                 // must be reversed before being plotted
01357                 i = 0;
01358                 if ( cline->npts > 0 )
01359                 {
01360                     do
01361                     {
01362                         plcol1( ( clev->level - fc_minz ) / ( fc_maxz - fc_minz ) );
01363                         cx = plP_wcpcx( plP_w3wcx( cline->x[i], cline->y[i], plsc->ranmi ) );
01364                         for ( j = i; j < cline->npts; j++ ) // convert to 2D coordinates
01365                         {
01366                             uu[j] = plP_wcpcx( plP_w3wcx( cline->x[j], cline->y[j], plsc->ranmi ) );
01367                             vv[j] = plP_wcpcy( plP_w3wcy( cline->x[j], cline->y[j], plsc->ranmi ) );
01368                             if ( uu[j] < cx ) // find turn back point
01369                                 break;
01370                             else
01371                                 cx = uu[j];
01372                         }
01373                         plnxtv( &uu[i], &vv[i], NULL, j - i, 0 ); // plot line with increasing x
01374 
01375                         if ( j < cline->npts )                    // line not yet finished,
01376                         {
01377                             start = j - 1;
01378                             for ( i = start; i < cline->npts; i++ ) // search turn forward point
01379                             {
01380                                 uu[i] = plP_wcpcx( plP_w3wcx( cline->x[i], cline->y[i], plsc->ranmi ) );
01381                                 if ( uu[i] > cx )
01382                                     break;
01383                                 else
01384                                     cx = uu[i];
01385                             }
01386                             end = i - 1;
01387 
01388                             for ( k = 0; k < ( end - start + 1 ) / 2; k++ ) // reverse line segment
01389                             {
01390                                 l           = start + k;
01391                                 m           = end - k;
01392                                 tx          = cline->x[l];
01393                                 ty          = cline->y[l];
01394                                 cline->x[l] = cline->x[m];
01395                                 cline->y[l] = cline->y[m];
01396                                 cline->x[m] = tx;
01397                                 cline->y[m] = ty;
01398                             }
01399 
01400                             // convert to 2D coordinates
01401                             for ( j = start; j <= end; j++ )
01402                             {
01403                                 uu[j] = plP_wcpcx( plP_w3wcx( cline->x[j], cline->y[j], plsc->ranmi ) );
01404                                 vv[j] = plP_wcpcy( plP_w3wcy( cline->x[j], cline->y[j], plsc->ranmi ) );
01405                             }
01406                             plnxtv( &uu[start], &vv[start], NULL, end - start + 1, 0 ); // and plot it
01407 
01408                             cline->x[end] = cline->x[start];
01409                             cline->y[end] = cline->y[start];
01410                             i             = end; // restart where it was left
01411                         }
01412                     } while ( j < cline->npts && i < cline->npts );
01413                 }
01414                 cline = cline->next;
01415             }
01416             while ( cline != NULL );
01417             clev = clev->next;
01418         }
01419         while ( clev != NULL );
01420 
01421         cont_clean_store( cont ); // now release the contour memory
01422         pl3upv = 1;
01423         free( uu );
01424         free( vv );
01425     }
01426 
01427 // Finish up by drawing sides, background grid (both are optional)
01428 
01429     if ( side )
01430         plside3( x_modified, y_modified, zops, zp, nx, ny, opt );
01431 
01432     if ( zbflg )
01433     {
01434         color = plsc->icol0;
01435         width = plsc->width;
01436         plwid( zbwidth );
01437         plcol0( zbcol );
01438         plgrid3( zbtck );
01439         plwid( width );
01440         plcol0( color );
01441     }
01442 
01443     freework();
01444 
01445     if ( clipped )
01446     {
01447         free( _x );
01448         free( _y );
01449         for ( i = 0; i < nx; i++ )
01450             free( _z[i] );
01451         free( _z );
01452     }
01453 }
01454 
01455 //--------------------------------------------------------------------------
01456 // void plxyindexlimits()
01457 //
01458 // Transform from y array limits to corresponding x array limits (or vice
01459 // versa).
01460 //
01461 // N.B. we follow the convention here that all upper range limits are one
01462 // more than the actual last index.
01463 // instart (>= 0) through inn is the index range where
01464 // the input inarray_min and inarray_max arrays are defined.
01465 //
01466 // outstart (>= 0), through outn (with outn <= outnmax) is the index range
01467 // where the output outarray_min and outarray_max arrays are defined.
01468 //
01469 // In order to assure the transformation from y array limits to x array limits
01470 // (or vice versa) is single-valued, this programme plaborts if the
01471 // inarray_min array has a maximum or inarray_max array has a minimum.
01472 //--------------------------------------------------------------------------
01473 
01474 static void
01475 plxyindexlimits( PLINT instart, PLINT inn,
01476                  PLINT *inarray_min, PLINT *inarray_max,
01477                  PLINT *outstart, PLINT *outn, PLINT outnmax,
01478                  PLINT *outarray_min, PLINT *outarray_max )
01479 {
01480     PLINT i, j;
01481     if ( inn < 0 )
01482     {
01483         myabort( "plxyindexlimits: Must have instart >= 0" );
01484         return;
01485     }
01486     if ( inn - instart <= 0 )
01487     {
01488         myabort( "plxyindexlimits: Must have at least 1 defined point" );
01489         return;
01490     }
01491     *outstart = inarray_min[instart];
01492     *outn     = inarray_max[instart];
01493     for ( i = instart; i < inn; i++ )
01494     {
01495         *outstart = MIN( *outstart, inarray_min[i] );
01496         *outn     = MAX( *outn, inarray_max[i] );
01497         if ( i + 2 < inn )
01498         {
01499             if ( inarray_min[i] < inarray_min[i + 1] &&
01500                  inarray_min[i + 1] > inarray_min[i + 2] )
01501             {
01502                 myabort( "plxyindexlimits: inarray_min must not have a maximum" );
01503                 return;
01504             }
01505             if ( inarray_max[i] > inarray_max[i + 1] &&
01506                  inarray_max[i + 1] < inarray_max[i + 2] )
01507             {
01508                 myabort( "plxyindexlimits: inarray_max must not have a minimum" );
01509                 return;
01510             }
01511         }
01512     }
01513     if ( *outstart < 0 )
01514     {
01515         myabort( "plxyindexlimits: Must have all elements of inarray_min >= 0" );
01516         return;
01517     }
01518     if ( *outn > outnmax )
01519     {
01520         myabort( "plxyindexlimits: Must have all elements of inarray_max <= outnmax" );
01521         return;
01522     }
01523     for ( j = *outstart; j < *outn; j++ )
01524     {
01525         i = instart;
01526         // Find first valid i for this j.
01527         while ( i < inn && !( inarray_min[i] <= j && j < inarray_max[i] ) )
01528             i++;
01529         if ( i < inn )
01530             outarray_min[j] = i;
01531         else
01532         {
01533             myabort( "plxyindexlimits: bad logic; invalid i should never happen" );
01534             return;
01535         }
01536         // Find next invalid i for this j.
01537         while ( i < inn && ( inarray_min[i] <= j && j < inarray_max[i] ) )
01538             i++;
01539         outarray_max[j] = i;
01540     }
01541 }
01542 
01543 //--------------------------------------------------------------------------
01544 // void plP_gzback()
01545 //
01546 // Get background parameters for 3d plot.
01547 //--------------------------------------------------------------------------
01548 
01549 void
01550 plP_gzback( PLINT **zbf, PLINT **zbc, PLFLT **zbt, PLINT **zbw )
01551 {
01552     *zbf = &zbflg;
01553     *zbc = &zbcol;
01554     *zbt = &zbtck;
01555     *zbw = &zbwidth;
01556 }
01557 
01558 //--------------------------------------------------------------------------
01559 // PLFLT plGetAngleToLight()
01560 //
01561 // Gets cos of angle between normal to a polygon and a light source.
01562 // Requires at least 3 elements, forming non-parallel lines
01563 // in the arrays.
01564 //--------------------------------------------------------------------------
01565 
01566 static PLFLT
01567 plGetAngleToLight( PLFLT* x, PLFLT* y, PLFLT* z )
01568 {
01569     PLFLT vx1, vx2, vy1, vy2, vz1, vz2;
01570     PLFLT px, py, pz;
01571     PLFLT vlx, vly, vlz;
01572     PLFLT mag1, mag2;
01573     PLFLT cosangle;
01574 
01575     vx1 = x[1] - x[0];
01576     vx2 = x[2] - x[1];
01577     vy1 = y[1] - y[0];
01578     vy2 = y[2] - y[1];
01579     vz1 = z[1] - z[0];
01580     vz2 = z[2] - z[1];
01581 
01582 // Find vector perpendicular to the face
01583     px   = vy1 * vz2 - vz1 * vy2;
01584     py   = vz1 * vx2 - vx1 * vz2;
01585     pz   = vx1 * vy2 - vy1 * vx2;
01586     mag1 = px * px + py * py + pz * pz;
01587 
01588 // Vectors were parallel!
01589     if ( mag1 == 0 )
01590         return 1;
01591 
01592     vlx  = xlight - x[0];
01593     vly  = ylight - y[0];
01594     vlz  = zlight - z[0];
01595     mag2 = vlx * vlx + vly * vly + vlz * vlz;
01596     if ( mag2 == 0 )
01597         return 1;
01598 
01599 // Now have 3 vectors going through the first point on the given surface
01600     cosangle = fabs( ( vlx * px + vly * py + vlz * pz ) / sqrt( mag1 * mag2 ) );
01601 
01602 // In case of numerical rounding
01603     if ( cosangle > 1 )
01604         cosangle = 1;
01605     return cosangle;
01606 }
01607 
01608 //--------------------------------------------------------------------------
01609 // void plt3zz()
01610 //
01611 // Draws the next zig-zag line for a 3-d plot.  The data is stored in array
01612 // z[][] as a function of x[] and y[], and is plotted out starting at index
01613 // (x0,y0).
01614 //
01615 // Depending on the state of "flag", the sequence of data points sent to
01616 // plnxtv is altered so as to allow cross-hatch plotting, or plotting
01617 // parallel to either the x-axis or the y-axis.
01618 //--------------------------------------------------------------------------
01619 
01620 static void
01621 plt3zz( PLINT x0, PLINT y0, PLINT dx, PLINT dy, PLINT flag, PLINT *init,
01622         PLFLT *x, PLFLT *y, PLF2OPS zops, PLPointer zp, PLINT nx, PLINT ny,
01623         PLINT *u, PLINT *v, PLFLT* c )
01624 {
01625     PLINT n = 0;
01626     PLFLT x2d, y2d;
01627     PLFLT ( *getz )( PLPointer, PLINT, PLINT ) = zops->get;
01628 
01629     while ( 1 <= x0 && x0 <= nx && 1 <= y0 && y0 <= ny )
01630     {
01631         x2d  = plP_w3wcx( x[x0 - 1], y[y0 - 1], getz( zp, x0 - 1, y0 - 1 ) );
01632         y2d  = plP_w3wcy( x[x0 - 1], y[y0 - 1], getz( zp, x0 - 1, y0 - 1 ) );
01633         u[n] = plP_wcpcx( x2d );
01634         v[n] = plP_wcpcy( y2d );
01635         if ( c != NULL )
01636             c[n] = ( getz( zp, x0 - 1, y0 - 1 ) - fc_minz ) / ( fc_maxz - fc_minz );
01637 
01638         switch ( flag )
01639         {
01640         case -3:
01641             y0  += dy;
01642             flag = -flag;
01643             break;
01644         case -2:
01645             y0 += dy;
01646             break;
01647         case -1:
01648             y0  += dy;
01649             flag = -flag;
01650             break;
01651         case 1:
01652             x0 += dx;
01653             break;
01654         case 2:
01655             x0  += dx;
01656             flag = -flag;
01657             break;
01658         case 3:
01659             x0  += dx;
01660             flag = -flag;
01661             break;
01662         }
01663         n++;
01664     }
01665 
01666     if ( flag == 1 || flag == -2 )
01667     {
01668         if ( flag == 1 )
01669         {
01670             x0 -= dx;
01671             y0 += dy;
01672         }
01673         else if ( flag == -2 )
01674         {
01675             y0 -= dy;
01676             x0 += dx;
01677         }
01678         if ( 1 <= x0 && x0 <= nx && 1 <= y0 && y0 <= ny )
01679         {
01680             x2d  = plP_w3wcx( x[x0 - 1], y[y0 - 1], getz( zp, x0 - 1, y0 - 1 ) );
01681             y2d  = plP_w3wcy( x[x0 - 1], y[y0 - 1], getz( zp, x0 - 1, y0 - 1 ) );
01682             u[n] = plP_wcpcx( x2d );
01683             v[n] = plP_wcpcy( y2d );
01684             if ( c != NULL )
01685                 c[n] = ( getz( zp, x0 - 1, y0 - 1 ) - fc_minz ) / ( fc_maxz - fc_minz );
01686             n++;
01687         }
01688     }
01689 
01690 // All the setup is done.  Time to do the work.
01691 
01692     plnxtv( u, v, c, n, *init );
01693     *init = 0;
01694 }
01695 
01696 //--------------------------------------------------------------------------
01697 // void plside3()
01698 //
01699 // This routine draws sides around the front of the 3d plot so that
01700 // it does not appear to float.
01701 //--------------------------------------------------------------------------
01702 
01703 static void
01704 plside3( PLFLT *x, PLFLT *y, PLF2OPS zops, PLPointer zp, PLINT nx, PLINT ny, PLINT opt )
01705 {
01706     PLINT i;
01707     PLFLT cxx, cxy, cyx, cyy, cyz;
01708     PLFLT xmin, ymin, zmin, xmax, ymax, zmax, zscale;
01709     PLFLT tx, ty, ux, uy;
01710     PLFLT ( *getz )( PLPointer, PLINT, PLINT ) = zops->get;
01711 
01712     plP_gw3wc( &cxx, &cxy, &cyx, &cyy, &cyz );
01713     plP_gdom( &xmin, &xmax, &ymin, &ymax );
01714     plP_grange( &zscale, &zmin, &zmax );
01715 
01716 // Get x, y coordinates of legs and plot
01717 
01718     if ( cxx >= 0.0 && cxy <= 0.0 )
01719     {
01720         if ( opt != 1 )
01721         {
01722             for ( i = 0; i < nx; i++ )
01723             {
01724                 tx = plP_w3wcx( x[i], y[0], zmin );
01725                 ty = plP_w3wcy( x[i], y[0], zmin );
01726                 ux = plP_w3wcx( x[i], y[0], getz( zp, i, 0 ) );
01727                 uy = plP_w3wcy( x[i], y[0], getz( zp, i, 0 ) );
01728                 pljoin( tx, ty, ux, uy );
01729             }
01730         }
01731         if ( opt != 2 )
01732         {
01733             for ( i = 0; i < ny; i++ )
01734             {
01735                 tx = plP_w3wcx( x[0], y[i], zmin );
01736                 ty = plP_w3wcy( x[0], y[i], zmin );
01737                 ux = plP_w3wcx( x[0], y[i], getz( zp, 0, i ) );
01738                 uy = plP_w3wcy( x[0], y[i], getz( zp, 0, i ) );
01739                 pljoin( tx, ty, ux, uy );
01740             }
01741         }
01742     }
01743     else if ( cxx <= 0.0 && cxy <= 0.0 )
01744     {
01745         if ( opt != 1 )
01746         {
01747             for ( i = 0; i < nx; i++ )
01748             {
01749                 tx = plP_w3wcx( x[i], y[ny - 1], zmin );
01750                 ty = plP_w3wcy( x[i], y[ny - 1], zmin );
01751                 ux = plP_w3wcx( x[i], y[ny - 1], getz( zp, i, ny - 1 ) );
01752                 uy = plP_w3wcy( x[i], y[ny - 1], getz( zp, i, ny - 1 ) );
01753                 pljoin( tx, ty, ux, uy );
01754             }
01755         }
01756         if ( opt != 2 )
01757         {
01758             for ( i = 0; i < ny; i++ )
01759             {
01760                 tx = plP_w3wcx( x[0], y[i], zmin );
01761                 ty = plP_w3wcy( x[0], y[i], zmin );
01762                 ux = plP_w3wcx( x[0], y[i], getz( zp, 0, i ) );
01763                 uy = plP_w3wcy( x[0], y[i], getz( zp, 0, i ) );
01764                 pljoin( tx, ty, ux, uy );
01765             }
01766         }
01767     }
01768     else if ( cxx <= 0.0 && cxy >= 0.0 )
01769     {
01770         if ( opt != 1 )
01771         {
01772             for ( i = 0; i < nx; i++ )
01773             {
01774                 tx = plP_w3wcx( x[i], y[ny - 1], zmin );
01775                 ty = plP_w3wcy( x[i], y[ny - 1], zmin );
01776                 ux = plP_w3wcx( x[i], y[ny - 1], getz( zp, i, ny - 1 ) );
01777                 uy = plP_w3wcy( x[i], y[ny - 1], getz( zp, i, ny - 1 ) );
01778                 pljoin( tx, ty, ux, uy );
01779             }
01780         }
01781         if ( opt != 2 )
01782         {
01783             for ( i = 0; i < ny; i++ )
01784             {
01785                 tx = plP_w3wcx( x[nx - 1], y[i], zmin );
01786                 ty = plP_w3wcy( x[nx - 1], y[i], zmin );
01787                 ux = plP_w3wcx( x[nx - 1], y[i], getz( zp, nx - 1, i ) );
01788                 uy = plP_w3wcy( x[nx - 1], y[i], getz( zp, nx - 1, i ) );
01789                 pljoin( tx, ty, ux, uy );
01790             }
01791         }
01792     }
01793     else if ( cxx >= 0.0 && cxy >= 0.0 )
01794     {
01795         if ( opt != 1 )
01796         {
01797             for ( i = 0; i < nx; i++ )
01798             {
01799                 tx = plP_w3wcx( x[i], y[0], zmin );
01800                 ty = plP_w3wcy( x[i], y[0], zmin );
01801                 ux = plP_w3wcx( x[i], y[0], getz( zp, i, 0 ) );
01802                 uy = plP_w3wcy( x[i], y[0], getz( zp, i, 0 ) );
01803                 pljoin( tx, ty, ux, uy );
01804             }
01805         }
01806         if ( opt != 2 )
01807         {
01808             for ( i = 0; i < ny; i++ )
01809             {
01810                 tx = plP_w3wcx( x[nx - 1], y[i], zmin );
01811                 ty = plP_w3wcy( x[nx - 1], y[i], zmin );
01812                 ux = plP_w3wcx( x[nx - 1], y[i], getz( zp, nx - 1, i ) );
01813                 uy = plP_w3wcy( x[nx - 1], y[i], getz( zp, nx - 1, i ) );
01814                 pljoin( tx, ty, ux, uy );
01815             }
01816         }
01817     }
01818 }
01819 
01820 //--------------------------------------------------------------------------
01821 // void plgrid3()
01822 //
01823 // This routine draws a grid around the back side of the 3d plot with
01824 // hidden line removal.
01825 //--------------------------------------------------------------------------
01826 
01827 static void
01828 plgrid3( PLFLT tick )
01829 {
01830     PLFLT xmin, ymin, zmin, xmax, ymax, zmax, zscale;
01831     PLFLT cxx, cxy, cyx, cyy, cyz, zmin_in, zmax_in;
01832     PLINT u[3], v[3];
01833     PLINT nsub = 0;
01834     PLFLT tp;
01835 
01836     plP_gw3wc( &cxx, &cxy, &cyx, &cyy, &cyz );
01837     plP_gdom( &xmin, &xmax, &ymin, &ymax );
01838     plP_grange( &zscale, &zmin_in, &zmax_in );
01839     zmin = ( zmax_in > zmin_in ) ? zmin_in : zmax_in;
01840     zmax = ( zmax_in > zmin_in ) ? zmax_in : zmin_in;
01841 
01842     pldtik( zmin, zmax, &tick, &nsub, FALSE );
01843     tp     = tick * floor( zmin / tick ) + tick;
01844     pl3upv = 0;
01845 
01846     if ( cxx >= 0.0 && cxy <= 0.0 )
01847     {
01848         while ( tp <= zmax )
01849         {
01850             u[0] = plP_wcpcx( plP_w3wcx( xmin, ymax, tp ) );
01851             v[0] = plP_wcpcy( plP_w3wcy( xmin, ymax, tp ) );
01852             u[1] = plP_wcpcx( plP_w3wcx( xmax, ymax, tp ) );
01853             v[1] = plP_wcpcy( plP_w3wcy( xmax, ymax, tp ) );
01854             u[2] = plP_wcpcx( plP_w3wcx( xmax, ymin, tp ) );
01855             v[2] = plP_wcpcy( plP_w3wcy( xmax, ymin, tp ) );
01856             plnxtv( u, v, 0, 3, 0 );
01857 
01858             tp += tick;
01859         }
01860         u[0] = plP_wcpcx( plP_w3wcx( xmax, ymax, zmin ) );
01861         v[0] = plP_wcpcy( plP_w3wcy( xmax, ymax, zmin ) );
01862         u[1] = plP_wcpcx( plP_w3wcx( xmax, ymax, zmax ) );
01863         v[1] = plP_wcpcy( plP_w3wcy( xmax, ymax, zmax ) );
01864         plnxtv( u, v, 0, 2, 0 );
01865     }
01866     else if ( cxx <= 0.0 && cxy <= 0.0 )
01867     {
01868         while ( tp <= zmax )
01869         {
01870             u[0] = plP_wcpcx( plP_w3wcx( xmax, ymax, tp ) );
01871             v[0] = plP_wcpcy( plP_w3wcy( xmax, ymax, tp ) );
01872             u[1] = plP_wcpcx( plP_w3wcx( xmax, ymin, tp ) );
01873             v[1] = plP_wcpcy( plP_w3wcy( xmax, ymin, tp ) );
01874             u[2] = plP_wcpcx( plP_w3wcx( xmin, ymin, tp ) );
01875             v[2] = plP_wcpcy( plP_w3wcy( xmin, ymin, tp ) );
01876             plnxtv( u, v, 0, 3, 0 );
01877 
01878             tp += tick;
01879         }
01880         u[0] = plP_wcpcx( plP_w3wcx( xmax, ymin, zmin ) );
01881         v[0] = plP_wcpcy( plP_w3wcy( xmax, ymin, zmin ) );
01882         u[1] = plP_wcpcx( plP_w3wcx( xmax, ymin, zmax ) );
01883         v[1] = plP_wcpcy( plP_w3wcy( xmax, ymin, zmax ) );
01884         plnxtv( u, v, 0, 2, 0 );
01885     }
01886     else if ( cxx <= 0.0 && cxy >= 0.0 )
01887     {
01888         while ( tp <= zmax )
01889         {
01890             u[0] = plP_wcpcx( plP_w3wcx( xmax, ymin, tp ) );
01891             v[0] = plP_wcpcy( plP_w3wcy( xmax, ymin, tp ) );
01892             u[1] = plP_wcpcx( plP_w3wcx( xmin, ymin, tp ) );
01893             v[1] = plP_wcpcy( plP_w3wcy( xmin, ymin, tp ) );
01894             u[2] = plP_wcpcx( plP_w3wcx( xmin, ymax, tp ) );
01895             v[2] = plP_wcpcy( plP_w3wcy( xmin, ymax, tp ) );
01896             plnxtv( u, v, 0, 3, 0 );
01897 
01898             tp += tick;
01899         }
01900         u[0] = plP_wcpcx( plP_w3wcx( xmin, ymin, zmin ) );
01901         v[0] = plP_wcpcy( plP_w3wcy( xmin, ymin, zmin ) );
01902         u[1] = plP_wcpcx( plP_w3wcx( xmin, ymin, zmax ) );
01903         v[1] = plP_wcpcy( plP_w3wcy( xmin, ymin, zmax ) );
01904         plnxtv( u, v, 0, 2, 0 );
01905     }
01906     else if ( cxx >= 0.0 && cxy >= 0.0 )
01907     {
01908         while ( tp <= zmax )
01909         {
01910             u[0] = plP_wcpcx( plP_w3wcx( xmin, ymin, tp ) );
01911             v[0] = plP_wcpcy( plP_w3wcy( xmin, ymin, tp ) );
01912             u[1] = plP_wcpcx( plP_w3wcx( xmin, ymax, tp ) );
01913             v[1] = plP_wcpcy( plP_w3wcy( xmin, ymax, tp ) );
01914             u[2] = plP_wcpcx( plP_w3wcx( xmax, ymax, tp ) );
01915             v[2] = plP_wcpcy( plP_w3wcy( xmax, ymax, tp ) );
01916             plnxtv( u, v, 0, 3, 0 );
01917 
01918             tp += tick;
01919         }
01920         u[0] = plP_wcpcx( plP_w3wcx( xmin, ymax, zmin ) );
01921         v[0] = plP_wcpcy( plP_w3wcy( xmin, ymax, zmin ) );
01922         u[1] = plP_wcpcx( plP_w3wcx( xmin, ymax, zmax ) );
01923         v[1] = plP_wcpcy( plP_w3wcy( xmin, ymax, zmax ) );
01924         plnxtv( u, v, 0, 2, 0 );
01925     }
01926     pl3upv = 1;
01927 }
01928 
01929 //--------------------------------------------------------------------------
01930 // void plnxtv()
01931 //
01932 // Draw the next view of a 3-d plot. The physical coordinates of the
01933 // points for the next view are placed in the n points of arrays u and
01934 // v. The silhouette found so far is stored in the heap as a set of m peak
01935 // points.
01936 //
01937 // These routines dynamically allocate memory for hidden line removal.
01938 // Memory is allocated in blocks of 2*BINC*sizeof(PLINT) bytes.  Large
01939 // values of BINC give better performance but also allocate more memory
01940 // than is needed. If your 3D plots are very "spiky" or you are working
01941 // with very large matrices then you will probably want to increase BINC.
01942 //--------------------------------------------------------------------------
01943 
01944 static void
01945 plnxtv( PLINT *u, PLINT *v, PLFLT* c, PLINT n, PLINT init )
01946 {
01947     plnxtvhi( u, v, c, n, init );
01948 
01949     if ( pl3mode )
01950         plnxtvlo( u, v, c, n, init );
01951 }
01952 
01953 //--------------------------------------------------------------------------
01954 // void plnxtvhi()
01955 //
01956 // Draw the top side of the 3-d plot.
01957 //--------------------------------------------------------------------------
01958 
01959 static void
01960 plnxtvhi( PLINT *u, PLINT *v, PLFLT* c, PLINT n, PLINT init )
01961 {
01962     //
01963     // For the initial set of points, just display them and store them as the
01964     // peak points.
01965     //
01966     if ( init == 1 )
01967     {
01968         int i;
01969         oldhiview = (PLINT *) malloc( (size_t) ( 2 * n * sizeof ( PLINT ) ) );
01970         if ( !oldhiview )
01971             myexit( "plnxtvhi: Out of memory." );
01972 
01973         oldhiview[0] = u[0];
01974         oldhiview[1] = v[0];
01975         plP_draw3d( u[0], v[0], c, 0, 1 );
01976         for ( i = 1; i < n; i++ )
01977         {
01978             oldhiview[2 * i]     = u[i];
01979             oldhiview[2 * i + 1] = v[i];
01980             plP_draw3d( u[i], v[i], c, i, 0 );
01981         }
01982         mhi = n;
01983         return;
01984     }
01985 
01986     //
01987     // Otherwise, we need to consider hidden-line removal problem. We scan
01988     // over the points in both the old (i.e. oldhiview[]) and new (i.e. u[]
01989     // and v[]) arrays in order of increasing x coordinate.  At each stage, we
01990     // find the line segment in the other array (if one exists) that straddles
01991     // the x coordinate of the point. We have to determine if the point lies
01992     // above or below the line segment, and to check if the below/above status
01993     // has changed since the last point.
01994     //
01995     // If pl3upv = 0 we do not update the view, this is useful for drawing
01996     // lines on the graph after we are done plotting points.  Hidden line
01997     // removal is still done, but the view is not updated.
01998     //
01999     xxhi = 0;
02000     if ( pl3upv != 0 )
02001     {
02002         newhisize = 2 * ( mhi + BINC );
02003         if ( newhiview != NULL )
02004         {
02005             newhiview =
02006                 (PLINT *) realloc( (void *) newhiview,
02007                     (size_t) ( newhisize * sizeof ( PLINT ) ) );
02008         }
02009         else
02010         {
02011             newhiview =
02012                 (PLINT *) malloc( (size_t) ( newhisize * sizeof ( PLINT ) ) );
02013         }
02014         if ( !newhiview )
02015             myexit( "plnxtvhi: Out of memory." );
02016     }
02017 
02018     // Do the draw or shading with hidden line removal
02019 
02020     plnxtvhi_draw( u, v, c, n );
02021 
02022     // Set oldhiview
02023 
02024     swaphiview();
02025 }
02026 
02027 //--------------------------------------------------------------------------
02028 // void plnxtvhi_draw()
02029 //
02030 // Draw the top side of the 3-d plot.
02031 //--------------------------------------------------------------------------
02032 
02033 static void
02034 plnxtvhi_draw( PLINT *u, PLINT *v, PLFLT* c, PLINT n )
02035 {
02036     PLINT i   = 0, j = 0, first = 1;
02037     PLINT sx1 = 0, sx2 = 0, sy1 = 0, sy2 = 0;
02038     PLINT su1, su2, sv1, sv2;
02039     PLINT cx, cy, px, py;
02040     PLINT seg, ptold, lstold = 0, pthi, pnewhi = 0, newhi, change, ochange = 0;
02041 
02042 //
02043 // (oldhiview[2*i], oldhiview[2*i]) is the i'th point in the old array
02044 // (u[j], v[j]) is the j'th point in the new array
02045 //
02046 
02047 //
02048 // First attempt at 3d shading.  It works ok for simple plots, but
02049 // will just not draw faces, or draw them overlapping for very
02050 // jagged plots
02051 //
02052 
02053     while ( i < mhi || j < n )
02054     {
02055         //
02056         // The coordinates of the point under consideration are (px,py).  The
02057         // line segment joins (sx1,sy1) to (sx2,sy2).  "ptold" is true if the
02058         // point lies in the old array. We set it by comparing the x coordinates
02059         // of the i'th old point and the j'th new point, being careful if we
02060         // have fallen past the edges. Having found the point, load up the point
02061         // and segment coordinates appropriately.
02062         //
02063 
02064         ptold = ( j >= n || ( i < mhi && oldhiview[2 * i] < u[j] ) );
02065         if ( ptold )
02066         {
02067             px  = oldhiview[2 * i];
02068             py  = oldhiview[2 * i + 1];
02069             seg = j > 0 && j < n;
02070             if ( seg )
02071             {
02072                 sx1 = u[j - 1];
02073                 sy1 = v[j - 1];
02074                 sx2 = u[j];
02075                 sy2 = v[j];
02076             }
02077         }
02078         else
02079         {
02080             px  = u[j];
02081             py  = v[j];
02082             seg = i > 0 && i < mhi;
02083             if ( seg )
02084             {
02085                 sx1 = oldhiview[2 * ( i - 1 )];
02086                 sy1 = oldhiview[2 * ( i - 1 ) + 1];
02087                 sx2 = oldhiview[2 * i];
02088                 sy2 = oldhiview[2 * i + 1];
02089             }
02090         }
02091 
02092         //
02093         // Now determine if the point is higher than the segment, using the
02094         // logical function "above". We also need to know if it is the old view
02095         // or the new view that is higher. "newhi" is set true if the new view
02096         // is higher than the old.
02097         //
02098         if ( seg )
02099             pthi = plabv( px, py, sx1, sy1, sx2, sy2 );
02100         else
02101             pthi = 1;
02102 
02103         newhi = ( ptold && !pthi ) || ( !ptold && pthi );
02104         //
02105         // The last point and this point lie on different sides of
02106         // the current silouette
02107         //
02108         change = ( newhi && !pnewhi ) || ( !newhi && pnewhi );
02109 
02110         //
02111         // There is a new intersection point to put in the peak array if the
02112         // state of "newhi" changes.
02113         //
02114         if ( first )
02115         {
02116             plP_draw3d( px, py, c, j, 1 );
02117             first  = 0;
02118             lstold = ptold;
02119             savehipoint( px, py );
02120             pthi    = 0;
02121             ochange = 0;
02122         }
02123         else if ( change )
02124         {
02125             //
02126             // Take care of special cases at end of arrays.  If pl3upv is 0 the
02127             // endpoints are not connected to the old view.
02128             //
02129             if ( pl3upv == 0 && ( ( !ptold && j == 0 ) || ( ptold && i == 0 ) ) )
02130             {
02131                 plP_draw3d( px, py, c, j, 1 );
02132                 lstold  = ptold;
02133                 pthi    = 0;
02134                 ochange = 0;
02135             }
02136             else if ( pl3upv == 0 &&
02137                       ( ( !ptold && i >= mhi ) || ( ptold && j >= n ) ) )
02138             {
02139                 plP_draw3d( px, py, c, j, 1 );
02140                 lstold  = ptold;
02141                 pthi    = 0;
02142                 ochange = 0;
02143             }
02144             else
02145             {
02146                 //
02147                 // If pl3upv is not 0 then we do want to connect the current line
02148                 // with the previous view at the endpoints.  Also find intersection
02149                 // point with old view.
02150                 //
02151                 if ( i == 0 )
02152                 {
02153                     sx1 = oldhiview[0];
02154                     sy1 = -1;
02155                     sx2 = oldhiview[0];
02156                     sy2 = oldhiview[1];
02157                 }
02158                 else if ( i >= mhi )
02159                 {
02160                     sx1 = oldhiview[2 * ( mhi - 1 )];
02161                     sy1 = oldhiview[2 * ( mhi - 1 ) + 1];
02162                     sx2 = oldhiview[2 * ( mhi - 1 )];
02163                     sy2 = -1;
02164                 }
02165                 else
02166                 {
02167                     sx1 = oldhiview[2 * ( i - 1 )];
02168                     sy1 = oldhiview[2 * ( i - 1 ) + 1];
02169                     sx2 = oldhiview[2 * i];
02170                     sy2 = oldhiview[2 * i + 1];
02171                 }
02172 
02173                 if ( j == 0 )
02174                 {
02175                     su1 = u[0];
02176                     sv1 = -1;
02177                     su2 = u[0];
02178                     sv2 = v[0];
02179                 }
02180                 else if ( j >= n )
02181                 {
02182                     su1 = u[n - 1];
02183                     sv1 = v[n - 1];
02184                     su2 = u[n - 1];
02185                     sv2 = -1;
02186                 }
02187                 else
02188                 {
02189                     su1 = u[j - 1];
02190                     sv1 = v[j - 1];
02191                     su2 = u[j];
02192                     sv2 = v[j];
02193                 }
02194 
02195                 // Determine the intersection
02196 
02197                 pl3cut( sx1, sy1, sx2, sy2, su1, sv1, su2, sv2, &cx, &cy );
02198                 if ( cx == px && cy == py )
02199                 {
02200                     if ( lstold && !ochange )
02201                         plP_draw3d( px, py, c, j, 1 );
02202                     else
02203                         plP_draw3d( px, py, c, j, 0 );
02204 
02205                     savehipoint( px, py );
02206                     lstold = 1;
02207                     pthi   = 0;
02208                 }
02209                 else
02210                 {
02211                     if ( lstold && !ochange )
02212                         plP_draw3d( cx, cy, c, j, 1 );
02213                     else
02214                         plP_draw3d( cx, cy, c, j, 0 );
02215 
02216                     lstold = 1;
02217                     savehipoint( cx, cy );
02218                 }
02219                 ochange = 1;
02220             }
02221         }
02222 
02223         // If point is high then draw plot to point and update view.
02224 
02225         if ( pthi )
02226         {
02227             if ( lstold && ptold )
02228                 plP_draw3d( px, py, c, j, 1 );
02229             else
02230                 plP_draw3d( px, py, c, j, 0 );
02231 
02232             savehipoint( px, py );
02233             lstold  = ptold;
02234             ochange = 0;
02235         }
02236         pnewhi = newhi;
02237 
02238         if ( ptold )
02239             i++;
02240         else
02241             j++;
02242     }
02243 }
02244 
02245 //--------------------------------------------------------------------------
02246 // void  plP_draw3d()
02247 //
02248 // Does a simple move or line draw.
02249 //--------------------------------------------------------------------------
02250 
02251 static void
02252 plP_draw3d( PLINT x, PLINT y, PLFLT *c, PLINT j, PLINT move )
02253 {
02254     if ( move )
02255         plP_movphy( x, y );
02256     else
02257     {
02258         if ( c != NULL )
02259             plcol1( c[j - 1] );
02260         plP_draphy( x, y );
02261     }
02262 }
02263 
02264 //--------------------------------------------------------------------------
02265 // void plnxtvlo()
02266 //
02267 // Draw the bottom side of the 3-d plot.
02268 //--------------------------------------------------------------------------
02269 
02270 static void
02271 plnxtvlo( PLINT *u, PLINT *v, PLFLT*c, PLINT n, PLINT init )
02272 {
02273     PLINT i, j, first;
02274     PLINT sx1 = 0, sx2 = 0, sy1 = 0, sy2 = 0;
02275     PLINT su1, su2, sv1, sv2;
02276     PLINT cx, cy, px, py;
02277     PLINT seg, ptold, lstold = 0, ptlo, pnewlo, newlo, change, ochange = 0;
02278 
02279     first  = 1;
02280     pnewlo = 0;
02281 
02282     //
02283     // For the initial set of points, just display them and store them as the
02284     // peak points.
02285     //
02286     if ( init == 1 )
02287     {
02288         oldloview = (PLINT *) malloc( (size_t) ( 2 * n * sizeof ( PLINT ) ) );
02289         if ( !oldloview )
02290             myexit( "\nplnxtvlo: Out of memory." );
02291 
02292         plP_draw3d( u[0], v[0], c, 0, 1 );
02293         oldloview[0] = u[0];
02294         oldloview[1] = v[0];
02295         for ( i = 1; i < n; i++ )
02296         {
02297             plP_draw3d( u[i], v[i], c, i, 0 );
02298             oldloview[2 * i]     = u[i];
02299             oldloview[2 * i + 1] = v[i];
02300         }
02301         mlo = n;
02302         return;
02303     }
02304 
02305     //
02306     // Otherwise, we need to consider hidden-line removal problem. We scan
02307     // over the points in both the old (i.e. oldloview[]) and new (i.e. u[]
02308     // and v[]) arrays in order of increasing x coordinate.  At each stage, we
02309     // find the line segment in the other array (if one exists) that straddles
02310     // the x coordinate of the point. We have to determine if the point lies
02311     // above or below the line segment, and to check if the below/above status
02312     // has changed since the last point.
02313     //
02314     // If pl3upv = 0 we do not update the view, this is useful for drawing
02315     // lines on the graph after we are done plotting points.  Hidden line
02316     // removal is still done, but the view is not updated.
02317     //
02318     xxlo = 0;
02319     i    = 0;
02320     j    = 0;
02321     if ( pl3upv != 0 )
02322     {
02323         newlosize = 2 * ( mlo + BINC );
02324         if ( newloview != NULL )
02325         {
02326             newloview =
02327                 (PLINT *) realloc( (void *) newloview,
02328                     (size_t) ( newlosize * sizeof ( PLINT ) ) );
02329         }
02330         else
02331         {
02332             newloview =
02333                 (PLINT *) malloc( (size_t) ( newlosize * sizeof ( PLINT ) ) );
02334         }
02335         if ( !newloview )
02336             myexit( "plnxtvlo: Out of memory." );
02337     }
02338 
02339     //
02340     // (oldloview[2*i], oldloview[2*i]) is the i'th point in the old array
02341     // (u[j], v[j]) is the j'th point in the new array.
02342     //
02343     while ( i < mlo || j < n )
02344     {
02345         //
02346         // The coordinates of the point under consideration are (px,py).  The
02347         // line segment joins (sx1,sy1) to (sx2,sy2).  "ptold" is true if the
02348         // point lies in the old array. We set it by comparing the x coordinates
02349         // of the i'th old point and the j'th new point, being careful if we
02350         // have fallen past the edges. Having found the point, load up the point
02351         // and segment coordinates appropriately.
02352         //
02353         ptold = ( j >= n || ( i < mlo && oldloview[2 * i] < u[j] ) );
02354         if ( ptold )
02355         {
02356             px  = oldloview[2 * i];
02357             py  = oldloview[2 * i + 1];
02358             seg = j > 0 && j < n;
02359             if ( seg )
02360             {
02361                 sx1 = u[j - 1];
02362                 sy1 = v[j - 1];
02363                 sx2 = u[j];
02364                 sy2 = v[j];
02365             }
02366         }
02367         else
02368         {
02369             px  = u[j];
02370             py  = v[j];
02371             seg = i > 0 && i < mlo;
02372             if ( seg )
02373             {
02374                 sx1 = oldloview[2 * ( i - 1 )];
02375                 sy1 = oldloview[2 * ( i - 1 ) + 1];
02376                 sx2 = oldloview[2 * i];
02377                 sy2 = oldloview[2 * i + 1];
02378             }
02379         }
02380 
02381         //
02382         // Now determine if the point is lower than the segment, using the
02383         // logical function "above". We also need to know if it is the old view
02384         // or the new view that is lower. "newlo" is set true if the new view is
02385         // lower than the old.
02386         //
02387         if ( seg )
02388             ptlo = !plabv( px, py, sx1, sy1, sx2, sy2 );
02389         else
02390             ptlo = 1;
02391 
02392         newlo  = ( ptold && !ptlo ) || ( !ptold && ptlo );
02393         change = ( newlo && !pnewlo ) || ( !newlo && pnewlo );
02394 
02395         //
02396         // There is a new intersection point to put in the peak array if the
02397         // state of "newlo" changes.
02398         //
02399         if ( first )
02400         {
02401             plP_draw3d( px, py, c, j, 1 );
02402             first  = 0;
02403             lstold = ptold;
02404             savelopoint( px, py );
02405             ptlo    = 0;
02406             ochange = 0;
02407         }
02408         else if ( change )
02409         {
02410             //
02411             // Take care of special cases at end of arrays.  If pl3upv is 0 the
02412             // endpoints are not connected to the old view.
02413             //
02414             if ( pl3upv == 0 && ( ( !ptold && j == 0 ) || ( ptold && i == 0 ) ) )
02415             {
02416                 plP_draw3d( px, py, c, j, 1 );
02417                 lstold  = ptold;
02418                 ptlo    = 0;
02419                 ochange = 0;
02420             }
02421             else if ( pl3upv == 0 &&
02422                       ( ( !ptold && i >= mlo ) || ( ptold && j >= n ) ) )
02423             {
02424                 plP_draw3d( px, py, c, j, 1 );
02425                 lstold  = ptold;
02426                 ptlo    = 0;
02427                 ochange = 0;
02428             }
02429 
02430             //
02431             // If pl3upv is not 0 then we do want to connect the current line
02432             // with the previous view at the endpoints.  Also find intersection
02433             // point with old view.
02434             //
02435             else
02436             {
02437                 if ( i == 0 )
02438                 {
02439                     sx1 = oldloview[0];
02440                     sy1 = 100000;
02441                     sx2 = oldloview[0];
02442                     sy2 = oldloview[1];
02443                 }
02444                 else if ( i >= mlo )
02445                 {
02446                     sx1 = oldloview[2 * ( mlo - 1 )];
02447                     sy1 = oldloview[2 * ( mlo - 1 ) + 1];
02448                     sx2 = oldloview[2 * ( mlo - 1 )];
02449                     sy2 = 100000;
02450                 }
02451                 else
02452                 {
02453                     sx1 = oldloview[2 * ( i - 1 )];
02454                     sy1 = oldloview[2 * ( i - 1 ) + 1];
02455                     sx2 = oldloview[2 * i];
02456                     sy2 = oldloview[2 * i + 1];
02457                 }
02458 
02459                 if ( j == 0 )
02460                 {
02461                     su1 = u[0];
02462                     sv1 = 100000;
02463                     su2 = u[0];
02464                     sv2 = v[0];
02465                 }
02466                 else if ( j >= n )
02467                 {
02468                     su1 = u[n - 1];
02469                     sv1 = v[n - 1];
02470                     su2 = u[n];
02471                     sv2 = 100000;
02472                 }
02473                 else
02474                 {
02475                     su1 = u[j - 1];
02476                     sv1 = v[j - 1];
02477                     su2 = u[j];
02478                     sv2 = v[j];
02479                 }
02480 
02481                 // Determine the intersection
02482 
02483                 pl3cut( sx1, sy1, sx2, sy2, su1, sv1, su2, sv2, &cx, &cy );
02484                 if ( cx == px && cy == py )
02485                 {
02486                     if ( lstold && !ochange )
02487                         plP_draw3d( px, py, c, j, 1 );
02488                     else
02489                         plP_draw3d( px, py, c, j, 0 );
02490 
02491                     savelopoint( px, py );
02492                     lstold = 1;
02493                     ptlo   = 0;
02494                 }
02495                 else
02496                 {
02497                     if ( lstold && !ochange )
02498                         plP_draw3d( cx, cy, c, j, 1 );
02499                     else
02500                         plP_draw3d( cx, cy, c, j, 0 );
02501 
02502                     lstold = 1;
02503                     savelopoint( cx, cy );
02504                 }
02505                 ochange = 1;
02506             }
02507         }
02508 
02509         // If point is low then draw plot to point and update view.
02510 
02511         if ( ptlo )
02512         {
02513             if ( lstold && ptold )
02514                 plP_draw3d( px, py, c, j, 1 );
02515             else
02516                 plP_draw3d( px, py, c, j, 0 );
02517 
02518             savelopoint( px, py );
02519             lstold  = ptold;
02520             ochange = 0;
02521         }
02522 
02523         pnewlo = newlo;
02524 
02525         if ( ptold )
02526             i = i + 1;
02527         else
02528             j = j + 1;
02529     }
02530 
02531     // Set oldloview
02532 
02533     swaploview();
02534 }
02535 
02536 //--------------------------------------------------------------------------
02537 // savehipoint
02538 // savelopoint
02539 //
02540 // Add a point to the list of currently visible peaks/valleys, when
02541 // drawing the top/bottom surface, respectively.
02542 //--------------------------------------------------------------------------
02543 
02544 static void
02545 savehipoint( PLINT px, PLINT py )
02546 {
02547     if ( pl3upv == 0 )
02548         return;
02549 
02550     if ( xxhi >= newhisize )      // allocate additional space
02551     {
02552         newhisize += 2 * BINC;
02553         newhiview  = (PLINT *) realloc( (void *) newhiview,
02554             (size_t) ( newhisize * sizeof ( PLINT ) ) );
02555         if ( !newhiview )
02556             myexit( "savehipoint: Out of memory." );
02557     }
02558 
02559     newhiview[xxhi] = px;
02560     xxhi++;
02561     newhiview[xxhi] = py;
02562     xxhi++;
02563 }
02564 
02565 static void
02566 savelopoint( PLINT px, PLINT py )
02567 {
02568     if ( pl3upv == 0 )
02569         return;
02570 
02571     if ( xxlo >= newlosize )      // allocate additional space
02572     {
02573         newlosize += 2 * BINC;
02574         newloview  = (PLINT *) realloc( (void *) newloview,
02575             (size_t) ( newlosize * sizeof ( PLINT ) ) );
02576         if ( !newloview )
02577             myexit( "savelopoint: Out of memory." );
02578     }
02579 
02580     newloview[xxlo] = px;
02581     xxlo++;
02582     newloview[xxlo] = py;
02583     xxlo++;
02584 }
02585 
02586 //--------------------------------------------------------------------------
02587 // swaphiview
02588 // swaploview
02589 //
02590 // Swaps the top/bottom views.  Need to do a real swap so that the
02591 // memory cleanup routine really frees everything (and only once).
02592 //--------------------------------------------------------------------------
02593 
02594 static void
02595 swaphiview( void )
02596 {
02597     PLINT *tmp;
02598 
02599     if ( pl3upv != 0 )
02600     {
02601         mhi       = xxhi / 2;
02602         tmp       = oldhiview;
02603         oldhiview = newhiview;
02604         newhiview = tmp;
02605     }
02606 }
02607 
02608 static void
02609 swaploview( void )
02610 {
02611     PLINT *tmp;
02612 
02613     if ( pl3upv != 0 )
02614     {
02615         mlo       = xxlo / 2;
02616         tmp       = oldloview;
02617         oldloview = newloview;
02618         newloview = tmp;
02619     }
02620 }
02621 
02622 //--------------------------------------------------------------------------
02623 // freework
02624 //
02625 // Frees memory associated with work arrays
02626 //--------------------------------------------------------------------------
02627 
02628 static void
02629 freework( void )
02630 {
02631     free_mem( oldhiview );
02632     free_mem( oldloview );
02633     free_mem( newhiview );
02634     free_mem( newloview );
02635     free_mem( vtmp );
02636     free_mem( utmp );
02637     free_mem( ctmp );
02638 }
02639 
02640 //--------------------------------------------------------------------------
02641 // myexit
02642 //
02643 // Calls plexit, cleaning up first.
02644 //--------------------------------------------------------------------------
02645 
02646 static void
02647 myexit( char *msg )
02648 {
02649     freework();
02650     plexit( msg );
02651 }
02652 
02653 //--------------------------------------------------------------------------
02654 // myabort
02655 //
02656 // Calls plabort, cleaning up first.
02657 // Caller should return to the user program.
02658 //--------------------------------------------------------------------------
02659 
02660 static void
02661 myabort( char *msg )
02662 {
02663     freework();
02664     plabort( msg );
02665 }
02666 
02667 //--------------------------------------------------------------------------
02668 // int plabv()
02669 //
02670 // Determines if point (px,py) lies above the line joining (sx1,sy1) to
02671 // (sx2,sy2). It only works correctly if sx1 <= px <= sx2.
02672 //--------------------------------------------------------------------------
02673 
02674 static int
02675 plabv( PLINT px, PLINT py, PLINT sx1, PLINT sy1, PLINT sx2, PLINT sy2 )
02676 {
02677     int above;
02678 
02679     if ( py >= sy1 && py >= sy2 )
02680         above = 1;
02681     else if ( py < sy1 && py < sy2 )
02682         above = 0;
02683     else if ( (double) ( sx2 - sx1 ) * ( py - sy1 ) >=
02684               (double) ( px - sx1 ) * ( sy2 - sy1 ) )
02685         above = 1;
02686     else
02687         above = 0;
02688 
02689     return above;
02690 }
02691 
02692 //--------------------------------------------------------------------------
02693 // void pl3cut()
02694 //
02695 // Determines the point of intersection (cx,cy) between the line joining
02696 // (sx1,sy1) to (sx2,sy2) and the line joining (su1,sv1) to (su2,sv2).
02697 //--------------------------------------------------------------------------
02698 
02699 static void
02700 pl3cut( PLINT sx1, PLINT sy1, PLINT sx2, PLINT sy2,
02701         PLINT su1, PLINT sv1, PLINT su2, PLINT sv2, PLINT *cx, PLINT *cy )
02702 {
02703     PLINT x21, y21, u21, v21, yv1, xu1, a, b;
02704     double fa, fb;
02705 
02706     x21 = sx2 - sx1;
02707     y21 = sy2 - sy1;
02708     u21 = su2 - su1;
02709     v21 = sv2 - sv1;
02710     yv1 = sy1 - sv1;
02711     xu1 = sx1 - su1;
02712 
02713     a  = x21 * v21 - y21 * u21;
02714     fa = (double) a;
02715     if ( a == 0 )
02716     {
02717         if ( sx2 < su2 )
02718         {
02719             *cx = sx2;
02720             *cy = sy2;
02721         }
02722         else
02723         {
02724             *cx = su2;
02725             *cy = sv2;
02726         }
02727         return;
02728     }
02729     else
02730     {
02731         b   = yv1 * u21 - xu1 * v21;
02732         fb  = (double) b;
02733         *cx = (PLINT) ( sx1 + ( fb * x21 ) / fa + .5 );
02734         *cy = (PLINT) ( sy1 + ( fb * y21 ) / fa + .5 );
02735     }
02736 }
02737 
02738 //--------------------------------------------------------------------------
02739 // void plRotationShear
02740 //
02741 // Calculates the rotation and shear angles from a plplot transformation matrix
02742 //
02743 // N.B. the plot transformation matrix
02744 //
02745 // [xFormMatrix[0] xFormMatrix[2]]
02746 // [xFormMatrix[1] xFormMatrix[3]]
02747 //
02748 // is calculated as
02749 //
02750 // [stride cos(t)    stride sin(t)]
02751 // [sin(p-t)              cos(p-t)]
02752 //
02753 // where t is the rotation angle and p is the shear angle.
02754 // The purpose of this routine is to determine stride, rotation angle,
02755 // and shear angle from xFormMatrix.
02756 //
02757 // For information only, xFormMatrix is the product of the following
02758 // rotation, skew(shear), and scale matrices:
02759 //
02760 //  [stride    0] [1      0] [cos(t)  sin(t)]
02761 //  [0    cos(p)] [tan(p) 1] [-sin(t) cos(t)]
02762 //
02763 //--------------------------------------------------------------------------
02764 
02765 void
02766 plRotationShear( PLFLT *xFormMatrix, PLFLT *rotation, PLFLT *shear, PLFLT *stride )
02767 {
02768     PLFLT smr;
02769     *stride = sqrt( xFormMatrix[0] * xFormMatrix[0] + xFormMatrix[2] * xFormMatrix[2] );
02770 
02771     // Calculate rotation in range from -pi to pi.
02772     *rotation = atan2( xFormMatrix[2], xFormMatrix[0] );
02773 
02774     // Calculate shear - rotation in range from -pi to pi.
02775     smr = atan2( xFormMatrix[1], xFormMatrix[3] );
02776 
02777     // Calculate shear in range from -2 pi to 2 pi.
02778     *shear = smr + *rotation;
02779 
02780     // Calculate shear in range from -pi to pi.
02781     if ( *shear < -PI )
02782         *shear += 2. * PI;
02783     else if ( *shear > PI )
02784         *shear -= 2. * PI;
02785 
02786     // Actually must honour some convention to calculate the negative
02787     // of the shear angle instead of the shear angle. Why??
02788     *shear = -*shear;
02789     // Comment out the modified old logic which determines the negative
02790     // of the shear angle in a more complicated way.  Note, the modification
02791     // to divide the asin argument by *stride which solved a long-standing
02792     // bug (as does the above logic in a simpler way).
02793     //
02794     //shear = -asin( (xFormMatrix[0] * xFormMatrix[1] +
02795     //               xFormMatrix[2] * xFormMatrix[3] )/ *stride);
02796     //
02797 
02798     // Compute the cross product of the vectors [1,0] and [0,1] to
02799     // determine if we need to make a "quadrant 3,4" adjustment
02800     // to the shear angle.
02801 
02802     //
02803     // if ( xFormMatrix[0] * xFormMatrix[3] - xFormMatrix[1] * xFormMatrix[2] < 0.0 )
02804     // {
02805     //shear = -( M_PI + *shear );
02806     // }
02807     //
02808 }
02809 

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