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