Statistics
| Revision:

root / trunk / libraries / libCq_CMS_praster / src / org / cresques / io / EcwFile.java @ 8026

History | View | Annotate | Download (47.5 KB)

1
/*
2
 * Cresques Mapping Suite. Graphic Library for constructing mapping applications.
3
 *
4
 * Copyright (C) 2004-5.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program 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 General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
19
 *
20
 * For more information, contact:
21
 *
22
 * cresques@gmail.com
23
 */
24
package org.cresques.io;
25

    
26
import java.awt.Dimension;
27
import java.awt.Image;
28
import java.awt.Point;
29
import java.awt.image.BufferedImage;
30
import java.awt.image.PixelGrabber;
31

    
32
import org.cresques.cts.ICoordTrans;
33
import org.cresques.cts.IProjection;
34
import org.cresques.io.data.BandList;
35
import org.cresques.io.data.RasterBuf;
36
import org.cresques.io.exceptions.SupersamplingNotSupportedException;
37
import org.cresques.px.Extent;
38

    
39
import com.ermapper.ecw.JNCSException;
40
import com.ermapper.ecw.JNCSFile;
41
import com.ermapper.ecw.JNCSFileNotOpenException;
42
import com.ermapper.ecw.JNCSInvalidSetViewException;
43
import com.ermapper.ecw.JNCSProgressiveUpdate;
44
import com.ermapper.util.JNCSDatasetPoint;
45
import com.ermapper.util.JNCSWorldPoint;
46

    
47

    
48
/**
49
 * Soporte para los ficheros .ecw de ErMapper.
50
 * <br>
51
 * NOTA: El SDK que ermapper ha puesto a disposici?n del p?blico en java
52
 * es una versi?n 2.45, de 19/11/2001. Est? implementada usando JNI que
53
 * se apoya en tres librer?as din?micas (dll), y presenta deficiencias
54
 * muy graves a la hora de acceder a la informaci?n. Hasta el momento
55
 * hemos detectado 3 de ellas:<BR>
56
 *     1?.- No soporta ampliaciones superiores a 1:1. si se intenta acceder
57
 * a un ecw con un zoom mayor da una excepci?n del tipo
58
 * com.ermapper.ecw.JNCSInvalidSetViewException, que de no ser tenida encuenta
59
 * acaba tirando abajo la m?quina virtual de java.<BR>
60
 *     2?.- La longitud m?xima de l?nea que adminte el m?todo readLineRGBA es
61
 * de unos 2500 pixeles, lo que hace el uso para la impresi?n en formatos
62
 * superiorea a A4 a 300 ppp o m?s inviable.<BR>
63
 *     3?.- La actualizaci?n progresiva usando el interface JNCSProgressiveUpdate
64
 * con el JNCSFile hace que el equipo genere un error severo y se apague. Este
65
 * error imposibilita esta t?cnica de acceso a ECW.<BR>
66
 * <br>
67
 * Para saltarnos la limitaci?n del bug#1 pedimos la ventana correspondiente al zoom 1:1 para
68
 * el view que nos han puesto, y la resizeamos al tama?o que nos pide el usuario.<br>
69
 * Como consecuencia del bug#2, para tama?os de ventana muy grandes (los necesarios
70
 * para imprimir a m?s de A4 a 300DPI), hay que hacer varias llamadas al fichero con
71
 * varios marcos contiguos, y los devolvemos 'pegados' en una sola imagen (esto se
72
 * realiza de manera transparente para el usuario dentro de la llamada a updateImage.<br>
73
 *
74
 * @author "Luis W. Sevilla" <sevilla_lui@gva.es>
75
 */
