1 //--------------------------------------------------------------------------
2 // Copyright (C) 2004,2006  Andrew Ross
3 // Copyright (C) 2004-2014  Alan W. Irwin
4 //
5 // This file is part of PLplot.
6 //
7 // PLplot is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU Library General Public License as published by
9 // the Free Software Foundation; version 2 of the License.
10 //
11 // PLplot is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU Library General Public License for more details.
15 //
16 // You should have received a copy of the GNU Library General Public License
17 // along with PLplot; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19 //--------------------------------------------------------------------------
20 //
21 //--------------------------------------------------------------------------
22 // Implementation of PLplot example 20 in Java.
23 //--------------------------------------------------------------------------
24 
25 //
26 // Current user defined command line options are not supported in
27 // the Java bindings
28 //
29 
30 package plplot.examples;
31 
32 import plplot.core.*;
33 import static plplot.core.plplotjavacConstants.*;
34 
35 import java.io.*;
36 import java.util.*;
37 
38 class x20 {
39     // Class data
40     PLStream       pls = new PLStream();
41 
42     static int     XDIM          = 260;
43     static int     YDIM          = 220;
44     static boolean dbg           = false;
45     static boolean nosombrero    = false;
46     static boolean nointeractive = false;
47     static String  f_name        = null;
48 
49     //static PLOptionTable options[];
50 
51     // PLOptionTable options[] = {
52     // {
53     //     "dbg",			/* extra debugging plot */
54     //     NULL,
55     //     NULL,
56     //     &dbg,
57     //     PL_OPT_BOOL,
58     //     "-dbg",
59     //     "Extra debugging plot" },
60     // {
61     //     "nosombrero",			/* Turns on test of xor function */
62     //     NULL,
63     //     NULL,
64     //     &nosombrero,
65     //     PL_OPT_BOOL,
66     //     "-nosombrero",
67     //     "No sombrero plot" },
68     // {
69     //     "nointeractive",			/* Turns on test of xor function */
70     //     NULL,
71     //     NULL,
72     //     &nointeractive,
73     //     PL_OPT_BOOL,
74     //     "-nointeractive",
75     //     "No interactive selection" },
76     // {
77     //     "save",			/* For saving in postscript */
78     //     NULL,
79     //     NULL,
80     //     &f_name,
81     //     PL_OPT_STRING,
82     //     "-save filename",
83     //       "Save sombrero plot in color postscript `filename'" },
84     // {
85     //     NULL,			/* option */
86     //     NULL,			/* handler */
87     //     NULL,			/* client data */
88     //     NULL,			/* address of variable to set */
89     //     0,				/* mode flag */
90     //     NULL,			/* short syntax */
91     //     NULL }			/* long syntax */
92     // };
93 
94 
95     x20( String[] args )
96     {
97         double x[]   = new double[XDIM];
98         double y[]   = new double[YDIM];
99         double z[][] = new double[XDIM][YDIM];
100         double r[][];
101         double xi[] = new double[1];
102         double yi[] = new double[1];
103         double xe[] = new double[1];
104         double ye[] = new double[1];
105         int    i, j, width, height, num_col;
106         int    n[] = new int[1];
107         double img_f[][];
108         double img_min;
109         double img_max;
110         double maxmin[] = new double[2];
111         double x0, y0, dy, stretch;
112         double deltax, deltay, xg[][], yg[][];
113 
114 
115         // plplot initialization
116 
117         // Parse and process command line arguments.
118         //pls.MergeOpts(options, "x20c options", NULL);
119         pls.parseopts( args, PL_PARSE_FULL | PL_PARSE_NOPROGRAM );
120 
121         // Initialize PLplot.
122         pls.init();
123 
124         // view image border pixels
125         if ( dbg )
126         {
127             pls.env( 1., XDIM, 1., YDIM, 1, 1 ); // no plot box
128 
129             // build a one pixel square border, for diagnostics
130             for ( i = 0; i < XDIM; i++ )
131                 z[i][YDIM - 1] = 1.; // right
132             for ( i = 0; i < XDIM; i++ )
133                 z[i][0] = 1.;        // left
134 
135             for ( i = 0; i < YDIM; i++ )
136                 z[0][i] = 1.;        // top
137             for ( i = 0; i < YDIM; i++ )
138                 z[XDIM - 1][i] = 1.; // botton
139 
140             pls.lab( "...around a blue square.", " ", "A red border should appear..." );
141 
142             pls.image( z, 1., XDIM, 1., YDIM, 0., 0.,
143                 1., XDIM, 1., YDIM );
144         }
145 
146         // sombrero-like demo
147         if ( !nosombrero )
148         {
149             r = new double[XDIM][YDIM];
150             pls.col0( 2 ); // draw a yellow plot box, useful for diagnostics! :(
151             pls.env( 0., 2. * Math.PI, 0, 3. * Math.PI, 1, -1 );
152 
153             for ( i = 0; i < XDIM; i++ )
154                 x[i] = i * 2. * Math.PI / ( XDIM - 1 );
155             for ( i = 0; i < YDIM; i++ )
156                 y[i] = i * 3. * Math.PI / ( YDIM - 1 );
157 
158             for ( i = 0; i < XDIM; i++ )
159                 for ( j = 0; j < YDIM; j++ )
160                 {
161                     r[i][j] = Math.sqrt( x[i] * x[i] + y[j] * y[j] ) + 1e-3;
162                     z[i][j] = Math.sin( r[i][j] ) / ( r[i][j] );
163                 }
164 
165             pls.lab( "No, an amplitude clipped \"sombrero\"", "", "Saturn?" );
166             pls.ptex( 2., 2., 3., 4., 0., "Transparent image" );
167             pls.image( z, 0., 2. * Math.PI, 0., 3. * Math.PI, 0.05, 1.,
168                 0., 2. * Math.PI, 0., 3. * Math.PI );
169 
170             // save the plot
171             if ( f_name != null )
172                 save_plot( f_name );
173         }
174 
175 
176         // read Chloe image
177         if ( ( img_f = read_img( "Chloe.pgm", n ) ) == null )
178         {
179             if ( ( img_f = read_img( "../Chloe.pgm", n ) ) == null )
180             {
181                 System.out.println( "File error - aborting" );
182                 pls.end();
183                 System.exit( 1 );
184             }
185         }
186         num_col = n[0];
187         width   = img_f.length;
188         height  = img_f[0].length;
189 
190         // set gray colormap
191         gray_cmap( num_col );
192 
193         // display Chloe
194         pls.env( 1., width, 1., height, 1, -1 );
195 
196         if ( !nointeractive )
197             pls.lab( "Set and drag Button 1 to (re)set selection, Button 2 to finish.", " ", "Chloe..." );
198         else
199             pls.lab( "", " ", "Chloe..." );
200 
201         pls.image( img_f, 1., width, 1., height, 0., 0.,
202             1., width, 1., height );
203 
204         // selection/expansion demo
205         if ( !nointeractive )
206         {
207             xi[0] = 25.; xe[0] = 130.;
208             yi[0] = 235.; ye[0] = 125.;
209 
210             if ( get_clip( xi, xe, yi, ye ) )   // get selection rectangle
211             {
212                 pls.end();
213                 System.exit( 0 );
214             }
215 
216             //
217             // I'm unable to continue, clearing the plot and advancing to the next
218             // one, without hiting the enter key, or pressing the button... help!
219             //
220             // Forcing the xwin driver to leave locate mode and destroying the
221             // xhairs (in GetCursorCmd()) solves some problems, but I still have
222             // to press the enter key or press Button-2 to go to next plot, even
223             // if a pladv() is not present!  Using plbop() solves the problem, but
224             // it shouldn't be needed!
225             //
226 
227             // pls.bop();
228 
229             //
230             // spause(false), adv(0), spause(true), also works,
231             // but the above question remains.
232             // With this approach, the previous pause state is lost,
233             // as there is no API call to get its current state.
234             //
235 
236             pls.spause( false );
237             pls.adv( 0 );
238 
239             // display selection only
240             pls.image( img_f, 1., width, 1., height, 0., 0., xi[0], xe[0], ye[0], yi[0] );
241 
242             pls.spause( true );
243 
244             // zoom in selection
245             pls.env( xi[0], xe[0], ye[0], yi[0], 1, -1 );
246             pls.image( img_f, 1., width, 1., height, 0., 0., xi[0], xe[0], ye[0], yi[0] );
247         }
248 
249         // Base the dynamic range on the image contents.
250         f2mnmx( img_f, width, height, maxmin );
251         img_max = maxmin[0];
252         img_min = maxmin[1];
253 
254         // For java we use 2-d arrays to replace the pltr function
255         // even for the NULL case.
256         xg = new double[width + 1][height + 1];
257         yg = new double[width + 1][height + 1];
258 
259         // In order to mimic the NULL case, the following must be true.
260         // xg[i] = i*deltax; yg[j] = j*deltay, where
261         deltax = (double) width / (double) ( width - 1 );
262         deltay = (double) height / (double) ( height - 1 );
263         for ( i = 0; i <= width; i++ )
264         {
265             for ( j = 0; j <= height; j++ )
266             {
267                 xg[i][j] = i * deltax;
268                 yg[i][j] = j * deltay;
269             }
270         }
271         // Draw a saturated version of the original image.  Only use
272         // the middle 50% of the image's full dynamic range.
273         pls.col0( 2 );
274         pls.env( 0, width, 0, height, 1, -1 );
275         pls.lab( "", "", "Reduced dynamic range image example" );
276         pls.imagefr( img_f, 0., width, 0., height, 0., 0.,
277             img_min + img_max * 0.25,
278             img_max - img_max * 0.25,
279             xg, yg );
280 
281         // Draw a distorted version of the original image, showing its full dynamic range.
282         pls.env( 0, width, 0, height, 1, -1 );
283         pls.lab( "", "", "Distorted image example" );
284 
285         x0      = 0.5 * width;
286         y0      = 0.5 * height;
287         dy      = 0.5 * height;
288         stretch = 0.5;
289 
290         // In C / C++ the following would work, with plimagefr directly calling
291         // mypltr. For compatibilty with other language bindings the same effect
292         // can be achieved by generating the transformed grid first and then
293         // using pltr2.
294         // plimagefr(img_f, width, height, 0., width, 0., height, 0., 0., img_min, img_max, mypltr, (PLPointer) &stretch);
295 
296         for ( i = 0; i <= width; i++ )
297         {
298             for ( j = 0; j <= height; j++ )
299             {
300                 xg[i][j] = x0 + ( x0 - i ) * ( 1.0 - stretch *
301                                                Math.cos( ( j - y0 ) / dy * Math.PI * 0.5 ) );
302                 yg[i][j] = j;
303             }
304         }
305 
306         pls.imagefr( img_f, 0., width, 0., height, 0., 0., img_min, img_max, xg, yg );
307         pls.end();
308     }
309 
310     // read image from file in binary ppm format
311     double [][] read_img( String fname, int [] num_col )
312     {
313         BufferedReader  in;
314         DataInputStream in2;
315         double[][] img;
316         String          line;
317         StringTokenizer st;
318         int             i, j, w, h;
319 
320         // naive grayscale binary ppm reading. If you know how to, improve it
321         try {
322             in  = new BufferedReader( new FileReader( fname ) );
323             in2 = new DataInputStream( new DataInputStream( new BufferedInputStream( new FileInputStream( fname ) ) ) );
324         }
325         catch ( FileNotFoundException e ) {
326             System.out.println( "File " + fname + " not found" );
327             return null;
328         }
329 
330         try {
331             line = in.readLine();
332 
333             if ( line.compareTo( "P5\n" ) == 0 )   // I only understand this!
334             {
335                 System.out.println( line );
336                 System.out.println( "unknown file format " + fname );
337                 return null;
338             }
339             in2.skip( line.getBytes().length + 1 );
340 
341             do
342             {
343                 line = in.readLine();
344                 in2.skip( line.getBytes().length + 1 );
345             } while ( line.charAt( 0 ) == '#' );
346 
347             st = new StringTokenizer( line );
348             w  = Integer.parseInt( st.nextToken() );
349             h  = Integer.parseInt( st.nextToken() );
350 
351             line = in.readLine();
352             in2.skip( line.getBytes().length + 1 );
353             st         = new StringTokenizer( line );
354             num_col[0] = Integer.parseInt( st.nextToken() );
355 
356             img = new double[w][h];
357 
358             for ( j = 0; j < h; j++ )
359             {
360                 for ( i = 0; i < w; i++ )
361                 {
362                     img[i][h - j - 1] = in2.readUnsignedByte();
363                 }
364             }
365         }
366         catch ( IOException e ) {
367             System.out.println( "Error reading " + fname );
368             return null;
369         }
370 
371         return img;
372     }
373 
374     // save plot
375     void save_plot( String fname )
376     {
377         PLStream pls2 = new PLStream(); // create a new one
378 
379         pls2.sdev( "psc" );             // new device type. Use a known existing driver
380         pls2.sfnam( fname );            // file name
381 
382         pls2.cpstrm( pls, false );      // copy old stream parameters to new stream
383         pls2.replot();                  // do the save
384     }
385 
386     //  get selection square interactively
387     boolean get_clip( double[] xi, double[] xe, double[] yi, double[] ye )
388     {
389         PLGraphicsIn gin   = new PLGraphicsIn();
390         double       xxi   = xi[0], yyi = yi[0], xxe = xe[0], yye = ye[0], t;
391         boolean      start = false;
392         boolean[] st = new boolean[1];
393 
394         pls.xormod( true, st ); // enter xor mode to draw a selection rectangle
395 
396         if ( st[0] )            // driver has xormod capability, continue
397         {
398             double sx[] = new double[5];
399             double sy[] = new double[5];
400             while ( true )
401             {
402                 pls.xormod( false, st );
403                 pls.getCursor( gin );
404                 pls.xormod( true, st );
405 
406                 if ( gin.getButton() == 1 )
407                 {
408                     xxi = gin.getWX(); yyi = gin.getWY();
409                     if ( start )
410                         pls.line( sx, sy ); // clear previous rectangle
411 
412                     start = false;
413 
414                     sx[0] = xxi; sy[0] = yyi;
415                     sx[4] = xxi; sy[4] = yyi;
416                 }
417 
418                 if ( ( gin.getState() & 0x100 ) != 0 )
419                 {
420                     xxe = gin.getWX(); yye = gin.getWY();
421                     if ( start )
422                         pls.line( sx, sy ); // clear previous rectangle
423 
424                     start = true;
425 
426                     sx[2] = xxe; sy[2] = yye;
427                     sx[1] = xxe; sy[1] = yyi;
428                     sx[3] = xxi; sy[3] = yye;
429                     pls.line( sx, sy ); // draw new rectangle
430                 }
431 
432                 if ( gin.getButton() == 3 || gin.getKeysym() == 0x0D || gin.getKeysym() == 'Q' )
433                 {
434                     if ( start )
435                         pls.line( sx, sy ); // clear previous rectangle
436                     break;
437                 }
438             }
439             pls.xormod( false, st ); // leave xor mod
440             if ( xxe < xxi )
441             {
442                 t = xxi; xxi = xxe; xxe = t;
443             }
444 
445             if ( yyi < yye )
446             {
447                 t = yyi; yyi = yye; yye = t;
448             }
449 
450             xe[0] = xxe; xi[0] = xxi;
451             ye[0] = yye; yi[0] = yyi;
452 
453             return ( gin.getKeysym() == 'Q' );
454         }
455 
456         return false;
457     }
458 
459     // set gray colormap
460     void gray_cmap( int num_col )
461     {
462         double r[]   = new double[2];
463         double g[]   = new double[2];
464         double b[]   = new double[2];
465         double pos[] = new double[2];
466 
467         r[0] = g[0] = b[0] = 0.0;
468         r[1] = g[1] = b[1] = 1.0;
469 
470         pos[0] = 0.0;
471         pos[1] = 1.0;
472 
473         pls.scmap1n( num_col );
474         pls.scmap1l( true, pos, r, g, b );
475     }
476 
477     // Calculate the minimum and maximum of a 2-d array
478     void f2mnmx( double [][] f, int nx, int ny, double[] fmaxmin )
479     {
480         int i, j;
481 
482         fmaxmin[0] = f[0][0];
483         fmaxmin[1] = fmaxmin[0];
484 
485         for ( i = 0; i < nx; i++ )
486         {
487             for ( j = 0; j < ny; j++ )
488             {
489                 fmaxmin[0] = Math.max( fmaxmin[0], f[i][j] );
490                 fmaxmin[1] = Math.min( fmaxmin[1], f[i][j] );
491             }
492         }
493     }
494 
495     public static void main( String[] args )
496     {
497         new x20( args );
498     }
499 }
500 
501 
502 //--------------------------------------------------------------------------
503 //                              End of x20.cc
504 //--------------------------------------------------------------------------
505