Statistics
| Revision:

root / trunk / extensions / extRemoteSensing / src / org / gvsig / remotesensing / mosaic / process / MosaicProcess.java @ 22800

History | View | Annotate | Download (18 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2006 Instituto de Desarrollo Regional and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *  Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Iba?ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *      +34 963862235
28
 *   gvsig@gva.es
29
 *      www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   Instituto de Desarrollo Regional (Universidad de Castilla La-Mancha)
34
 *   Campus Universitario s/n
35
 *   02071 Alabacete
36
 *   Spain
37
 *
38
 *   +34 967 599 200
39
 */
40

    
41
package org.gvsig.remotesensing.mosaic.process;
42

    
43
import java.awt.geom.AffineTransform;
44
import java.io.IOException;
45

    
46
import org.gvsig.fmap.raster.layers.FLyrRasterSE;
47
import org.gvsig.raster.RasterProcess;
48
import org.gvsig.raster.buffer.BufferFactory;
49
import org.gvsig.raster.buffer.RasterBuffer;
50
import org.gvsig.raster.buffer.RasterBufferInvalidException;
51
import org.gvsig.raster.buffer.WriterBufferServer;
52
import org.gvsig.raster.dataset.GeoRasterWriter;
53
import org.gvsig.raster.dataset.IBuffer;
54
import org.gvsig.raster.dataset.IRasterDataSource;
55
import org.gvsig.raster.dataset.InvalidSetViewException;
56
import org.gvsig.raster.dataset.NotSupportedExtensionException;
57
import org.gvsig.raster.dataset.io.RasterDriverException;
58
import org.gvsig.raster.grid.Grid;
59
import org.gvsig.raster.grid.GridExtent;
60
import org.gvsig.raster.grid.OutOfGridException;
61
import org.gvsig.raster.util.RasterToolsUtil;
62

    
63
import com.iver.andami.PluginServices;
64
import com.iver.cit.gvsig.exceptions.layers.LoadLayerException;
65

    
66
/** 
67
* Clase que implementa el proceso de construccion de un mosaico mediante los m?todos b?sicos.
68
* 
69
* @params
70
* <LI>FLyrRasterSE[] "inputRasterLayers": Capas raster de entrada</LI>
71
* <LI>int "methodCode": M?todo de construcci?n (0:Valor m?ximo, 1:Valor m?nimo, 2: Valor Medio,
72
* 3: Valor del pixel de la capa superior, 4:Valor del pixel de la capa inferior)</LI>
73
* <LI>String "outputPath": Ruta completa al fichero de salida del proceso</LI>
74
* 
75
* @result
76
* <LI>outputRassterLayers[]: Capas raster resultantes</LI>
77
*
78
* 
79
* @author aMu?oz (alejandro.mu?oz@uclm.es)
80
* @version 30/4/2008
81
* */
82

    
83
public class MosaicProcess extends RasterProcess {
84
        
85
        public static final int MAX                 = 0;
86
        public static final int MIN                 = 1;
87
        public static final int AVERAGE         = 2;
88
        public static final int FRONT                 = 3;
89
        public static final int BACK                 = 4;
90

    
91
        // Layers que intervienen en el proceso
92
        private FLyrRasterSE inputRasterLayers[] = null;
93
        
94
        //Layer de salida
95
        private FLyrRasterSE outputRasterLayer = null;
96

    
97
        // Extend completo del mosaico
98
        private GridExtent fullExtend= null;
99
        
100
        // Grid resultante
101
        Grid mosaicGrid = null;
102
        
103
        // Buffers con las imagenes
104
        RasterBuffer buffers[]= null;
105
        
106
        // Codigo operacion mayor, menor,media valor de la situada encima.
107
        int codOp= 0; 
108
        
109
        // indicador de proceso
110
        int percent=0, proceso=0;
111
         
112
        // writer para escritura en fichero 
113
        private WriterBufferServer writerBufferServer =null;
114
        
115
        //  Numero de bandas 3 o 1 dependiendo de si es RGB o Nivel de gris
116
        int resultbandCount=0;
117
         
118
        // Fichero de salida
119
        private String fileName=null; 
120
        
121
        
122
        
123
        /** Inicializaci?n de los par?metros
124
         *  layers -  FLayers con los layers seleccionados para el mosaico.
125
         * 
126
         *         En la inicializacion se calcula el grid resultante.
127
         * */
128
        public void init() {
129
                
130
                inputRasterLayers= (FLyrRasterSE[])getParam("inputRasterLayers");
131
                codOp= getIntParam("methodCode");
132
                resultbandCount= getIntParam("numbands");
133
                fileName = getStringParam("outputPath");
134
                
135
//                 Calculo del extend resultante
136
                fullExtend= calculateExtend(inputRasterLayers);
137
                
138
                try {
139
                                mosaicGrid= new Grid(fullExtend,fullExtend,IBuffer.TYPE_BYTE,new int[] { 0, 1, 2 });
140
                                resultbandCount = mosaicGrid.getBandCount();
141
                } catch (RasterBufferInvalidException e) {
142
                        RasterToolsUtil.messageBoxError("buffer_incorrecto", this, e);
143
                }
144
        }
145

    
146
        
147
        /**
148
         *  Proceso
149
         * */
150
        public void process() throws InterruptedException {
151
                
152
                // Parte de carga de los datos
153
                buffers= new RasterBuffer[inputRasterLayers.length];
154
                IRasterDataSource dsetCopy = null; 
155
                try {
156
                
157
                        double minX= fullExtend.getMin().getX();
158
                        double minY= fullExtend.getMin().getY();
159
                        double maxX=  fullExtend.getMax().getX();
160
                        double maxY=  fullExtend.getMax().getY();
161
                        // Se cargan todos los raster en los grid correspondientes
162
                        percent=1;
163
                        for(int i=0; i< inputRasterLayers.length;i++)
164
                        {        
165
                                dsetCopy = ((FLyrRasterSE)inputRasterLayers[i]).getDataSource().newDataset();
166
                                BufferFactory bufferFactory = new BufferFactory(dsetCopy);
167
                                bufferFactory.setAdjustToExtent(false);
168
                                if (!RasterBuffer.loadInMemory(dsetCopy))
169
                                        bufferFactory.setReadOnly(true);
170
                                // Si pongo solo las renderizadas en algunos casos da problemas
171
                                bufferFactory.setDrawableBands(inputRasterLayers[i].getRenderBands());
172
                                bufferFactory.setAreaOfInterest(minX,minY,maxX,maxY,fullExtend.getNX(),fullExtend.getNY());
173
                                buffers[i]= (RasterBuffer) bufferFactory.getRasterBuf();
174
                                percent=(int)((i+1)*100/inputRasterLayers.length);
175

    
176
                        
177
                        }
178
                }catch (RasterDriverException e) {
179
                        RasterToolsUtil.messageBoxError(PluginServices.getText(this, "error_writer"), this, e);        
180
                } catch (InvalidSetViewException e) {
181
                        RasterToolsUtil.messageBoxError(PluginServices.getText(this, "error_extension"), this, e);        
182
                } catch (InterruptedException e) {
183
                        Thread.currentThread().interrupt();
184
                }
185
                
186
                proceso=1;
187
            
188
//                 Construccion del mosaico: Operaci?n M?ximo
189
                if(codOp==0){
190
                        int progress = 0;
191
                        for(int band=0; band<resultbandCount; band++){
192
                                mosaicGrid.setBandToOperate(band);
193
                                for(int col=0; col<mosaicGrid.getLayerNY(); col++){
194
                                        progress++;
195
                                        for(int row=0; row<mosaicGrid.getLayerNX();row++){
196
                                                setValueMax(row,col,band);
197
                                        }
198
                                        percent=(int)( progress*100/(mosaicGrid.getLayerNY()*resultbandCount));
199
                                }
200
                        }
201
                }
202
                
203
//                Construccion del mosaico: Operaci?n M?nimo
204
                if(codOp==1){
205
                        int progress = 0;
206
                        for(int band=0; band<resultbandCount; band++){
207
                                mosaicGrid.setBandToOperate(band);
208
                                for(int col=0; col<mosaicGrid.getLayerNY(); col++){
209
                                        progress++;
210
                                        for(int row=0; row<mosaicGrid.getLayerNX();row++){
211
                                                setValueMin(row,col,band);
212
                                        }
213
                                        percent=(int)( progress*100/(mosaicGrid.getLayerNY()*resultbandCount));
214
                                }
215
                        }
216
                }
217
                
218
//                 Construccion del mosaico: Operaci?n Media
219
                if(codOp==2){
220
                        int progress = 0;
221
                        for(int band=0; band<resultbandCount; band++){
222
                                mosaicGrid.setBandToOperate(band);
223
                                for(int col=0; col<mosaicGrid.getLayerNY(); col++){
224
                                        progress++;
225
                                        for(int row=0; row<mosaicGrid.getLayerNX();row++){
226
                                                setValueMean(row,col,band);
227
                                        }
228
                                        percent=(int)( progress*100/(mosaicGrid.getLayerNY()*resultbandCount));
229
                                }
230
                        }
231
                }
232
                
233
//                Construccion del mosaico: Operacion valor de capa de delantera
234
                if(codOp==3){
235
                        int progress = 0;
236
                        for(int band=0; band<resultbandCount; band++){
237
                                mosaicGrid.setBandToOperate(band);
238
                                for(int col=0; col<mosaicGrid.getLayerNY(); col++){
239
                                        progress++;
240
                                        for(int row=0; row<mosaicGrid.getLayerNX();row++){
241
                                                setValueFront(row,col,band);
242
                                        }
243
                                        percent=(int)( progress*100/(mosaicGrid.getLayerNY()*resultbandCount));
244
                                }
245
                        }
246
                }
247
                
248
                
249
//                Construccion del mosaico: Operaci?n Valor de capa de trasera
250
                if(codOp==4){
251
                        
252
                        // Cambio de orden del los elementos del buffer las capas inferiores pasan al principio del array
253
                        RasterBuffer buffersCopy[]= new RasterBuffer[buffers.length];
254
                        for(int i=0; i<buffers.length;i++)
255
                                buffersCopy[i]=buffers[i];
256
                        int k=buffers.length-1;
257
                        for(int i=0; i<buffers.length;i++){
258
                                buffers[i]=buffersCopy[k];
259
                                k--;
260
                        }
261
                        int progress = 0;
262
                        for(int band=0; band<resultbandCount; band++){
263
                                mosaicGrid.setBandToOperate(band);
264
                                for(int col=0; col<mosaicGrid.getLayerNY(); col++){
265
                                        progress++;
266
                                        for(int row=0; row<mosaicGrid.getLayerNX();row++){
267
                                                setValueBack(row,col,band);
268
                                        }
269
                                        percent=(int)( progress*100/(mosaicGrid.getLayerNY()*resultbandCount));
270
                                }
271
                        }
272
                }
273
                
274
                // Se liberan los buffers
275
                for(int i=0; i<inputRasterLayers.length;i++)
276
                        buffers[i].free();
277
                
278
                // Escritura en fichero
279
                proceso=2;
280
                createLayer();
281
                if (externalActions != null)
282
                        externalActions.end(outputRasterLayer);
283
        }
284

    
285
        
286
        /**
287
         *  M?todo que establece para la coordenada x,y el valor m?ximo 
288
         *  de todos los valores para ese p?xel en cualquiera de las imagenes.
289
         *  Si el valor en cualquiera de las imagenes es noData no es tenido en cuenta 
290
         *  @param cordenada x 
291
         *  @param coordenada y  
292
         * */
293
        public void setValueMax(int x, int y, int band){
294
                byte result=-128;
295
                for(int buf=0;buf<buffers.length;buf++){
296
                        byte data = (byte)(buffers[buf].getElemByte(y,x,band)&0xff);
297
//                                 TO DO: TENER EN CUENTA NODATA REAL DEL BUFER
298
                        if(data==(byte)mosaicGrid.getNoDataValue())
299
                                data=-128;
300
                        result=(byte) Math.max((byte)result,(byte)data);                
301
                }
302
                try {
303
                                mosaicGrid.setCellValue(x,y,(byte)result);
304
                } catch (OutOfGridException e) {
305
                                e.printStackTrace();
306
                }
307
        }
308
        
309
        /**
310
         *  M?todo que establece para la coordenada x,y el valor m?ximo 
311
         *  de todos los valores para ese p?xel en cualquiera de las imagenes.
312
         *  Si el valor en cualquiera de las imagenes es noData no es tenido en cuenta 
313
         *  @param cordenada x 
314
         *  @param coordenada y  
315
         * */
316
        public void setValueMin(int x, int y,int band){
317
                byte result=127;
318
                        for(int buf=0;buf<buffers.length;buf++){
319
                                byte data = (byte)(buffers[buf].getElemByte(y,x,band)&0xff);
320
                                // TO DO: TENER EN CUENTA NO DATA
321
                                if(data==(byte)mosaicGrid.getNoDataValue())
322
                                        data=127;
323
                                result=(byte) Math.min((byte)result,(byte)data);                
324
                        }
325
                        try {
326
                                mosaicGrid.setCellValue(x,y,(byte)result);
327
                        } catch (OutOfGridException e) {
328
                                // TODO Auto-generated catch block
329
                                e.printStackTrace();
330
                        }
331
        }
332
        
333
        
334
        /**
335
         *  M?todo que establece para la coordenada x,y el valor medio  
336
         *  de todos los valores para ese p?xel en cualquiera de las imagenes.
337
         *  Si el valor en cualquiera de las imagenes es noData no es tenido en cuenta 
338
         *  @param cordenada x 
339
         *  @param coordenada y  
340
         * */
341
        public void setValueMean(int x, int y, int band){
342
                int result=0;
343
                int buffTotales= buffers.length;
344
                for(int buf=0;buf<buffers.length;buf++){
345
                        int data = (int)((byte)(buffers[buf].getElemByte(y,x,band)));
346
                        //TODO: TENER EN CUENTA NODATA REAL DEL BUFER
347
                        if(data==(byte)mosaicGrid.getNoDataValue()){
348
                                buffTotales--;
349
                                data =0;
350
                        }
351
                        result+=data;                
352
                }
353
                if(buffTotales==0)
354
                        buffTotales=1;
355
                result=(byte)((result/buffTotales));
356
                try {
357
                                mosaicGrid.setCellValue(x,y,(byte)(result));
358
                } catch (OutOfGridException e) {
359
                                e.printStackTrace();
360
                }
361
        }
362
        
363
        
364
        /**
365
         *  M?todo que establece para la coordenada x,y el valor de la capa superior 
366
         *  en caso de solape. Se parte de un array de buffer ordenados, de tal manera que
367
         *  el primer elemento corresponde a la capa situada mas al frente. El ?ltimo por 
368
         *  contra es el situado al fondo.
369
         
370
         *  @param cordenada x 
371
         *  @param coordenada y  
372
         * */
373
        public void setValueFront(int x, int y, int band){
374
                byte result=0;
375
                for(int buf=0;buf<buffers.length;buf++){
376
                        result = (byte)(buffers[buf].getElemByte(y,x,band));
377
                        // TO DO : Valor no data del buffer
378
                        if(result!=(byte)mosaicGrid.getNoDataValue())
379
                                        break;
380
                }
381
                
382
                try {
383
                                mosaicGrid.setCellValue(x,y,(byte)result);
384
                } catch (OutOfGridException e) {
385
                                e.printStackTrace();
386
                }
387
        }
388
        
389
        
390
        /**
391
         *  M?todo que establece para la coordenada x,y el valor de la capa inferior
392
         *  en caso de solape. Se parte de un array de buffer ordenados, de tal manera que
393
         *  el primer elemento corresponde a la capa situada mas al frente. El ?ltimo por 
394
         *  contra es el situado al fondo.
395
         
396
         *  @param cordenada x 
397
         *  @param coordenada y  
398
         * */
399
        public void setValueBack(int x, int y, int band){
400
                byte result=0;
401
                for(int buf=0;buf<buffers.length;buf++){
402
                        result = (byte)(buffers[buf].getElemByte(y,x,band));
403
                        // TO DO : Valor no data del buffer
404
                        if(result!=(byte)mosaicGrid.getNoDataValue())
405
                                        break;
406
                }
407
                
408
                try {
409
                                mosaicGrid.setCellValue(x,y,(byte)result);
410
                } catch (OutOfGridException e) {
411
                                e.printStackTrace();
412
                }
413
        }
414
        
415
        
416
        /**
417
         * M?todo que calcula el extend resultante para la operaci?n de mosaico
418
         * 
419
         * @param layers que intervienen en la operacion.
420
         * @return GridExtend del mosaico
421
         * */
422
        
423
        private GridExtent calculateExtend (FLyrRasterSE layers[]){
424
                
425
                GridExtent result= null;
426
                IRasterDataSource dsetCopy = null; 
427
                double cellSize=0;
428
                double minX=0,maxX=0,minY=0,maxY=0;
429
                // Se obtiene el tama?o de celda mayor
430
                for(int i=0; i< layers.length;i++)
431
                {        
432
                        dsetCopy = ((FLyrRasterSE)layers[i]).getDataSource().newDataset();
433
                        BufferFactory bufferFactory = new BufferFactory(dsetCopy);
434
                        bufferFactory.setAdjustToExtent(false);
435
                        cellSize= Math.max(cellSize,bufferFactory.getDataSource().getCellSize());
436
                }
437
                
438
                minX = layers[0].getFullExtent().getMinX();
439
                minY = layers[0].getFullExtent().getMinY();
440
                maxX = layers[0].getFullExtent().getMaxX();
441
                maxY = layers[0].getFullExtent().getMaxY();
442
                
443
                for(int i=1; i<layers.length;i++){
444
                        
445
                        minX= Math.min(minX,layers[i].getFullExtent().getMinX());
446
                        minY= Math.min(minY,layers[i].getFullExtent().getMinY());
447
                        maxX= Math.max(maxX,layers[i].getFullExtent().getMaxX());
448
                        maxY= Math.max(maxY,layers[i].getFullExtent().getMaxY());
449
                }
450
                
451
                result = new GridExtent(minX,minY,maxX,maxY,cellSize);
452
                return result;
453
        }
454
        
455
        /**
456
         * Escritura del resultado en disco y carga en la vista 
457
         */
458
        public void createLayer(){
459
                try{
460
                        // Escritura de los datos a fichero temporal
461
                        int endIndex = fileName.lastIndexOf(".");
462
                        if (endIndex < 0)
463
                                 endIndex = fileName.length();
464
                        GeoRasterWriter grw = null;
465
                        writerBufferServer = new WriterBufferServer(mosaicGrid.getRasterBuf());
466
                        AffineTransform aTransform = new AffineTransform(fullExtend.getCellSize(),0.0,0.0,-fullExtend.getCellSize(),fullExtend.getMin().getX(),fullExtend.getMax().getY());
467
                        grw = GeoRasterWriter.getWriter(writerBufferServer, fileName, mosaicGrid.getBandCount(),aTransform, mosaicGrid.getRasterBuf().getWidth(), mosaicGrid.getRasterBuf().getHeight(), mosaicGrid.getRasterBuf().getDataType(), GeoRasterWriter.getWriter(fileName).getParams(), inputRasterLayers[0].getProjection());
468
                        grw.dataWrite();
469
                        grw.setWkt((String)((FLyrRasterSE)inputRasterLayers[0]).getWktProjection());
470
                        grw.writeClose();
471
                        mosaicGrid.getRasterBuf().free();
472
                        outputRasterLayer = FLyrRasterSE.createLayer("outputLayer",
473
                                        fileName, null);
474
        
475
                } catch (NotSupportedExtensionException e) {
476
                        RasterToolsUtil.messageBoxError(PluginServices.getText(this, "error_writer_notsupportedextension"), this, e);
477
                } catch (IOException e) {
478
                        RasterToolsUtil.messageBoxError(PluginServices.getText(this, "error_writer"), this, e);
479
                } catch (InterruptedException e) {
480
                                Thread.currentThread().interrupt();
481
                } catch (RasterDriverException e) {
482
                        RasterToolsUtil.messageBoxError(PluginServices.getText(this, "raster_buffer_invalid_extension"), this, e);
483
                } catch (LoadLayerException e) {
484
                        RasterToolsUtil.messageBoxError("error_cargar_capa", this, e);
485
                }
486

    
487
        }
488
        
489
        public Object getResult() {
490
                return outputRasterLayer;
491
        }
492

    
493

    
494
        /**
495
         * @return descripcion
496
         * */
497
        public String getTitle() {
498
                return PluginServices.getText(this,"mosaic_process");
499
        }
500

    
501
        
502
        /**
503
         *  @return String con el log en cada parte del proceso
504
         * */
505
        public String getLog()
506
        {
507
                if(proceso==0)
508
                        return PluginServices.getText(this,"load_buffer_data");
509
                else if (proceso==1)
510
                        return PluginServices.getText(this,"generate_mosaic");
511
                else
512
                        return PluginServices.getText(this,"write_to_file");
513
        }
514
        
515
        /**
516
         * @return  indicador de progreso
517
         * */
518
        public int getPercent() {
519
                if(writerBufferServer==null)
520
                        return percent;
521
                else 
522
                        return writerBufferServer.getPercent();
523
        }
524

    
525

    
526
        /*
527
        // Identificaci?n de zonas de solapamiento
528
        public boolean getSolapes(FLyrRasterSE raster1, FLyrRasterSE raster2){
529
                
530
                Grid grid1=null, grid2=null, aux=null;;
531
                IRasterDataSource dsetCopy = null; 
532
                dsetCopy =raster1.getDataSource().newDataset();
533
                BufferFactory bufferFactory = new BufferFactory(dsetCopy);
534
                
535
                IRasterDataSource dsetCopy2 = null; 
536
                dsetCopy2 =raster2.getDataSource().newDataset();
537
                BufferFactory bufferFactory2 = new BufferFactory(dsetCopy2);
538
                
539
                
540
                if (!RasterBuffer.loadInMemory(dsetCopy))
541
                        bufferFactory.setReadOnly(true);        
542
                
543
                try {
544
                        grid1 = new Grid(bufferFactory,raster1.getRenderBands());
545
                        grid2= new Grid(bufferFactory2,raster2.getRenderBands());
546
                } catch (RasterBufferInvalidException e) {
547
                        e.printStackTrace();
548
                }        
549
                
550
                // En grid1 la imagen con la cordenada x menor.
551
                if(grid2.getGridExtent().getMin().getX()< grid1.getGridExtent().getMin().getX())
552
                        {
553
                                try {
554
                                        grid1 = new Grid(bufferFactory2,raster2.getRenderBands());
555
                                        grid2= new Grid(bufferFactory,raster1.getRenderBands());
556
                                } catch (RasterBufferInvalidException e) {
557
                                        e.printStackTrace();
558
                                }        
559
                                
560
                        }
561
                
562
                double xmin= grid1.getGridExtent().getMin().getX();
563
                double xmax= grid1.getGridExtent().getMax().getX();
564
                double ymin= grid1.getGridExtent().getMin().getY();
565
                double ymax= grid1.getGridExtent().getMax().getY();
566
                
567
                double xmin2= grid2.getGridExtent().getMin().getX();
568
                double ymin2= grid2.getGridExtent().getMin().getY();
569
                
570
                if(!(xmin2>xmin && xmin2<xmax)){
571
                        System.out.print("Las imagenes no se solapan en las X");
572
                        return false;
573
                }
574
        
575
                if(!(ymin2>ymin && ymin2<ymax)){
576
                        System.out.print("Las imagenes no se solapan en las Y");
577
                        return false;
578
                }
579
                
580
                // Detectado el solapamiento
581
                System.out.print("Rango x["+ xmin2 + ","+ Math.min(xmax,grid2.getGridExtent().getMax().getX())+"].");
582
                System.out.print("Rango y["+ ymin2 + ","+ Math.min(ymax,grid2.getGridExtent().getMax().getY())+"].");
583
                
584
                return true;
585
        }*/
586

    
587

    
588
}