76
public class EcwFile extends GeoRasterFile implements JNCSProgressiveUpdate {
77
    //Lleva la cuenta del n?mero de actualizaciones que se hace de una imagen que corresponde con el 
78
    //n?mero de bandas que tiene. Esto es necesario ya que si una imagen tiene el mustResize a
79
    //true solo debe llamar a la funci?n resizeImage al actualizar la ?ltima banda, sino al hacer
80
    //un zoom menor que 1:1 se veria mal
81
    private static int nUpdate = 0;
82
    private JNCSFile file = null;
83
    private boolean bErrorOnOpen = false;
84
    private String errorMessage = null;
85
    private boolean multifile = false;
86
    private Extent v = null;
87

    
88
    // Ultimo porcentaje de refresco. Se carga en el update y se
89
    // actualiza en el refreshUpdate
90
    private int lastRefreshPercent = 0;
91

    
92
    public EcwFile(IProjection proj, String fName) {
93
        super(proj, null);
94
        fName = DataSource.normalize(fName);
95
        super.setName(fName);
96
        extent = new Extent();
97

    
98
        try {
99
            //System.err.println("Abriendo "+fName);
100
            file = new JNCSFile(fName, false);
101
            load();
102
            //readGeoInfo(fName);
103
            bandCount = file.numBands;
104

    
105
            if ( bandCount > 2) {
106
                    setBand(RED_BAND,   0);
107
                    setBand(GREEN_BAND, 1);
108
                    setBand(BLUE_BAND,  2);
109
            } else
110
                    setBand(RED_BAND|GREEN_BAND|BLUE_BAND, 0);
111
        } catch (Exception e) {
112
            bErrorOnOpen = true;
113
            errorMessage = e.getMessage();
114
            System.err.println(errorMessage);
115
            e.printStackTrace();
116
        }
117
    }
118

    
119
    /**
120
     * Carga un ECW.
121
     *
122
     * @param fname
123
     */
124
    public GeoFile load() {
125
        double minX;
126
        double minY;
127
        double maxX;
128
        double maxY;
129

    
130
        if(file.cellIncrementY > 0)
131
                file.cellIncrementY = -file.cellIncrementY;
132
        
133
        minX = file.originX;
134
        maxY = file.originY;
135
        maxX = file.originX +
136
               ((double) (file.width - 1) * file.cellIncrementX);
137
        minY = file.originY +
138
               ((double) (file.height - 1) * file.cellIncrementY);
139
        
140
        extent = new Extent(minX, minY, maxX, maxY);
141
        requestExtent = extent;
142
        return this;
143
    }
144

    
145
    public void close() {
146
            if(file != null){
147
                    file.close(true);
148
                    file = null;
149
            }
150
    }
151

    
152
    /**
153
     * Devuelve el ancho de la imagen
154
     */
155
    public int getWidth() {
156
        return file.width;
157
    }
158

    
159
    /**
160
     * Devuelve el alto de la imagen
161
     */
162
    public int getHeight() {
163
        return file.height;
164
    }
165

    
166
    /**
167
     *
168
     */
169
    public void setMultifile(boolean mult) {
170
        this.multifile = mult;
171
    }
172

    
173
    public void setView(Extent e) {
174
            //Aplicamos la transformaci?n a la vista en caso de que haya un fichero .rmf 
175
            /*                     
176
            if(file.cellIncrementY > 0)
177
                file.cellIncrementY = -file.cellIncrementY;
178
            if(minX < file.originX)
179
                    minX = file.originX;
180
            if(maxY > file.originY)
181
                    maxY = file.originY;
182
            if(maxX > (file.originX + ((double) (file.width - 1) * file.cellIncrementX)))
183
                    maxX = file.originX + ((double) (file.width - 1) * file.cellIncrementX);
184
            if(minY < file.originY + ((double) (file.height - 1) * file.cellIncrementY))
185
                    minY = file.originY + ((double) (file.height - 1) * file.cellIncrementY);
186
            
187
                Extent transformView = new Extent(        minX, minY, maxX, maxY );*/
188
        v = new Extent(e);
189
    }
190

    
191
    public Extent getView() {
192
        return v;
193
    }
194
    
195
    private void setFileView(int numBands, int [] bandList, ChunkFrame f)
196
            throws JNCSFileNotOpenException, JNCSInvalidSetViewException {
197
        file.setView(file.numBands, bandList, f.v.minX(), f.v.maxY(), f.v.maxX(), f.v.minY(), f.width, f.height);
198
    }
199

    
200
    /**
201
     * Obtiene un trozo de imagen (determinado por la vista y los par?metros.
202
     *
203
     * @param width
204
     * @param height
205
     */
206
    public synchronized Image updateImage(int width, int height, ICoordTrans rp) {
207
        // TODO reproyectar para devolver el trozo de imagen pedida sobre ...
208
        // la proyecci?n de destino.
209
        int line = 0;
210
        boolean mustResize = false;
211
        Dimension fullSize = null;
212
        Image ecwImage = null;
213

    
214
        if (file == null) {
215
            return ecwImage;
216
        }
217

    
218
        try {
219
            int[] bandlist;
220
            int[] bandListTriband;
221
            int[] pRGBArray = null;
222

    
223
            if(mustVerifySize()){
224
            // Work out the correct aspect for the setView call.
225
                    double dFileAspect = (double) v.width() / (double) v.height();
226
                    double dWindowAspect = (double) width / (double) height;
227
        
228
                    if (dFileAspect > dWindowAspect) {
229
                        height = (int) ((double) width / dFileAspect);
230
                    } else {
231
                        width = (int) ((double) height * dFileAspect);
232
                    }
233
            }
234
            fullSize = new Dimension(width, height);
235

    
236
            //System.out.println("fullSize = ("+width+","+height+")");
237
            // Peta en los peque?os ... arreglar antes de meter del todo
238
            ChunkFrame[] frames = ChunkFrame.computeFrames(file, v, fullSize, extent);
239

    
240
            if (frames.length == 1) {
241
                width = frames[0].width;
242
                height = frames[0].height;
243

    
244
                if (width <= 0) {
245
                    width = 1;
246
                }
247

    
248
                if (height <= 0) {
249
                    height = 1;
250
                }
251
            }
252

    
253
            /*                        JNCSDatasetPoint ptMin = file.convertWorldToDataset(v.minX(), v.minY());
254
                                    JNCSDatasetPoint ptMax = file.convertWorldToDataset(v.maxX(), v.maxY());
255
                                    System.out.println("Dataset coords Width = "+(ptMax.x-ptMin.x)+", px width ="+width);
256
                                    // BEGIN Cambiando para soportar e < 1:1
257
                                    // TODO Mejorarlo para que los PAN con un zoom muy grande sean correctos
258
                                    if ((ptMax.x-ptMin.x)<width) {
259
                                            width = ptMax.x-ptMin.x;
260
                                            height = ptMin.y-ptMax.y;
261
                                            System.out.println("Size=("+width+","+height+")");
262
                                            mustResize = true;
263
                                    }*/
264

    
265
            // Create an image of the ecw file.
266
            if (doTransparency) {
267
                ecwImage = new BufferedImage(width, height,
268
                                             BufferedImage.TYPE_INT_ARGB);
269
            } else {
270
                ecwImage = new BufferedImage(width, height,
271
                                             BufferedImage.TYPE_INT_RGB);
272
            }
273

    
274
            pRGBArray = new int[width];
275

    
276
            // Setup the view parameters for the ecw file.
277
            bandlist = new int[bandCount];
278
            bandListTriband = new int[bandCount];
279

    
280
            if (bandCount > 2) {
281
                bandlist[0] = getBand(RED_BAND);
282
                bandlist[1] = getBand(GREEN_BAND);
283
                bandlist[2] = getBand(BLUE_BAND);
284

    
285
                if (bandCount > 3) {
286
                    for (int i = 3; i < bandCount; i++) {
287
                        bandlist[i] = 0;
288
                    }
289
                }
290
            } else {
291
                for (int i = 0; i < bandCount; i++) {
292
                    bandlist[i] = i;
293
                }
294
            }
295

    
296
            if (bandCount == 3) {
297
                bandListTriband[0] = 0;
298
                bandListTriband[1] = 1;
299
                bandListTriband[2] = 2;
300
            }
301

    
302
            for (int nChunk = 0; nChunk < frames.length; nChunk++) {
303
                ChunkFrame f = frames[nChunk];
304

    
305
                // Set the view                        
306
                if (bandCount != 3) {
307
                    setFileView(file.numBands, bandlist, f);
308
                } else {
309
                    setFileView(file.numBands, bandListTriband, f);
310
                }
311

    
312
                /* 
313
                 * Esta peli es porque el Ecw no intercambia las bandas con lo que me toca hacerlo
314
                 * a mano. Primero detectamos si se ha alterado el orden de las mismas. Si es as?
315
                 * calculamos mascaras y desplazamientos y hacemos una copia en pRGBArrayCopy
316
                 * con las bandas alteradas de orden
317
                 */
318
                int[] pRGBArrayCopy = null;
319
                int[] mascara = new int[3];
320
                int[] shl = new int[3];
321
                int[] shr = new int[3];
322
                boolean order = true;
323

    
324
                if (bandCount == 3) {
325
                    for (int i = 0; i < bandCount; i++)
326
                        if (bandlist[i] != i) {
327
                            order = false;
328
                        }
329

    
330
                    if (!order) {
331
                        for (int i = 0; i < bandCount; i++) {
332
                            switch (bandlist[i]) {
333
                            case 0:
334
                                mascara[i] = 0x00ff0000;
335
                                break;
336
                            case 1:
337
                                mascara[i] = 0x0000ff00;
338
                                break;
339
                            case 2:
340
                                mascara[i] = 0x000000ff;
341
                                break;
342
                            }
343
                            if ((i == 1) && (bandlist[i] == 0)) 
344
                                shr[i] = 8;
345
                            if ((i == 2) && (bandlist[i] == 0)) 
346
                                shr[i] = 16;
347
                            if ((i == 0) && (bandlist[i] == 1)) 
348
                                shl[i] = 8;
349
                            if ((i == 2) && (bandlist[i] == 1))
350
                                shr[i] = 8;
351
                            if ((i == 0) && (bandlist[i] == 2)) 
352
                                shl[i] = 16;
353
                            if ((i == 1) && (bandlist[i] == 2))
354
                                shl[i] = 8;
355
                        }
356
                    }
357
                }
358

    
359
                // Read the scan lines
360
                for (line = 0; line < f.height; line++) {
361
                    file.readLineRGBA(pRGBArray);
362

    
363
                    if ((bandCount == 3) && !order) {
364
                        pRGBArrayCopy = new int[pRGBArray.length];
365

    
366
                        for (int i = 0; i < pRGBArray.length; i++) {
367
                            pRGBArrayCopy[i] = (pRGBArray[i] & 0xff000000) +
368
                                               (((pRGBArray[i] & mascara[2]) << shl[2]) >> shr[2]) +
369
                                               (((pRGBArray[i] & mascara[1]) << shl[1]) >> shr[1]) +
370
                                               (((pRGBArray[i] & mascara[0]) << shl[0]) >> shr[0]);
371
                        }
372

    
373
                        pRGBArray = pRGBArrayCopy;
374
                    }
375

    
376
                    // Prueba de sustituci?n de color transparente
377
                    if (doTransparency) {
378
                        if (line == 0) {
379
                            tFilter.debug = true;
380
                        }
381

    
382
                        tFilter.filterLine(pRGBArray);
383
                        tFilter.debug = false;
384
                    }
385

    
386
                    ((BufferedImage) ecwImage).setRGB(f.pos.x, f.pos.y + line,
387
                                                      f.width, 1, pRGBArray, 0,
388
                                                      f.width);
389
                }
390
            }
391

    
392
            if (frames[0].mustResize) {
393
                //System.out.println("resize "+fullSize);
394
                return resizeImage(fullSize, ecwImage);
395
            }
396

    
397
            /*
398
             * La excepci?n atrapada es la de 'zoom > 1:1 no valido'
399
            } catch (com.ermapper.ecw.JNCSInvalidSetViewException e) {
400
                    System.err.println(errorMessage);
401
                    e.printStackTrace(); */
402
        } catch (com.ermapper.ecw.JNCSException e) { //java.lang.ArrayIndexOutOfBoundsException:
403
            bErrorOnOpen = true;
404
            System.err.println("EcwFile JNCS Error en la l?nea " + line + "/" +
405
                               height);
406
            System.err.println(e.getMessage());
407
            e.printStackTrace();
408
        } catch (java.lang.ArrayIndexOutOfBoundsException e) { //:
409
            bErrorOnOpen = true;
410
            System.err.println("EcwFile ArrayIndex Error en la l?nea " + line +
411
                               "/" + height);
412
            System.err.println(e.getMessage());
413
            e.printStackTrace();
414
        } catch (Exception e) {
415
            bErrorOnOpen = true;
416
            errorMessage = e.getMessage();
417

    
418
            //                        g.drawString(errorMessage, 0, 50);
419
            System.err.println(errorMessage);
420
            e.printStackTrace();
421
        }
422

    
423
        lastRefreshPercent = file.getPercentComplete();
424
        System.out.println("Leido al " + lastRefreshPercent + " %.");
425

    
426
        return ecwImage;
427
    }
428

    
429
    /**
430
     * Redimensionado de imagen
431
     * La funci?n getScaledInstance nos devuelve un tipo image que no sirve por lo que
432
     * habr? que crear  buffImg como BufferedImage y copiar los datos devueltos por esta
433
     * funci?n a este que es el que ser? devuelto por la funci?n
434
     * @param sz
435
     * @param image        Image de entrada
436
     * @return        Imagen reescalada
437
     */
438
    private Image resizeImage(Dimension sz, Image image) {
439
        Image buffImg = null;
440
        Image img = image.getScaledInstance((int) sz.getWidth(),
441
                                            (int) sz.getHeight(),
442
                                            Image.SCALE_SMOOTH);
443

    
444
        //Todo este pollo es para copiar el tipo image devuelto a BufferedImage
445
        buffImg = new BufferedImage(img.getWidth(null), img.getHeight(null),
446
                                    BufferedImage.TYPE_INT_ARGB);
447

    
448
        int[] pixels = new int[img.getWidth(null) * img.getHeight(null)];
449
        PixelGrabber pg = new PixelGrabber(img, 0, 0, img.getWidth(null),
450
                                           img.getHeight(null), pixels, 0,
451
                                           img.getWidth(null));
452

    
453
        try {
454
            pg.grabPixels();
455
        } catch (InterruptedException e) {
456
            e.printStackTrace();
457
        }
458

    
459
        for (int j = 0; j < buffImg.getHeight(null); j++) {
460
            for (int i = 0; i < buffImg.getWidth(null); i++) {
461
                ((BufferedImage) buffImg).setRGB(i, j,
462
                                                 pixels[(j * buffImg.getWidth(null)) +
463
                                                 i]);
464
            }
465
        }
466

    
467
        return buffImg;
468
    }
469

    
470
    /**
471
     * Reproyecta el raster.
472
     */
473
    public void reProject(ICoordTrans rp) {
474
        // TODO metodo reProject pendiente de implementar
475
    }
476

    
477
    /**
478
     * Soporte para actualizaci?n de la imagen
479
     * @see com.ermapper.ecw.JNCSProgressiveUpdate#refreshUpdate(int, int, double, double, double, double)
480
     */
481
    public void refreshUpdate(int nWidth, int nHeight, double dWorldTLX,
482
                              double dWorldTLY, double dWorldBRX,
483
                              double dWorldBRY) {
484
        int completado = file.getPercentComplete();
485
        System.out.println("EcwFile: se actualiza 1: " + completado +
486
                           " % completado");
487

    
488
        if ((updatable != null) && (lastRefreshPercent < 100)) {
489
            if (((completado - lastRefreshPercent) > 25) ||
490
                    (completado == 100)) {
491
                lastRefreshPercent = file.getPercentComplete();
492
                updatable.repaint();
493
            }
494
        }
495
    }
496

    
497
    public void refreshUpdate(int nWidth, int nHeight, int dDatasetTLX,
498
                              int dDatasetTLY, int dDatasetBRX, int dDatasetBRY) {
499
        System.out.println("EcwFile: se actualiza 2");
500
    }
501

    
502
    /**
503
     *  Esta funci?n es porque el Ecw no intercambia las bandas con lo que me toca hacerlo
504
     * a mano. Primero detectamos si se ha alterado el orden de las mismas. Si es as?
505
     * calculamos mascaras y desplazamientos y hacemos una copia en pRGBArrayCopy
506
     * con las bandas alteradas de orden
507
     * @param bandList        lista de bandas
508
     * @param mask mascara
509
     * @param shl desplazamiento izquierda
510
     * @param shr desplazamiento derecha
511
     */
512
    private boolean calcMaskAndShift(int[] bandList, int[] mask, int[] shl,
513
                                     int[] shr) {
514
        boolean order = true;
515

    
516
        if (bandCount == 3) {
517
            for (int i = 0; i < bandCount; i++)
518
                if (bandList[i] != i) {
519
                    order = false;
520
                }
521

    
522
            if (!order) {
523
                for (int i = 0; i < bandCount; i++) {
524
                    switch (bandList[i]) {
525
                    case 0:
526
                        mask[i] = 0x00ff0000;
527
                        break;
528
                    case 1:
529
                        mask[i] = 0x0000ff00;
530
                        break;
531
                    case 2:
532
                        mask[i] = 0x000000ff;
533
                        break;
534
                    }
535
                    
536
                    if ((i == 1) && (bandList[i] == 0))
537
                        shr[i] = 8;
538
                    if ((i == 2) && (bandList[i] == 0)) 
539
                        shr[i] = 16;
540
                    if ((i == 0) && (bandList[i] == 1))
541
                        shl[i] = 8;
542
                    if ((i == 2) && (bandList[i] == 1))
543
                        shr[i] = 8;
544
                    if ((i == 0) && (bandList[i] == 2))
545
                        shl[i] = 16;
546
                    if ((i == 1) && (bandList[i] == 2))
547
                        shl[i] = 8;
548
                }
549
            }
550
        }
551

    
552
        return order;
553
    }
554

    
555
    /**
556
     * Intercambio de bandas para ecw manual. Se le pasa el array de bytes que se desea intercambiar
557
     * la mascara y desplazamientos previamente calculados con calcMaskAndShift
558
     * @param order        true si el orden de las bandas no est? alterado y false si lo est?
559
     * @param pRGBArray array de
560
     * @param mascara
561
     * @param shl desplazamiento a izquierda
562
     * @param shr desplazamiento a derecha
563
     * @return array con las bandas cambiadas
564
     */
565
    private int[] changeBands(boolean order, int[] pRGBArray, int[] mascara,
566
                              int[] shl, int[] shr) {
567
        if ((bandCount == 3) && !order) {
568
            int[] pRGBArrayCopy = new int[pRGBArray.length];
569

    
570
            for (int i = 0; i < pRGBArray.length; i++) {
571
                pRGBArrayCopy[i] = (pRGBArray[i] & 0xff000000) +
572
                                   (((pRGBArray[i] & mascara[2]) << shl[2]) >> shr[2]) +
573
                                   (((pRGBArray[i] & mascara[1]) << shl[1]) >> shr[1]) +
574
                                   (((pRGBArray[i] & mascara[0]) << shl[0]) >> shr[0]);
575
            }
576

    
577
            return pRGBArrayCopy;
578
        }
579

    
580
        return pRGBArray;
581
    }
582

    
583
    /**
584
     * Asigna al objeto Image los valores con los dato de la imagen contenidos en el
585
     * vector de enteros.
586
     * @param image        imagen con los datos actuales
587
     * @param startX        inicio de la posici?n en X dentro de la imagen
588
     * @param startY        inicio de la posici?n en X dentro de la imagen
589
     * @param w        Ancho de la imagen
590
     * @param h        Alto de la imagen
591
     * @param rgbArray        vector que contiene la banda que se va a sustituir
592
     * @param offset        desplazamiento
593
     * @param scansize        tama?o de imagen recorrida por cada p
594
     */
595
    protected void setRGBLine(BufferedImage image, int startX, int startY,
596
                              int w, int h, int[] rgbArray, int offset,
597
                              int scansize) {
598
        image.setRGB(startX, startY, w, h, rgbArray, offset, scansize);
599
    }
600

    
601
    /**
602
     * Asigna al objeto Image la mezcla entre los valores que ya tiene y los valores
603
     * con los dato de la imagen contenidos en el vector de enteros. De los valores RGB
604
     * que ya contiene se mantienen las bandas que no coinciden con el valor de flags. La
605
     * banda correspondiente a flags es sustituida por los datos del vector.
606
     * @param image        imagen con los datos actuales
607
     * @param startX        inicio de la posici?n en X dentro de la imagen
608
     * @param startY        inicio de la posici?n en X dentro de la imagen
609
     * @param w        Ancho de la imagen
610
     * @param h        Alto de la imagen
611
     * @param rgbArray        vector que contiene la banda que se va a sustituir
612
     * @param offset        desplazamiento
613
     * @param scansize        tama?o de imagen recorrida por cada paso
614
     * @param flags        banda que se va a sustituir (Ctes de GeoRasterFile)
615
     */
616
    protected void setRGBLine(BufferedImage image, int startX, int startY,
617
                              int w, int h, int[] rgbArray, int offset,
618
                              int scansize, int flags) {
619
        int[] line = new int[rgbArray.length];
620
        image.getRGB(startX, startY, w, h, line, offset, scansize);
621

    
622
        if (flags == GeoRasterFile.RED_BAND) {
623
            for (int i = 0; i < line.length; i++)
624
                line[i] = (line[i] & 0x0000ffff) | (rgbArray[i] & 0xffff0000);
625
        } else if (flags == GeoRasterFile.GREEN_BAND) {
626
            for (int i = 0; i < line.length; i++)
627
                line[i] = (line[i] & 0x00ff00ff) | (rgbArray[i] & 0xff00ff00);
628
        } else if (flags == GeoRasterFile.BLUE_BAND) {
629
            for (int i = 0; i < line.length; i++)
630
                line[i] = (line[i] & 0x00ffff00) | (rgbArray[i] & 0xff0000ff);
631
        }
632

    
633
        image.setRGB(startX, startY, w, h, line, offset, scansize);
634
    }
635

    
636
    /**
637
     * Asigna al objeto Image la mezcla entre los valores que ya tiene y los valores
638
     * con los dato de la imagen contenidos en el vector de enteros. De los valores RGB
639
     * que ya contiene se mantienen las bandas que no coinciden con el valor de flags. La
640
     * banda correspondiente a flags es sustituida por los datos del vector.
641
     * @param image        imagen con los datos actuales
642
     * @param startX        inicio de la posici?n en X dentro de la imagen
643
     * @param startY        inicio de la posici?n en X dentro de la imagen
644
     * @param w        Ancho de la imagen
645
     * @param h        Alto de la imagen
646
     * @param rgbArray        vector que contiene la banda que se va a sustituir
647
     * @param offset        desplazamiento
648
     * @param scansize        tama?o de imagen recorrida por cada paso
649
     * @param origBand        Banda origen del GeoRasterFile
650
     * @param destBandFlag        banda que se va a sustituir (Ctes de GeoRasterFile)
651
     */
652
    protected void setRGBLine(BufferedImage image, int startX, int startY,
653
                              int w, int h, int[] rgbArray, int offset,
654
                              int scansize, int origBand, int destBandFlag) {
655
        int[] line = new int[rgbArray.length];
656
        image.getRGB(startX, startY, w, h, line, offset, scansize);
657

    
658
        if ((origBand == 0) && (destBandFlag == GeoRasterFile.RED_BAND)) {
659
            for (int i = 0; i < line.length; i++)
660
                line[i] = (line[i] & 0xff00ffff) | (rgbArray[i] & 0x00ff0000);
661
        } else if ((origBand == 1) &&
662
                       (destBandFlag == GeoRasterFile.GREEN_BAND)) {
663
            for (int i = 0; i < line.length; i++)
664
                line[i] = (line[i] & 0xffff00ff) | (rgbArray[i] & 0x0000ff00);
665
        } else if ((origBand == 2) &&
666
                       (destBandFlag == GeoRasterFile.BLUE_BAND)) {
667
            for (int i = 0; i < line.length; i++)
668
                line[i] = (line[i] & 0xffffff00) | (rgbArray[i] & 0x000000ff);
669
        }
670
        else if ((origBand == 0) && (destBandFlag == GeoRasterFile.GREEN_BAND)) {
671
            for (int i = 0; i < line.length; i++)
672
                line[i] = (line[i] & 0xffff00ff) |
673
                          ((rgbArray[i] & 0x00ff0000) >> 8);
674
        } else if ((origBand == 0) &&
675
                       (destBandFlag == GeoRasterFile.BLUE_BAND)) {
676
            for (int i = 0; i < line.length; i++)
677
                line[i] = (line[i] & 0xffffff00) |
678
                          ((rgbArray[i] & 0x00ff0000) >> 16);
679
        }
680
        else if ((origBand == 1) && (destBandFlag == GeoRasterFile.RED_BAND)) {
681
            for (int i = 0; i < line.length; i++)
682
                line[i] = (line[i] & 0xff00ffff) |
683
                          ((rgbArray[i] & 0x0000ff00) << 8);
684
        } else if ((origBand == 1) &&
685
                       (destBandFlag == GeoRasterFile.BLUE_BAND)) {
686
            for (int i = 0; i < line.length; i++)
687
                line[i] = (line[i] & 0xffffff00) |
688
                          ((rgbArray[i] & 0x0000ff00) >> 8);
689
        }
690
        else if ((origBand == 2) && (destBandFlag == GeoRasterFile.RED_BAND)) {
691
            for (int i = 0; i < line.length; i++)
692
                line[i] = (line[i] & 0xff00ffff) |
693
                          ((rgbArray[i] & 0x000000ff) << 16);
694
        } else if ((origBand == 2) &&
695
                       (destBandFlag == GeoRasterFile.GREEN_BAND)) {
696
            for (int i = 0; i < line.length; i++)
697
                line[i] = (line[i] & 0xffff00ff) |
698
                          ((rgbArray[i] & 0x000000ff) << 8);
699
        }
700

    
701
        image.setRGB(startX, startY, w, h, line, offset, scansize);
702
    }
703
            
704
    /* (non-Javadoc)
705
     * @see org.cresques.io.GeoRasterFile#updateImage(int, int, org.cresques.cts.ICoordTrans, java.awt.Image, int origBand, int destBand)
706
     */
707
    public Image updateImage(int width, int height, ICoordTrans rp, Image img,
708
                             int origBand, int destBandFlag) throws SupersamplingNotSupportedException{
709
        //TODO reproyectar para devolver el trozo de imagen pedida sobre ...
710
        // la proyecci?n de destino.
711
        int line = 0;
712
        boolean mustResize = false;
713
        Dimension fullSize = null;
714
        boolean trySupersampling = false;
715

    
716
        if (file == null) {
717
            return null;
718
        }
719

    
720
        try {
721
            int[] bandlist;
722
            int[] bandListTriband;
723
            int[] pRGBArray = null;
724

    
725
            if(mustVerifySize()){
726
                    // Work out the correct aspect for the setView call.
727
                    double dFileAspect = (double) v.width() / (double) v.height();
728
                    double dWindowAspect = (double) width / (double) height;
729
        
730
                    if (dFileAspect > dWindowAspect) {
731
                        height = (int) ((double) width / dFileAspect);
732
                    } else {
733
                        width = (int) ((double) height * dFileAspect);
734
                    }
735
            }
736

    
737
            fullSize = new Dimension(width, height);
738
                        
739
            ChunkFrame[] frames = ChunkFrame.computeFrames(file, v, fullSize, extent);
740
                    
741
            if (frames.length == 1) {
742
                width = frames[0].width;
743
                height = frames[0].height;
744

    
745
                if (width <= 0)
746
                    width = 1;
747
             
748
                if (height <= 0)
749
                    height = 1;
750
            }
751
                        
752
            // Create an image of the ecw file.
753
            pRGBArray = new int[width];
754

    
755
            // Setup the view parameters for the ecw file.
756
            bandlist = new int[bandCount];
757
            bandListTriband = new int[bandCount];
758

    
759
            if (bandCount > 2) {
760
                bandlist[0] = getBand(RED_BAND);
761
                bandlist[1] = getBand(GREEN_BAND);
762
                bandlist[2] = getBand(BLUE_BAND);
763

    
764
                if (bandCount > 3) {
765
                    for (int i = 3; i < bandCount; i++) {
766
                        bandlist[i] = 0;
767
                    }
768
                }
769
            } else {
770
                for (int i = 0; i < bandCount; i++)
771
                    bandlist[i] = i;
772
            }
773

    
774
            if (bandCount == 3) {
775
                bandListTriband[0] = 0;
776
                bandListTriband[1] = 1;
777
                bandListTriband[2] = 2;
778
            }
779

    
780
            int[] mascara = new int[3];
781
            int[] shl = new int[3];
782
            int[] shr = new int[3];
783
            boolean order = true;
784
            
785
                        
786
            if (img == null) { //Caso en el que se crea un Image
787
                EcwFile.nUpdate = 1;
788

    
789
                Image ecwImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
790

    
791
                for (int nChunk = 0; nChunk < frames.length; nChunk++) {
792
                    ChunkFrame f = frames[nChunk];
793
                    
794
                    try{
795
                            if (bandCount != 3) {
796
                                setFileView(file.numBands, bandlist, f);
797
                            } else {
798
                                setFileView(file.numBands, bandListTriband, f);
799
                            }
800
                    }catch(JNCSInvalidSetViewException exc){
801
                            trySupersampling = true;
802
                    }
803

    
804
                    order = calcMaskAndShift(bandlist, mascara, shl, shr);
805

    
806
                    for (line = 0; line < f.height; line++) {
807
                        file.readLineRGBA(pRGBArray);
808
                        pRGBArray = changeBands(order, pRGBArray, mascara, shl, shr);
809
                        setRGBLine((BufferedImage) ecwImage, f.pos.x, f.pos.y + line, f.width, 1, pRGBArray, 0, f.width);
810
                    }
811
                                        
812
                } //Chuncks
813

    
814
                applyAlpha(ecwImage);
815

    
816
                if (frames[0].mustResize && !this.multifile)
817
                    return resizeAndResampleImage(fullSize, ecwImage);
818
                
819
                lastRefreshPercent = file.getPercentComplete();
820

    
821
                //System.out.println("Leido al "+lastRefreshPercent+" %.");
822
                return ecwImage;
823
            } else { //Caso en el que se actualiza una banda del Image
824
                EcwFile.nUpdate++;
825

    
826
                for (int nChunk = 0; nChunk < frames.length; nChunk++) {
827
                    ChunkFrame f = frames[nChunk];
828

    
829
                    if (bandCount != 3) {
830
                        setFileView(file.numBands, bandlist, f);
831
                    } else {
832
                        setFileView(file.numBands, bandListTriband, f);
833
                    }
834

    
835
                    order = calcMaskAndShift(bandlist, mascara, shl, shr);
836
                    
837
                    for (line = 0; line < f.height; line++) {
838
                        file.readLineRGBA(pRGBArray);
839
                        pRGBArray = changeBands(order, pRGBArray, mascara, shl, shr);
840
                        setRGBLine((BufferedImage) img, f.pos.x, f.pos.y + line, f.width, 1, pRGBArray, 0, f.width, origBand, destBandFlag);
841
                    }
842
                } //Chuncks
843

    
844
                applyAlpha(img);
845

    
846
                if (frames[0].mustResize && (nUpdate == 3) && this.multifile) {
847
                    return resizeAndResampleImage(fullSize, img);
848
                }else{
849
                        isSupersampling = false;
850
                                this.stepArrayX = this.stepArrayY = null;
851
                }
852

    
853
                lastRefreshPercent = file.getPercentComplete();
854

    
855
                //System.out.println("Leido al "+lastRefreshPercent+" %.");
856
                return img;
857
            }
858
        } catch (com.ermapper.ecw.JNCSException e) { //java.lang.ArrayIndexOutOfBoundsException:
859
            bErrorOnOpen = true;
860
            System.err.println("EcwFile JNCS Error en la l?nea " + line + "/" +
861
                               height);
862
            System.err.println(e.getMessage());
863
        } catch (java.lang.ArrayIndexOutOfBoundsException e) { //:
864
            bErrorOnOpen = true;
865
            System.err.println("EcwFile ArrayIndex Error en la l?nea " + line +"/" + height);
866
            System.err.println(e.getMessage());
867
        } catch (Exception e) {
868
            bErrorOnOpen = true;
869
            errorMessage = e.getMessage();
870
            System.err.println(errorMessage);
871
            if(trySupersampling)
872
                    throw new SupersamplingNotSupportedException();
873
        }
874

    
875
        return img;
876
    }
877

    
878
        /**
879
         * Esta funci?n calcula los arrays de steps en X e Y para que cuando hay supersampleo 
880
         * se aplique el filtro solo a la esquina superior izquierda de cada pixel. 
881
         */
882
    private void calcArraySteps(int width, int height, double stepX, double stepY, double offsetX, double offsetY){
883
            isSupersampling = true;
884
            int w = (int) (Math.ceil(((double)width) * stepX) + 1);
885
            this.stepArrayX = new int[w];
886
            for (double j =  Math.abs(offsetX); j < w; j += stepX) 
887
                    stepArrayX[(int)(j)] ++;
888
            int h = (int) (Math.ceil(((double)height) * stepY) + 1);
889
            this.stepArrayY = new int[h];
890
            for (double j =  Math.abs(offsetY); j < h; j += stepY) 
891
                    stepArrayY[(int)(j)] ++;
892
        }
893

    
894
        /**
895
         * Obtiene una ventana de datos de la imagen a partir de coordenadas reales. 
896
         * No aplica supersampleo ni subsampleo sino que devuelve una matriz de igual tama?o a los
897
         * pixeles de disco. 
898
         * @param x Posici?n X superior izquierda
899
         * @param y Posici?n Y superior izquierda
900
         * @param w Ancho en coordenadas reales
901
         * @param h Alto en coordenadas reales
902
         * @param rasterBuf        Buffer de datos
903
         * @param bandList
904
         * @return Buffer de datos
905
         */
906
        public RasterBuf getWindowRaster(double x, double y, double w, double h, BandList bandList, RasterBuf rasterBuf) {                
907
                Extent selectedExtent = new Extent(x, y, x + w, y - h);
908
                setView(selectedExtent);
909
                int wPx = rasterBuf.getWidth();
910
                int hPx = rasterBuf.getHeight();
911
                try{
912
                        int[] bl = new int[3];
913
                        bl[0] = 0;bl[1] = 1;bl[2] = 2;
914
                        file.setView(file.numBands, bl, selectedExtent.minX(), selectedExtent.maxY(), selectedExtent.maxX(), selectedExtent.minY(), wPx, hPx);                        
915
                        int width = (int)((w * file.width) / extent.width());
916
                        int height = (int)((h * file.height) / extent.height());
917
                        rasterBuf = new RasterBuf(RasterBuf.TYPE_BYTE, wPx, hPx, bandList.getDrawableBandsCount(), true);
918
                        
919
                        int[] pRGBArray = new int[width];
920
                        for (int line = 0; line < rasterBuf.getHeight(); line++) {
921
                file.readLineRGBA(pRGBArray);
922
                for(int col = 0; col < pRGBArray.length; col ++){
923
                        rasterBuf.setElemByte(line, col, 0, (byte)(pRGBArray[col] & 0x000000ff));
924
                        rasterBuf.setElemByte(line, col, 1, (byte)((pRGBArray[col] & 0x0000ff00) >> 8));
925
                        rasterBuf.setElemByte(line, col, 2, (byte)((pRGBArray[col] & 0x00ff0000) >> 16));
926
                }
927
            }
928
                }catch(JNCSInvalidSetViewException exc){
929
                        exc.printStackTrace();
930
                }catch (JNCSFileNotOpenException e) {
931
                        e.printStackTrace();
932
                }catch (JNCSException ex) {
933
                        ex.printStackTrace();
934
                }
935
                
936
                return rasterBuf;
937
        }
938
        
939
        /**
940
         * Obtiene una ventana de datos de la imagen a partir de coordenadas pixel. 
941
         * No aplica supersampleo ni subsampleo sino que devuelve una matriz de igual tama?o a los
942
         * pixeles de disco. 
943
         * @param x Posici?n X superior izquierda
944
         * @param y Posici?n Y superior izquierda
945
         * @param w Ancho en coordenadas reales
946
         * @param h Alto en coordenadas reales
947
         * @param rasterBuf        Buffer de datos
948
         * @param bandList
949
         * @return Buffer de datos
950
         */
951
        public RasterBuf getWindowRaster(int x, int y, int w, int h, BandList bandList, RasterBuf rasterBuf) {
952
                double initX = file.originX + ((x * extent.width()) / file.width);
953
                double initY = file.originY - ((y * extent.height()) / file.height);
954
                double width = ((w * extent.width()) / file.width);
955
                double height = ((h * extent.height()) / file.height);
956
                return getWindowRaster(initX, initY, width, height, bandList, rasterBuf);
957
        }
958
    
959
    /**
960
     * 
961
     * @param sz
962
     * @param image
963
     * @return
964
     */
965
    private Image resizeAndResampleImage(Dimension sz, Image image) {
966
        int w = (int)sz.getWidth();
967
        int h = (int)sz.getHeight();
968
            Image buffImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
969
            
970
        //Desplazamiento para la X y la Y leidas. Estas tienen efecto cuando un pixel no empieza a visualizarse
971
        //justo en su esquina superior izquierda y tiene que ser cortado en la visualizaci?n.
972
       
973
        double currentViewX = (((double) file.width)/(Math.abs(extent.getMax().getX() - extent.getMin().getX())))*(v.minX()-file.originX);
974
                double currentViewY = (((double) file.height)/(Math.abs(extent.getMax().getY() - extent.getMin().getY())))*(file.originY - v.minY());
975
        double offsetX = Math.abs(currentViewX - ((int)currentViewX));
976
        double offsetY = Math.abs(currentViewY - ((int)currentViewY));
977
        
978
        int xSrc, ySrc;
979
        int decr = 2;
980

    
981
        if(v.minX() == extent.minX() || v.maxX() == extent.maxX() || v.minY() == extent.minY() || v.maxY() == extent.maxY()){
982
                decr = 0;
983
                offsetX = offsetY = 0;
984
        }
985

    
986
        double scaleW = (double)((double)(image.getWidth(null) - decr) / (double)w);
987
        double scaleH = (double)((double)(image.getHeight(null) - decr) / (double)h);
988
        this.calcArraySteps(w, h, scaleW, scaleH, offsetX, offsetY);
989
        for (int y1 = 0; y1 < h; y1++){
990
        ySrc = (int) ((y1 * scaleH) + offsetY);
991
                for (int x1 = 0; x1 < w; x1++){
992
                        xSrc = (int) ((x1 * scaleW) + offsetX);
993
                        try {
994
                                ((BufferedImage) buffImg).setRGB(x1, y1, ((BufferedImage)image).getRGB(xSrc, ySrc));
995
                        } catch (java.lang.ArrayIndexOutOfBoundsException e) {
996
                        }
997
                }
998
        }
999
        
1000
        return buffImg;
1001
    }
1002

    
1003
    
1004
    private void applyAlpha(Image im) {
1005
        BufferedImage img = (BufferedImage) im;
1006
        int alpha = (getAlpha() & 0xff) << 24;
1007
        int w = img.getWidth();
1008
        int[] line = new int[w];
1009

    
1010
        for (int j = 0; j < img.getHeight(); j++) {
1011
            img.getRGB(0, j, w, 1, line, 0, w);
1012

    
1013
            for (int i = 0; i < w; i++)
1014
                line[i] = (alpha | (line[i] & 0x00ffffff));
1015

    
1016
            img.setRGB(0, j, w, 1, line, 0, w);
1017
        }
1018
    }
1019

    
1020
    /* (non-Javadoc)
1021
     * @see org.cresques.io.GeoRasterFile#getData(int, int)
1022
     */
1023
    public Object getData(int x, int y, int band) {
1024
        //file.readLineRGBA();
1025
        return null;
1026
    }
1027

    
1028
    /**
1029
     * Devuelve los datos de una ventana solicitada
1030
     * @param ulX        coordenada X superior izda.
1031
     * @param ulY        coordenada Y superior derecha.
1032
     * @param sizeX        tama?o en X de la ventana.
1033
     * @param sizeY tama?o en Y de la ventana.
1034
     * @param band        Banda solicitada.
1035
     */
1036
    public byte[] getWindow(int ulX, int ulY, int sizeX, int sizeY, int band) {
1037
        //TODO Nacho: Implementar getWindow de EcwFile
1038
        return null;
1039
    }
1040

    
1041
    /**
1042
     * Obtiene la zona (Norte / Sur)
1043
     * @return true si la zona es norte y false si es sur
1044
     */
1045
    public boolean getZone() {
1046
        //TODO Nacho: Implementar getZone de EcwFile
1047
        return false;
1048
    }
1049

    
1050
    /**
1051
     *Devuelve el n?mero de zona UTM
1052
     *@return N?mero de zona
1053
     */
1054
    public int getUTM() {
1055
        //                TODO Nacho: Implementar getUTM de EcwFile
1056
        return 0;
1057
    }
1058

    
1059
    /**
1060
     * Obtiene el sistema de coordenadas geograficas
1061
     * @return Sistema de coordenadas geogr?ficas
1062
     */
1063
    public String getGeogCS() {
1064
        //TODO Nacho: Implementar getGeogCS de EcwFile
1065
        return new String("");
1066
    }
1067

    
1068
    /**
1069
     * Devuelve el tama?o de bloque
1070
     * @return Tama?o de bloque
1071
     */
1072
    public int getBlockSize() {
1073
        //TODO Nacho: Implementar getBlockSize de EcwFile        
1074
        return 1;
1075
    }
1076
        
1077
    /**
1078
         * Calcula la transformaci?n que se produce sobre la vista cuando la imagen tiene un fichero .rmf
1079
         * asociado. En Ecw el origen de coordenadas en Y es el valor m?ximo y decrece hasta el m?nimo.
1080
         * @param originX Origen de la imagen en la coordenada X
1081
         * @param originY Origen de la imagen en la coordenada Y
1082
         */
1083
    public void setExtentTransform(double originX, double originY, double w, double h, double psX, double psY) {
1084
                
1085
        }
1086

    
1087
    /**
1088
     * Trozo de imagen (Chunk) en que se divide la consulta a la librer?a,
1089
     * para esquivar el bug#2.
1090
     *
1091
     * @author luisw
1092
     */
1093
    static class ChunkFrame {
1094
        // Ancho m?ximo (~2500 px)
1095
        final static int MAX_WIDTH = 1536;
1096

    
1097
        // Alto m?ximo (no hay l?mite)
1098
        final static int MAX_HEIGHT = 1536;
1099
        Point pos;
1100
        Extent v;
1101
        int width;
1102
        int height;
1103
        boolean mustResize = false;
1104

    
1105
        public ChunkFrame(Extent vista, int w, int h) {
1106
            v = vista;
1107
            width = w;
1108
            height = h;
1109
        }
1110

    
1111
        /**
1112
         * Calcula el array de chunks (trozos).
1113
         * @param file        Fichero ecw que hay que trocear.
1114
         * @param v Extent total de la vista.
1115
         * @param sz        Tama?o total de la vista.
1116
         * @return array de ChunkFrames.
1117
         * @throws JNCSFileNotOpenException
1118
         */
1119
        public static ChunkFrame[] computeFrames(JNCSFile file, Extent v,
1120
                                                 Dimension sz, Extent extent)
1121
                                          throws JNCSFileNotOpenException {
1122
            ChunkFrame[] frames = null;
1123
            ChunkFrame f = null;
1124

    
1125
            // Calcula el n? de chunks (filas y columnas)
1126
            int numCol = (sz.width / MAX_WIDTH);
1127

    
1128
            // Calcula el n? de chunks (filas y columnas)
1129
            int numRow = (sz.height / MAX_HEIGHT);
1130

    
1131
            if ((sz.width - (numCol * MAX_WIDTH)) > 0) {
1132
                numCol++;
1133
            }
1134

    
1135
            if ((sz.height - (numRow * MAX_HEIGHT)) > 0) {
1136
                numRow++;
1137
            }
1138

    
1139
            frames = new ChunkFrame[numCol * numRow];
1140

    
1141
            JNCSDatasetPoint ptMin = file.convertWorldToDataset(v.minX(), v.minY());
1142
            JNCSDatasetPoint ptMax = file.convertWorldToDataset(v.maxX(), v.maxY());
1143

    
1144
            //No utilizamos JNCSDatasetPoint porque siempre hace un redondeo por abajo con lo que perdemos precisi?n. En su lugar
1145
            //utilizamos currentViewM... calculado manualmente y que nos proporciona todos los decimales 
1146
            double currentViewMinX = (((double) file.width)/(Math.abs(extent.getMax().getX() - extent.getMin().getX())))*(v.minX()-file.originX);
1147
            double currentViewMaxX = (((double) file.width)/(Math.abs(extent.getMax().getX() - extent.getMin().getX())))*(v.maxX()-file.originX);
1148
                    double currentViewMinY = (((double) file.height)/(Math.abs(extent.getMax().getY() - extent.getMin().getY())))*(file.originY - v.minY());
1149
                    double currentViewMaxY = (((double) file.height)/(Math.abs(extent.getMax().getY() - extent.getMin().getY())))*(file.originY - v.maxY());
1150
                      
1151
            if ((ptMax.x - ptMin.x) < sz.width) {
1152
                numCol = numRow = 1;
1153
                frames = new ChunkFrame[numCol * numRow];
1154
                int nPixelsX = (int)Math.ceil(Math.abs(currentViewMaxX - currentViewMinX));
1155
                int nPixelsY = (int)Math.ceil(Math.abs(currentViewMaxY - currentViewMinY));
1156
                
1157
                if(v.minX() == extent.minX() || v.maxX() == extent.maxX() || v.minY() == extent.minY() || v.maxY() == extent.maxY()){
1158
                        f = frames[0] = new ChunkFrame(v, nPixelsX, nPixelsY);
1159
                        f.v = new Extent(v);
1160
                }else{
1161
                        f = frames[0] = new ChunkFrame(v, nPixelsX + 1, nPixelsY + 1);
1162
                        double pointEndWcX = v.minX() + (((nPixelsX + 1) * Math.abs(v.maxX() - v.minX())) / nPixelsX);
1163
                        double pointEndWcY = v.maxY() - (((nPixelsY + 1) * Math.abs(v.maxY() - v.minY())) / nPixelsY);
1164
                        f.v = new Extent(v.minX(), v.maxY(), pointEndWcX, pointEndWcY);
1165
                }
1166
                
1167
                f.pos = new Point(0, 0);
1168
                f.mustResize = true;
1169
            } else {
1170
                // Calcula cada chunk
1171
                double stepx = ((double) ptMax.x - ptMin.x) / sz.getWidth();
1172
                double stepy = ((double) ptMax.y - ptMin.y) / sz.getHeight();
1173
                int h = sz.height;
1174

    
1175
                for (int r = 0; r < numRow; r++) {
1176
                    int w = sz.width;
1177

    
1178
                    for (int c = 0; c < numCol; c++) {
1179
                        f = new ChunkFrame(null, -1, -1);
1180

    
1181
                        // Posici?n del chunk
1182
                        f.pos = new Point(c * MAX_WIDTH, r * MAX_HEIGHT);
1183

    
1184
                        // Tama?o del chunk
1185
                        f.width = Math.min(MAX_WIDTH, w);
1186
                        f.height = Math.min(MAX_HEIGHT, h);
1187

    
1188
                        // Extent del chunk
1189
                        int x1 = ptMin.x + (int) (f.pos.x * stepx);
1190
                        int x2 = x1 + (int) (f.width * stepx);
1191
                        int y1 = ptMax.y - (int) (f.pos.y * stepy); 
1192
                        int y2 = y1 - (int) (f.height * stepy); //ptMin.y;
1193
                        JNCSWorldPoint pt1 = file.convertDatasetToWorld(x1, y1);
1194
                        JNCSWorldPoint pt2 = file.convertDatasetToWorld(x2, y2);
1195
                        
1196
                        f.v = new Extent(pt1.x, pt1.y, pt2.x, pt2.y); // Hay que calcularlo
1197
                        frames[(r * numCol) + c] = f;
1198
                        w -= MAX_WIDTH;
1199
                    }
1200

    
1201
                    h -= MAX_HEIGHT;
1202
                }
1203
            }
1204

    
1205
            //System.out.println("Hay "+numRow+" filas y "+numCol+" columnas.");
1206
            return frames;
1207
        }
1208
    }
1209
}