//-------------------------------------------------------------------------- // Copyright (C) 1994 Geoffrey Furnish // Copyright (C) 1995, 2000 Maurice LeBrun // Copyright (C) 2002-2014 Alan W. Irwin // Copyright (C) 2004 Andrew Ross // // This file is part of PLplot. // // PLplot is free software; you can redistribute it and/or modify // it under the terms of the GNU Library General Public License as published by // the Free Software Foundation; version 2 of the License. // // PLplot is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Library General Public License for more details. // // You should have received a copy of the GNU Library General Public License // along with PLplot; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //-------------------------------------------------------------------------- // //-------------------------------------------------------------------------- // This example program demonstrates the use of the plstream C++ class, and // some aspects of its improvements over the klunky C API, mostly those // relating to 2-d plotting. //-------------------------------------------------------------------------- #include "plc++demos.h" #ifdef PL_USE_NAMESPACE using namespace std; #endif //-------------------------------------------------------------------------- // In the real world, the user has his own Matrix class, so he just includes // the header for it. Here we conjure up a dopey stand in. class Matrix { int nx, ny; PLFLT *v; public: Matrix( int _nx, int _ny ) : nx( _nx ), ny( _ny ) { v = new PLFLT[nx * ny]; } ~Matrix() { delete[] v; } PLFLT & operator()( int i, int j ) { // Should do bounds checking, pass for now. return v[ j * ny + i ]; } PLFLT operator()( int i, int j ) const { // Should do bounds checking, pass for now. return v[ j * ny + i ]; } void redim( int i, int j ) { delete[] v; nx = i, ny = j; v = new PLFLT[nx * ny]; } }; //-------------------------------------------------------------------------- // To perform contouring, we have to concretize the abstract contouring // interface. Do this by deriving from Contourable_Data, and implementing // the indexing operator. class ContourableMatrix : public Contourable_Data { int nx, ny; Matrix m; int wrapy; // periodic in 2nd coord ? public: ContourableMatrix( int _nx, int _ny, int wy = 0 ) : Contourable_Data( _nx, _ny ), nx( _nx ), ny( _ny ), m( nx, ny ), wrapy( wy ) {} void elements( int& _nx, int& _ny ) const { _nx = nx; if ( wrapy ) _ny = ny + 1; else _ny = ny; } PLFLT & operator()( int i, int j ) { if ( wrapy ) j %= ny; return m( i, j ); } PLFLT operator()( int i, int j ) const { if ( wrapy ) j %= ny; return m( i, j ); } }; //-------------------------------------------------------------------------- // For general mesh plotting, we also need to concretize the abstract // coordinate interface. Do this by deriving from Coord_2d and filling in // the blanks. class CoordinateMatrix : public Coord_2d { int nx, ny; Matrix m; int wrapy; public: CoordinateMatrix( int _nx, int _ny, int wy = 0 ) : nx( _nx ), ny( _ny ), m( nx, ny ), wrapy( wy ) {} PLFLT operator()( int ix, int iy ) const { if ( wrapy ) iy %= ny; return m( ix, iy ); } PLFLT & operator()( int ix, int iy ) { if ( wrapy ) iy %= ny; return m( ix, iy ); } void elements( int& _nx, int& _ny ) { _nx = nx; if ( wrapy ) _ny = ny + 1; else _ny = ny; } void min_max( PLFLT& _min, PLFLT& _max ) { _min = _max = m( 0, 0 ); for ( int i = 0; i < nx; i++ ) for ( int j = 0; j < ny; j++ ) { if ( m( i, j ) < _min ) _min = m( i, j ); if ( m( i, j ) > _max ) _max = m( i, j ); } } }; class x01cc { public: x01cc( int, char ** ); void plot1(); void plot2(); private: plstream *pls; }; //-------------------------------------------------------------------------- // Just a simple little routine to show simple use of the plstream object. //-------------------------------------------------------------------------- void x01cc::plot1() { pls->col( Red ); pls->env( 0., 1., 0., 1., 0, 0 ); pls->col( Yellow ); pls->lab( "(x)", "(y)", "#frPLplot Example 1 - y=x#u2" ); PLFLT x[6], y[6]; for ( int i = 0; i < 6; i++ ) { x[i] = .2 * i; y[i] = x[i] * x[i]; } pls->col( Cyan ); pls->poin( 6, x, y, 9 ); pls->col( Green ); pls->line( 6, x, y ); } //-------------------------------------------------------------------------- // Demonstration of contouring using the C++ abstract interface which does // not impose fascist requirements on storage order/format of user data as // the C and Fortran API's do. //-------------------------------------------------------------------------- void x01cc::plot2() { pls->adv( 0 ); // First declare some objects to hold the data and the coordinates. Note, // if you don't want to go to the trouble of making these derived classes so // easy to use (const and non-const indexing operators, etc), such as if you // have existing code using a Matrix class, and all you want to do now is // plot it, then you could just make these derived classes have a // constructor taking a Matrix (previously calculated somewhere else) by // reference through the constructor. That way the calculation engine can // continue to use the normal container class, and only the plotting code // needs the auxiliary class to concretize the C++ abstract contouring // interface. // Since this is a "polar" plot ( :-), see below), we need to enable the // "wrapy" option in our special purpose data and coordinate classes. Note // that this allows "reconnection" of lines, etc, with trivial effort, IFF // done from C++. For C-- and Dogtran, one would have to copy the data to a // new buffer, and pad one side with an image copy of the other side. ContourableMatrix d( 64, 64, 1 ); CoordinateMatrix xg( 64, 64, 1 ), yg( 64, 64, 1 ); int i, j; PLFLT twopi = 2. * 3.1415927; // Set up the data and coordinate matrices. for ( i = 0; i < 64; i++ ) { PLFLT r = i / 64.; for ( j = 0; j < 64; j++ ) { PLFLT theta = twopi * j / 64.; xg( i, j ) = r * cos( theta ); yg( i, j ) = r * sin( theta );; d( i, j ) = exp( -r * r ) * cos( twopi * 2 * r ) * sin( 3 * theta ); } } // Now draw a normal shaded plot. PLFLT zmin = -1., zmax = 1.; int NCONTR = 20; PLFLT shade_min, shade_max, sh_color; int sh_cmap = 1, sh_width; int min_color = 1, min_width = 0, max_color = 0, max_width = 0; pls->vpor( .1, .9, .1, .9 ); pls->wind( 0., 1., 0., twopi ); for ( i = 0; i < NCONTR; i++ ) { shade_min = zmin + ( zmax - zmin ) * i / (PLFLT) NCONTR; shade_max = zmin + ( zmax - zmin ) * ( i + 1 ) / (PLFLT) NCONTR; sh_color = i / (PLFLT) ( NCONTR - 1 ); sh_width = 2; pls->psty( 0 ); pls->shade( d, 0., 1., 0., twopi, shade_min, shade_max, sh_cmap, sh_color, sh_width, min_color, min_width, max_color, max_width, true, NULL ); } pls->col( Red ); pls->box( "bcnst", 0.0, 0, "bcnstv", 0.0, 0 ); // Now do it again, but with the coordinate transformation taken into // account. pls->adv( 0 ); cxx_pltr2 tr( xg, yg ); pls->vpas( .1, .9, .1, .9, 1. ); pls->wind( -1., 1., -1., 1. ); for ( i = 0; i < NCONTR; i++ ) { shade_min = zmin + ( zmax - zmin ) * i / (PLFLT) NCONTR; shade_max = zmin + ( zmax - zmin ) * ( i + 1 ) / (PLFLT) NCONTR; sh_color = i / (PLFLT) ( NCONTR - 1 ); sh_width = 2; pls->psty( 0 ); pls->shade( d, 0., 1., 0., twopi, shade_min, shade_max, sh_cmap, sh_color, sh_width, min_color, min_width, max_color, max_width, false, &tr ); } pls->col( Red ); // Now draw the border around the drawing region. PLFLT x[65], y[65]; for ( i = 0; i < 65; i++ ) { x[i] = xg( 63, i ); y[i] = yg( 63, i ); } pls->line( 65, x, y ); // Finally, let's "squoosh" the plot, and draw it all again. PLFLT X1 = 1., X2 = .1, Y1 = 1.2, Y2 = -.2; for ( i = 0; i < 64; i++ ) { PLFLT r = i / 64.; for ( j = 0; j < 64; j++ ) { PLFLT theta = twopi * j / 64.; xg( i, j ) = X1 * r * cos( theta ) + X2 * r * r * cos( 2 * theta ); yg( i, j ) = Y1 * r * sin( theta ) + Y2 * r * r * sin( 2 * theta ); } } PLFLT xmin, xmax, ymin, ymax; xg.min_max( xmin, xmax ), yg.min_max( ymin, ymax ); pls->adv( 0 ); pls->vpas( .1, .9, .1, .9, 1. ); pls->wind( xmin, xmax, ymin, ymax ); for ( i = 0; i < NCONTR; i++ ) { shade_min = zmin + ( zmax - zmin ) * i / (PLFLT) NCONTR; shade_max = zmin + ( zmax - zmin ) * ( i + 1 ) / (PLFLT) NCONTR; sh_color = i / (PLFLT) ( NCONTR - 1 ); sh_width = 2; pls->psty( 0 ); pls->shade( d, 0., 1., 0., twopi, shade_min, shade_max, sh_cmap, sh_color, sh_width, min_color, min_width, max_color, max_width, false, &tr ); } pls->col( Red ); // Now draw the border around the drawing region. for ( i = 0; i < 65; i++ ) { x[i] = xg( 63, i ); y[i] = yg( 63, i ); } pls->line( 65, x, y ); } x01cc::x01cc( int argc, char **argv ) { pls = new plstream(); // Parse and process command line arguments. pls->parseopts( &argc, argv, PL_PARSE_FULL ); // Initialize plplot. pls->init(); plot1(); plot2(); delete pls; } //-------------------------------------------------------------------------- // Finally! //-------------------------------------------------------------------------- int main( int argc, char **argv ) { x01cc *x = new x01cc( argc, argv ); delete x; } //-------------------------------------------------------------------------- // End of x01cc.cc //--------------------------------------------------------------------------