Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libRaster / src / org / gvsig / raster / dataset / RasterDataset.java @ 27361

History | View | Annotate | Download (33.2 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2006 IVER T.I. 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
package org.gvsig.raster.dataset;
20

    
21
import java.awt.geom.AffineTransform;
22
import java.awt.geom.NoninvertibleTransformException;
23
import java.awt.geom.Point2D;
24
import java.io.File;
25
import java.io.IOException;
26
import java.lang.reflect.Constructor;
27
import java.lang.reflect.InvocationTargetException;
28
import java.util.Iterator;
29
import java.util.Map.Entry;
30

    
31
import org.cresques.cts.ICoordTrans;
32
import org.cresques.cts.IProjection;
33
import org.gvsig.raster.RasterLibrary;
34
import org.gvsig.raster.dataset.io.GdalDriver;
35
import org.gvsig.raster.dataset.io.IRegistrableRasterFormat;
36
import org.gvsig.raster.dataset.io.MemoryRasterDriver;
37
import org.gvsig.raster.dataset.io.MemoryRasterDriverParam;
38
import org.gvsig.raster.dataset.io.RasterDriverException;
39
import org.gvsig.raster.dataset.io.rmf.ClassSerializer;
40
import org.gvsig.raster.dataset.io.rmf.ParsingException;
41
import org.gvsig.raster.dataset.io.rmf.RmfBlocksManager;
42
import org.gvsig.raster.dataset.properties.DatasetColorInterpretation;
43
import org.gvsig.raster.dataset.properties.DatasetHistogram;
44
import org.gvsig.raster.dataset.properties.DatasetMetadata;
45
import org.gvsig.raster.dataset.properties.DatasetStatistics;
46
import org.gvsig.raster.dataset.serializer.ColorInterpretationRmfSerializer;
47
import org.gvsig.raster.dataset.serializer.GeoInfoRmfSerializer;
48
import org.gvsig.raster.dataset.serializer.ProjectionRmfSerializer;
49
import org.gvsig.raster.dataset.serializer.RmfSerializerException;
50
import org.gvsig.raster.datastruct.ColorTable;
51
import org.gvsig.raster.datastruct.Extent;
52
import org.gvsig.raster.datastruct.NoData;
53
import org.gvsig.raster.datastruct.Transparency;
54
import org.gvsig.raster.datastruct.serializer.ColorTableRmfSerializer;
55
import org.gvsig.raster.datastruct.serializer.NoDataRmfSerializer;
56
import org.gvsig.raster.projection.CRS;
57
import org.gvsig.raster.util.RasterUtilities;
58
import org.gvsig.raster.util.extensionPoints.ExtensionPoint;
59
/**
60
 * Manejador de ficheros raster georeferenciados.
61
 * 
62
 * Esta clase abstracta es el ancestro de todas las clases que proporcionan
63
 * soporte para ficheros raster georeferenciados.<br>
64
 * Actua tambien como una 'Fabrica', ocultando al cliente la manera en que
65
 * se ha implementado ese manejo. Una clase nueva que soportara un nuevo
66
 * tipo de raster tendr?a que registrar su extensi?n o extensiones usando
67
 * el m?todo @see registerExtension.<br> 
68
 */
69
public abstract class RasterDataset extends GeoInfo {
70
        /**
71
         * Flags que representan a las bandas visualizables
72
         */
73
        public static final int              RED_BAND            = 0x01;
74
        public static final int              GREEN_BAND          = 0x02;
75
        public static final int              BLUE_BAND           = 0x04;
76
        public static final int              ALPHA_BAND          = 0x08;
77

    
78
        /**
79
         * N?mero de bandas de la imagen
80
         */
81
        protected int                        bandCount           = 1;
82
        private int[]                        dataType            = null;
83

    
84
        protected DatasetStatistics          stats               = new DatasetStatistics(this);
85
        protected DatasetHistogram           histogram           = null;
86
        protected Object                     param               = null;
87
        protected RmfBlocksManager           rmfBlocksManager    = null;
88

    
89
        protected ColorTable                 colorTable          = null;
90
        protected DatasetColorInterpretation colorInterpretation = null;
91

    
92
        /**
93
         * Valor del NoData
94
         */
95
        protected double                     noData              = 0;
96

    
97
        protected String                     wktProjection       = "";
98

    
99
        /**
100
         * Indica si el valor NoData esta activo
101
         */
102
        protected boolean                    noDataEnabled       = false;
103
        
104
        /*
105
         * (non-Javadoc)
106
         * @see java.lang.Object#clone()
107
         */
108
        public Object clone() {
109
                try {
110
                        RasterDataset dataset = RasterDataset.open(proj, param);
111
                        // Estas van por referencia
112
                        dataset.histogram = histogram;
113
                        dataset.stats = stats;
114
                        return dataset;
115
                } catch (NotSupportedExtensionException e) {
116
                        e.printStackTrace();
117
                } catch (RasterDriverException e) {
118
                        e.printStackTrace();
119
                }
120
                return null;
121
        }
122
        
123
        /**
124
         * Constructor
125
         */
126
        public RasterDataset() {
127
        }
128
        
129
        /**
130
         * Factoria para abrir distintos tipos de raster.
131
         * 
132
         * @param proj Proyecci?n en la que est? el raster.
133
         * @param fName Nombre del fichero.
134
         * @return GeoRasterFile, o null si hay problemas.
135
         */
136
        public static RasterDataset open(IProjection proj, Object param) throws NotSupportedExtensionException, RasterDriverException {
137
                String idFormat = null;
138

    
139
                if (param instanceof String)
140
                        idFormat = RasterUtilities.getExtensionFromFileName(((String) param));
141
                if (param instanceof IRegistrableRasterFormat)
142
                        idFormat = ((IRegistrableRasterFormat) param).getFormatID();
143

    
144
                RasterDataset grf = null;
145

    
146
                Class clase = null;
147
                if (param instanceof MemoryRasterDriverParam) {
148
                        clase = MemoryRasterDriver.class;
149
                } else {
150
                        if (idFormat != null) {
151
                                ExtensionPoint extensionPoint = ExtensionPoint.getExtensionPoint("RasterReader");
152
                                clase = (Class) extensionPoint.getValue(idFormat);
153
                        }
154
                }
155

    
156
                if (clase == null)
157
                        clase = GdalDriver.class;
158
                
159
                Class [] args = {IProjection.class, Object.class};
160
                try {
161
                        Constructor hazNuevo = clase.getConstructor(args);
162
                        Object [] args2 = {proj, param};
163
                        grf = (RasterDataset) hazNuevo.newInstance(args2);
164
                } catch (SecurityException e) {
165
                        throw new RasterDriverException("Error SecurityException in open");
166
                } catch (NoSuchMethodException e) {
167
                        throw new RasterDriverException("Error NoSuchMethodException in open");
168
                } catch (IllegalArgumentException e) {
169
                        throw new RasterDriverException("Error IllegalArgumentException in open");
170
                } catch (InstantiationException e) {
171
                        throw new RasterDriverException("Error InstantiationException in open");
172
                } catch (IllegalAccessException e) {
173
                        throw new RasterDriverException("Error IllegalAccessException in open");
174
                } catch (InvocationTargetException e) {
175
                        throw new NotSupportedExtensionException("Error in open. Problemas con las librer?as.");
176
                }
177
                return grf;
178
        }
179
                
180
        /**
181
         * Acciones de inicilizaci?n comunes a todos los drivers.
182
         * Este m?todo debe ser llamado explicitamente por el constructor de cada driver.
183
         * Estas son acciones de inicializaci?n que se ejecutan despu?s del constructor de cada driver.
184
         * Las acciones que hayan de ser realizadas antes se definen en el constructor de RasterDataset.
185
         */
186
        protected void init() {
187
        }
188
        
189
        /**
190
         * Tipo de fichero soportado.
191
         * Devuelve true si el tipo de fichero (extension) est? soportado, si no
192
         * devuelve false.
193
         * 
194
         * @param fName Fichero raster
195
         * @return  true si est? soportado, si no false.
196
                */
197
        public static boolean fileIsSupported(String fName) {
198
                ExtensionPoint extensionPoint = ExtensionPoint.getExtensionPoint("RasterReader");
199
                return extensionPoint.existKey(RasterUtilities.getExtensionFromFileName(fName));
200
        }
201

    
202
        /**
203
         * Obtiene la lista de extensiones de ficheros soportadas
204
         * @return Lista de extensiones registradas
205
         */
206
        public static String[] getExtensionsSupported() {
207
                return ExtensionPoint.getExtensionPoint("RasterReader").getKeys();
208
        }
209
        
210
        /**
211
         * Constructor
212
         * @param proj        Proyecci?n
213
         * @param name        Nombre del fichero de imagen.
214
         */
215
        public RasterDataset(IProjection proj, Object param) {
216
                super(proj, param);
217
                if(param instanceof String)
218
                        setFileSize(new File(getFName()).length());
219
        }
220

    
221
        
222
        /**
223
         * Carga un fichero raster. Puede usarse para calcular el extent e instanciar 
224
         * un objeto de este tipo.
225
         */
226
        abstract public GeoInfo load();
227
        
228
        /**
229
         * Cierra el fichero y libera los recursos.
230
         */
231
        abstract public void close();
232
                
233
        /**
234
         * Carga metadatos desde el fichero Rmf si estos existen
235
         * @param fName Nombre del fichero
236
         * @throws ParsingException 
237
         */
238
        protected void loadFromRmf(RmfBlocksManager manager) throws ParsingException {
239
                if (!manager.checkRmf())
240
                        return;
241

    
242
                if (!new File(manager.getPath()).exists())
243
                        return;
244

    
245
                GeoInfoRmfSerializer geoInfoSerializer = new GeoInfoRmfSerializer(this);
246
                ColorTableRmfSerializer colorTableSerializer = new ColorTableRmfSerializer();
247
                NoDataRmfSerializer noDataSerializer = new NoDataRmfSerializer(new NoData(noData, RasterLibrary.NODATATYPE_LAYER));
248
                ColorInterpretationRmfSerializer colorInterpSerializer = new ColorInterpretationRmfSerializer();
249
                ProjectionRmfSerializer projectionRmfSerializer = new ProjectionRmfSerializer();
250

    
251
                manager.addClient(geoInfoSerializer);
252
                manager.addClient(colorTableSerializer);
253
                manager.addClient(noDataSerializer);
254
                manager.addClient(colorInterpSerializer);
255
                manager.addClient(projectionRmfSerializer);
256

    
257
                manager.read(null);
258

    
259
                manager.removeAllClients();
260

    
261
                if (colorTableSerializer.getResult() != null)
262
                        setColorTable((ColorTable) colorTableSerializer.getResult());
263

    
264
                if (noDataSerializer.getResult() != null) {
265
                        noData = ((org.gvsig.raster.datastruct.NoData) noDataSerializer.getResult()).getValue();
266
                        noDataEnabled = (((NoData) noDataSerializer.getResult()).getType() != RasterLibrary.NODATATYPE_DISABLED);
267
                }
268

    
269
                if (colorInterpSerializer.getResult() != null) {
270
                        DatasetColorInterpretation ci = (DatasetColorInterpretation) colorInterpSerializer.getResult();
271
                        setColorInterpretation(ci);
272
                        if (ci.getBand(DatasetColorInterpretation.ALPHA_BAND) != -1)
273
                                getTransparencyDatasetStatus().setTransparencyBand(ci.getBand(DatasetColorInterpretation.ALPHA_BAND));
274
                }
275

    
276
                if (projectionRmfSerializer.getResult() != null) {
277
                        wktProjection = CRS.convertIProjectionToWkt((IProjection) projectionRmfSerializer.getResult());
278
                }
279
        }
280

    
281
        /**
282
         * Obtiene el ancho de la imagen
283
         * @return Ancho de la imagen
284
         */
285
        abstract public int getWidth();
286
        
287
        /**
288
         * Obtiene el ancho de la imagen
289
         * @return Ancho de la imagen
290
         */
291
        abstract public int getHeight();
292

    
293
        /**
294
         * Reproyecci?n.
295
         * @param rp        Coordenadas de la transformaci?n
296
         */
297
        abstract public void reProject(ICoordTrans rp);
298

    
299
        /**
300
         * Asigna un nuevo Extent 
301
         * @param e        Extent
302
         */
303
        abstract public void setView(Extent e);
304
        
305
        /**
306
         * Obtiene el extent asignado
307
         * @return        Extent
308
         */
309
        abstract public Extent getView();
310
                                
311
        /**
312
         * Obtiene el valor del raster en la coordenada que se le pasa.
313
         * El valor ser? Double, Int, Byte, etc. dependiendo del tipo de
314
         * raster.
315
         * @param x        coordenada X
316
         * @param y coordenada Y
317
         * @return
318
         * @throws InterruptedException 
319
         */
320
        abstract public Object getData(int x, int y, int band)throws InvalidSetViewException, FileNotOpenException, RasterDriverException, InterruptedException;
321

    
322
        /**
323
         * Obtiene el n?nero de bandas del fichero
324
         * @return Entero que representa el n?mero de bandas
325
         */
326
        public int getBandCount() { 
327
                return bandCount; 
328
        }
329
                
330
        /**
331
         * @return Returns the dataType.
332
         */
333
        public int[] getDataType() {
334
                return dataType;
335
        }
336
        
337
        /**
338
         * @param dataType The dataType to set.
339
         */
340
        public void setDataType(int[] dataType) {
341
                this.dataType = dataType;
342
        }
343
         
344
        /**
345
         * Obtiene el tama?o de pixel en X
346
         * @return tama?o de pixel en X
347
         */
348
        public double getPixelSizeX() {
349
                return externalTransformation.getScaleX();
350
        }
351
        
352
        /**
353
         * Obtiene el tama?o de pixel en Y
354
         * @return tama?o de pixel en Y
355
         */
356
        public double getPixelSizeY() {
357
                return externalTransformation.getScaleY();
358
        }
359

    
360
        /**
361
         * Obtiene una ventana de datos de la imagen a partir de coordenadas reales. 
362
         * No aplica supersampleo ni subsampleo sino que devuelve una matriz de igual tama?o a los
363
         * pixeles de disco. 
364
         * @param ulx Posici?n X superior izquierda
365
         * @param uly Posici?n Y superior izquierda
366
         * @param lrx Posici?n X inferior derecha
367
         * @param lry Posici?n Y inferior derecha
368
         * @param rasterBuf        Buffer de datos
369
         * @param bandList
370
         * @return Buffer de datos
371
         */
372
        abstract public IBuffer getWindowRaster(double ulx, double uly, double lrx, double lry, BandList bandList, IBuffer rasterBuf)throws InterruptedException, RasterDriverException;
373
        
374
        /**
375
         * Obtiene una ventana de datos de la imagen a partir de coordenadas reales. 
376
         * No aplica supersampleo ni subsampleo sino que devuelve una matriz de igual tama?o a los
377
         * pixeles de disco. 
378
         * @param x Posici?n X superior izquierda
379
         * @param y Posici?n Y superior izquierda
380
         * @param w Ancho en coordenadas reales
381
         * @param h Alto en coordenadas reales
382
         * @param rasterBuf        Buffer de datos
383
         * @param bandList
384
         * @param adjustToExtent Flag que dice si el extent solicitado debe ajustarse al extent del raster o no.
385
         * @return Buffer de datos
386
         */
387
        abstract public IBuffer getWindowRaster(double x, double y, double w, double h, BandList bandList, IBuffer rasterBuf, boolean adjustToExtent)throws InterruptedException, RasterDriverException;
388
        
389
        /**
390
         * Obtiene una ventana de datos de la imagen a partir de coordenadas reales. 
391
         * Se aplica supersampleo o subsampleo dependiendo del tama?o del buffer especificado.
392
         * 
393
         * @param minX Posici?n m?nima X superior izquierda
394
         * @param minY Posici?n m?nima Y superior izquierda
395
         * @param maxX Posici?n m?xima X inferior derecha
396
         * @param maxY Posici?n m?xima Y inferior derecha
397
         * @param bufWidth Ancho del buffer de datos
398
         * @param bufHeight Alto del buffer de datos
399
         * @param rasterBuf        Buffer de datos
400
         * @param adjustToExtent Flag que dice si el extent solicitado debe ajustarse al extent del raster o no.
401
         * @param bandList
402
         * @return Buffer de datos
403
         */
404
        abstract public IBuffer getWindowRaster(double minX, double minY, double maxX, double maxY, int bufWidth, int bufHeight, BandList bandList, IBuffer rasterBuf, boolean adjustToExtent)throws InterruptedException, RasterDriverException;
405
        
406
        /**
407
         * Obtiene una ventana de datos de la imagen a partir de coordenadas pixel. 
408
         * No aplica supersampleo ni subsampleo sino que devuelve una matriz de igual tama?o a los
409
         * pixeles de disco. 
410
         * @param x Posici?n X superior izquierda
411
         * @param y Posici?n Y superior izquierda
412
         * @param w Ancho en coordenadas reales
413
         * @param h Alto en coordenadas reales
414
         * @param rasterBuf        Buffer de datos
415
         * @param bandList
416
         * @return Buffer de datos
417
         */
418
        abstract public IBuffer getWindowRaster(int x, int y, int w, int h, BandList bandList, IBuffer rasterBuf)throws InterruptedException, RasterDriverException;
419
        
420
        /**
421
         * Obtiene una ventana de datos de la imagen a partir de coordenadas pixel. 
422
         * Se aplica supersampleo o subsampleo dependiendo del tama?o del buffer especificado.
423
         * 
424
         * @param x Posici?n X superior izquierda
425
         * @param y Posici?n Y superior izquierda
426
         * @param w Ancho en coordenadas reales
427
         * @param h Alto en coordenadas reales
428
         * @param bufWidth Ancho del buffer de datos
429
         * @param bufHeight Alto del buffer de datos
430
         * @param rasterBuf        Buffer de datos
431
         * @param bandList
432
         * @return Buffer de datos
433
         */
434
        abstract public IBuffer getWindowRaster(int x, int y, int w, int h, int bufWidth, int bufHeight, BandList bandList, IBuffer rasterBuf)throws InterruptedException, RasterDriverException;
435
        
436
        abstract public int getBlockSize();
437
        
438
        /**
439
         * Obtiene el objeto que contiene los metadatos. Este m?todo debe ser redefinido por los
440
         * drivers si necesitan devolver metadatos. 
441
         * @return
442
         */
443
        public DatasetMetadata getMetadata(){
444
                return null;
445
        }
446

    
447
        /**
448
         * Obtiene el valor NoData asociado al raster. Si hay un valor en el fichero
449
         * RMF se devuelve este, sino se buscar? en la cabecera del raster o metadatos de
450
         * este. Si finalmente no encuentra ninguno se devuelve el valor por defecto
451
         * definido en la libreria.
452
         * @return
453
         */
454
        public double getNoDataValue() {
455
                return noData;
456
        }
457

    
458
        /**
459
         * Pone el valor original de noData. Primero lo consulta del valor del metadata
460
         * y luego del RMF.
461
         */
462
        public void resetNoDataValue() {
463
                /**
464
                 * Intentamos recuperar el valor del metadatas, en caso de no encontrarlo le
465
                 * asignamos el noData por defecto
466
                 */
467
                noDataEnabled = false;
468
                do {
469
                        if (getMetadata() == null) {
470
                                noData = RasterLibrary.defaultNoDataValue;
471
                                break;
472
                        }
473

    
474
                        if (getMetadata().getNoDataValue().length == 0) {
475
                                noData = RasterLibrary.defaultNoDataValue;
476
                                break;
477
                        }
478

    
479
                        noData = getMetadata().getNoDataValue()[0];
480
                        noDataEnabled = getMetadata().isNoDataEnabled();
481
                } while (false);
482

    
483
                try {
484
                        NoData noDataObject = (NoData) loadObjectFromRmf(NoData.class, null);
485
                        if (noDataObject != null) {
486
                                if (noDataObject.getType() > 0)
487
                                        noData = noDataObject.getValue();
488
                                noDataEnabled = (noDataObject.getType() > 0);
489
                        }
490
                } catch (RmfSerializerException e) {
491
                }
492
        }
493
        
494
        /**
495
         * Establece el valor del NoData
496
         * @param value
497
         */
498
        public void setNoDataValue(double value) {
499
                noData = value;
500
                noDataEnabled = true;
501
        }
502
                
503
        /**
504
         * Obtiene el objeto que contiene que contiene la interpretaci?n de 
505
         * color por banda
506
         * @return
507
         */
508
        public DatasetColorInterpretation getColorInterpretation(){
509
                return colorInterpretation;
510
        }
511
                
512
        /**
513
         * Asigna el objeto que contiene que contiene la interpretaci?n de 
514
         * color por banda
515
         * @param DatasetColorInterpretation
516
         */
517
        public void setColorInterpretation(DatasetColorInterpretation colorInterpretation){
518
                this.colorInterpretation = colorInterpretation;
519
        }
520
        
521
        /**
522
         * Dice si el fichero tiene georreferenciaci?n o no.
523
         * @return true si tiene georreferenciaci?n y false si no la tiene
524
         */
525
        public boolean isGeoreferenced(){
526
                return true;
527
        }
528

    
529
        /**
530
         * Obtiene el objeto paleta. Esta paleta es la que tiene adjunta el fichero de disco. Si es
531
         * null este objeto quiere decir que no tiene paleta para su visualizaci?n. 
532
         * @return Palette
533
         */
534
        public ColorTable getColorTable() {
535
                return colorTable;
536
        }
537

    
538
        /**
539
         * Define el objeto paleta. Si se define null quiere decir que no tiene paleta
540
         * para su visualizaci?n. 
541
         * @param value
542
         */
543
        public void setColorTable(ColorTable value) {
544
                colorTable = value;
545
        }
546
        
547
        /**
548
         * Obtiene el estado de transparencia de un GeoRasterFile. 
549
         * @return Objeto TransparencyFileStatus
550
         */
551
        public Transparency getTransparencyDatasetStatus() {
552
                return null;
553
        }
554
        
555
        /**
556
         * Dado unas coordenadas reales, un tama?o de buffer y un tama?o de raster. 
557
         * Si el buffer es de mayor tama?o que el raster (supersampleo) quiere decir que 
558
         * por cada pixel de buffer se repiten varios del raster. Esta funci?n calcula el 
559
         * n?mero de pixels de desplazamiento en X e Y que corresponden al primer pixel del
560
         * buffer en la esquina superior izquierda. Esto es necesario porque la coordenada
561
         * solicitada es real y puede no caer sobre un pixel completo. Este calculo es
562
         * util cuando un cliente quiere supersamplear sobre un buffer y que no se lo haga
563
         * el driver autom?ticamente.
564
         * @param dWorldTLX Coordenada real X superior izquierda
565
         * @param dWorldTLY Coordenada real Y superior izquierda
566
         * @param dWorldBRX Coordenada real X inferior derecha
567
         * @param dWorldBRY Coordenada real Y inferior derecha
568
         * @param nWidth Ancho del raster
569
         * @param nHeight Alto del raster
570
         * @param bufWidth Ancho del buffer
571
         * @param bufHeight Alto del buffer
572
         * @return Array de dos elementos con el desplazamiento en X e Y. 
573
         */
574
        public double[] calcSteps(double dWorldTLX, double dWorldTLY, double dWorldBRX, double dWorldBRY, 
575
                        double nWidth, double nHeight, int bufWidth, int bufHeight) {
576

    
577
                Point2D p1 = new Point2D.Double(dWorldTLX, dWorldTLY);
578
                Point2D p2 = new Point2D.Double(dWorldBRX, dWorldBRY);
579

    
580
                Point2D tl = worldToRaster(new Point2D.Double(p1.getX(), p1.getY()));
581
                Point2D br = worldToRaster(new Point2D.Double(p2.getX(), p2.getY()));
582
                
583
                double wPx = (bufWidth / Math.abs(br.getX() - tl.getX()));
584
                double hPx = (bufHeight / Math.abs(br.getY() - tl.getY()));
585
                
586
                int x = (int)((tl.getX() > br.getX()) ? Math.floor(br.getX()) : Math.floor(tl.getX()));
587
                int y = (int)((tl.getY() > br.getY()) ? Math.floor(br.getY()) : Math.floor(tl.getY()));
588
                
589
                double a = (tl.getX() > br.getX()) ? (Math.abs(br.getX() - x)) : (Math.abs(tl.getX() - x));
590
                double b = (tl.getY() > br.getY()) ? (Math.abs(br.getY() - y)) : (Math.abs(tl.getY() - y)); 
591

    
592
                                double stpX = (int)((a * bufWidth) / Math.abs(br.getX() - tl.getX()));
593
                double stpY = (int)((b * bufHeight) / Math.abs(br.getY() - tl.getY()));
594
                
595
                return new double[]{stpX, stpY, wPx, hPx};
596
        }
597
        
598
        /**
599
         * Lee una l?nea completa del raster y devuelve un array del tipo correcto. Esta funci?n es util
600
         * para una lectura rapida de todo el fichero sin necesidad de asignar vista. 
601
         * @param nLine N?mero de l?nea a leer
602
         * @param band Banda requerida
603
         * @return Object que es un array unidimendional del tipo de datos del raster
604
         * @throws InvalidSetViewException
605
         * @throws FileNotOpenException
606
         * @throws RasterDriverException
607
         * @throws InterruptedException 
608
         */
609
        abstract public Object readCompleteLine(int line, int band)throws InvalidSetViewException, FileNotOpenException, RasterDriverException, InterruptedException;
610
        
611
        /**
612
         * Lee un bloque completo de datos del raster y devuelve un array tridimensional del tipo correcto. Esta funci?n es util
613
         * para una lectura rapida de todo el fichero sin necesidad de asignar vista. 
614
         * @param pos Posici?n donde se empieza  a leer
615
         * @param blockHeight Altura m?xima del bloque leido
616
         * @return Object que es un array tridimendional del tipo de datos del raster. (Bandas X Filas X Columnas)
617
         * @throws InvalidSetViewException
618
         * @throws FileNotOpenException
619
         * @throws RasterDriverException
620
         */
621
        abstract public Object readBlock(int pos, int blockHeight)
622
                throws InvalidSetViewException, FileNotOpenException, RasterDriverException, InterruptedException;
623
        
624
        /**
625
         * Convierte un punto desde coordenadas pixel a coordenadas del mundo.
626
         * @param pt Punto a transformar
627
         * @return punto transformado en coordenadas del mundo
628
         */
629
        public Point2D rasterToWorld(Point2D pt) {
630
                Point2D p = new Point2D.Double();
631
                externalTransformation.transform(pt, p);
632
                return p;
633
        }
634
        
635
        /**
636
         * Convierte un punto desde del mundo a coordenadas pixel.
637
         * @param pt Punto a transformar
638
         * @return punto transformado en coordenadas pixel
639
         */
640
        public Point2D worldToRaster(Point2D pt) {
641
                Point2D p = new Point2D.Double();
642
                try {
643
                        externalTransformation.inverseTransform(pt, p);
644
                } catch (NoninvertibleTransformException e) {
645
                        return pt;
646
                }
647
                return p;
648
        }
649
        
650
        /**
651
         * Calcula el extent en coordenadas del mundo real
652
         * @return Extent
653
         */
654
        public Extent getExtent() {
655
                return new Extent(        rasterToWorld(new Point2D.Double(0, 0)), 
656
                                                        rasterToWorld(new Point2D.Double(getWidth(), getHeight())),
657
                                                        rasterToWorld(new Point2D.Double(getWidth(), 0)),
658
                                                        rasterToWorld(new Point2D.Double(0, getHeight())));
659
        }
660
        
661
        /**
662
         * Calcula el extent en coordenadas del mundo real sin rotaci?n. Solo coordenadas y tama?o de pixel
663
         * @return Extent
664
         */
665
        public Extent getExtentWithoutRot() {
666
                AffineTransform at = new AffineTransform(        externalTransformation.getScaleX(), 0, 
667
                                                                                                        0, externalTransformation.getScaleY(), 
668
                                                                                                        externalTransformation.getTranslateX(), externalTransformation.getTranslateY());
669
                Point2D p1 = new Point2D.Double(0, 0);
670
                Point2D p2 = new Point2D.Double(getWidth(), getHeight());
671
                at.transform(p1, p1);
672
                at.transform(p2, p2);
673
                return new Extent(p1, p2);
674
        }
675
        
676
        /**
677
         * ASigna el par?metro de inicializaci?n del driver.
678
         */
679
        public void setParam(Object param) {
680
                this.param = param;
681
        }
682
        
683
        /**
684
         * Obtiene las estadisticas asociadas al fichero
685
         * @return Objeto con las estadisticas
686
         */
687
        public DatasetStatistics getStatistics() {
688
                return stats;
689
        }
690
        
691
        /**
692
         * Obtiene el n?mero de overviews de una banda
693
         * @return
694
         */
695
        abstract public int getOverviewCount(int band) throws BandAccessException, RasterDriverException;
696

    
697
        /**
698
         * Obtiene el ancho de una overview de una banda
699
         * @return
700
         */
701
        abstract public int getOverviewWidth(int band, int overview) throws BandAccessException, RasterDriverException;
702

    
703
        /**
704
         * Obtiene el alto de una overview de una banda
705
         * @return
706
         */
707
        abstract public int getOverviewHeight(int band, int overview) throws BandAccessException, RasterDriverException;
708
        
709
        /**
710
         * Informa de si el dataset soporta overviews o no.
711
         * @return true si soporta overviews y false si no las soporta.
712
         */
713
        abstract public boolean overviewsSupport();
714
        
715
        /**
716
         * Obtiene el histograma asociado al dataset. Este puede ser obtenido 
717
         * completo o seg?n una lista de clases pasada.
718
         * 
719
         * @return Histograma asociado al dataset.
720
         */
721
        public DatasetHistogram getHistogram() {
722
                if (histogram == null)
723
                        histogram = new DatasetHistogram(this);
724
                return histogram;
725
        }
726
        
727
        /**
728
         * Pone a cero el porcentaje de progreso del proceso de calculo de histograma
729
         */
730
        public void resetPercent() {
731
                if (histogram != null)
732
                        histogram.resetPercent();
733
        }
734

    
735
        /**
736
         * Obtiene el porcentaje de proceso en la construcci?n del histograma,
737
         * @return porcentaje de progreso
738
         */
739
        public int getPercent() {
740
                if (histogram != null) 
741
                        return histogram.getPercent();
742
                return 0;
743
        }
744

    
745
        /**
746
         * Obtiene el gestor de ficheros RMF
747
         * @return RmfBloksManager
748
         */
749
        public RmfBlocksManager getRmfBlocksManager() {
750
                if (rmfBlocksManager == null) {
751
                        String fileRMF = RasterUtilities.getNameWithoutExtension(getFName()) + ".rmf";
752
                        rmfBlocksManager = new RmfBlocksManager(fileRMF);
753
                }
754
                return rmfBlocksManager;
755
        }
756
                
757
        /**
758
         * Informa de si el punto en coordenadas del mundo real pasado por par?metro cae dentro del 
759
         * raster o fuera. Para este calculo cogeremos el punto a averiguar si est? dentro del raster 
760
         * y le aplicaremos la transformaci?n inversa de la transformaci?n af?n aplicada. Una vez hecho 
761
         * esto ya se puede comprobar si est? dentro de los l?mites del extent del raster.
762
         * @param p Punto a comprobar en coordenadas reales
763
         * @return true si el punto est? dentro y false si est? fuera.
764
         */
765
        public boolean isInside(Point2D p){
766
                //Realizamos los calculos solo si el punto est? dentro del extent de la imagen rotada, as? nos ahorramos los calculos
767
                //cuando el puntero est? fuera
768
                
769
                Point2D pt = new Point2D.Double();
770
                try {
771
                        
772
                        getAffineTransform().inverseTransform(p, pt);
773
                        if(        pt.getX() >= 0 && pt.getX() < getWidth() &&
774
                                        pt.getY() >= 0 && pt.getY() < getHeight())
775
                                return true;
776
                } catch (NoninvertibleTransformException e) {
777
                        return false;
778
                }
779
                
780
                return false;
781
        }
782
        
783
        /**
784
         * Consulta de si un raster tiene rotaci?n o no.
785
         * @return true si tiene rotaci?n y false si no la tiene.
786
         */
787
        public boolean isRotated() {
788
                if(externalTransformation.getShearX() != 0 || externalTransformation.getShearY() != 0)
789
                        return true;
790
                return false;
791
        }
792

    
793
        /**
794
         * Devuelve si el RasterDataSet tiene el valor noData activo
795
         * @return the noDataEnabled
796
         */
797
        public boolean isNoDataEnabled() {
798
                return noDataEnabled;
799
        }
800

    
801
        /**
802
         * Define si el RasterDataSet tiene el valor noData activo 
803
         * @param noDataEnabled the noDataEnabled to set
804
         */
805
        public void setNoDataEnabled(boolean noDataEnabled) {
806
                this.noDataEnabled = noDataEnabled;
807
        }
808

    
809
        /**
810
         * Devuelve si el Dataset es reproyectable 
811
         * @return
812
         */
813
        public boolean isReproyectable() {
814
                return false;
815
        }
816
        
817
        public String getWktProjection() {
818
                return wktProjection;
819
        }
820

    
821
        /**
822
         * Devuelve un serializador que tenga un constructor con la clase pasada por parametro
823
         * @throws RmfSerializerException 
824
         */
825
        static private Class getSerializerClass(Class class1) throws RmfSerializerException {
826
                ExtensionPoint extensionPoint = ExtensionPoint.getExtensionPoint("Serializer");
827
                Iterator iterator = extensionPoint.getIterator();
828
                while (iterator.hasNext()) {
829
                        Entry entry = (Entry) iterator.next();
830
                        if (entry != null) {
831
                                Class[] args = { class1 };
832
                                Class clase = (Class) entry.getValue();
833
                                try {
834
                                        clase.getConstructor(args);
835
                                        return clase;
836
                                } catch (Exception e) {
837
                                        // Si no encuentra un constructor para esta clase, seguir? buscando en los dem?s elementos
838
                                }
839
                        }
840
                }
841
                throw new RmfSerializerException("No se ha encontrado la clase para el serializador");
842
        }
843
        
844
        /**
845
         * Construye un serializador que soporte la clase class1. El constructor se invoca
846
         * con el parametro value.
847
         * 
848
         * @param class1
849
         * @param value
850
         * @return
851
         * @throws RmfSerializerException 
852
         */
853
        static private ClassSerializer getSerializerObject(Class class1, Object value) throws RmfSerializerException {
854
                try {
855
                        Class[] args = { class1 };
856
                        Constructor constructor = getSerializerClass(class1).getConstructor(args);
857
                        Object[] args2 = { value };
858
                        return (ClassSerializer) constructor.newInstance(args2);
859
                } catch (Exception e) {
860
                        throw new RmfSerializerException("No se ha podido crear el serializador para el Rmf", e);
861
                }
862
        }
863

    
864
        /**
865
         * Guarda en el RMF que trata el BlocksManager el valor value usando el serializador que soporta
866
         * la clase class1.
867
         *  
868
         * @param blocksManager
869
         * @param class1
870
         * @param value
871
         * @throws RmfSerializerException 
872
         */
873
        static private void saveObjectToRmfFile(RmfBlocksManager blocksManager, Class class1, Object value) throws RmfSerializerException {
874
                ClassSerializer serializerObject = getSerializerObject(class1, value);
875

    
876
                if (serializerObject == null) 
877
                        throw new RmfSerializerException("No se ha podido encontrar el serializador para el Rmf");
878

    
879
                if (!blocksManager.checkRmf())
880
                        throw new RmfSerializerException("Error al comprobar el fichero Rmf");
881
                        
882
                blocksManager.addClient(serializerObject);
883
                try {
884
                        blocksManager.write(true);
885
                } catch (IOException e) {
886
                        throw new RmfSerializerException("Error al escribir el fichero Rmf", e);
887
                }
888
                blocksManager.removeAllClients();
889
        }
890

    
891
        /**
892
         * Guarda en el fichero file (en formato RMF) el objecto value usando el serializador que trata
893
         * las clases class1.
894
         * 
895
         * Si el fichero RMF no existe se crea. Ha de ser un RMF de formato valido.
896
         * 
897
         * @param file
898
         * @param class1
899
         * @param value
900
         * @throws RmfSerializerException 
901
         */
902
        static public void saveObjectToRmfFile(String file, Class class1, Object value) throws RmfSerializerException {
903
                String fileRMF = RasterUtilities.getNameWithoutExtension(file) + ".rmf";
904
                RmfBlocksManager blocksManager = new RmfBlocksManager(fileRMF);
905
                saveObjectToRmfFile(blocksManager, class1, value);
906
        }
907

    
908
        /**
909
         * Guarda en el fichero file (en formato RMF) el objecto value usando el serializador que trata
910
         * la misma clase que el objeto value.
911
         * 
912
         * Si el fichero RMF no existe se crea. Ha de ser un RMF de formato valido.
913
         * 
914
         * @param file
915
         * @param value
916
         * @throws RmfSerializerException 
917
         */
918
        static public void saveObjectToRmfFile(String file, Object value) throws RmfSerializerException {
919
                saveObjectToRmfFile(file, value.getClass(), value);
920
        }
921
        
922
        /**
923
         * Guarda en el RMF el objecto actual en caso de que exista un serializador para el.
924
         * El tipo del objeto se especifica en el parametro class1.
925
         * Esto nos puede permitir poder poner a null un valor y encontrar su serializador.
926
         * @param value
927
         * @throws RmfSerializerException 
928
         */
929
        public void saveObjectToRmf(Class class1, Object value) throws RmfSerializerException {
930
                saveObjectToRmfFile(getRmfBlocksManager(), class1, value);
931
        }
932
        
933
        /**
934
         * Carga un objecto desde un serializador del tipo class1. Usa value para iniciar dicho
935
         * serializador
936
         *  
937
         * @param class1
938
         * @param value
939
         * @return
940
         * @throws RmfSerializerException 
941
         */
942
        static private Object loadObjectFromRmfFile(RmfBlocksManager blocksManager, Class class1, Object value) throws RmfSerializerException {
943
                ClassSerializer serializerObject = getSerializerObject(class1, value);
944

    
945
                if (serializerObject == null) 
946
                        throw new RmfSerializerException("No se ha podido encontrar el serializador para el Rmf");
947

    
948
                if (!blocksManager.checkRmf())
949
                        throw new RmfSerializerException("Error al comprobar el fichero Rmf");
950

    
951
                blocksManager.addClient(serializerObject);
952
                try {
953
                        blocksManager.read(null);
954
                } catch (ParsingException e) {
955
                        throw new RmfSerializerException("Error al leer el fichero Rmf", e);
956
                }
957
                blocksManager.removeAllClients();
958

    
959
                return serializerObject.getResult();
960
        }
961

    
962
        /**
963
         * Carga un objecto del fichero RMF del dataset
964
         * @param class1
965
         * @param value
966
         * @return
967
         * @throws RmfSerializerException 
968
         */
969
        public Object loadObjectFromRmf(Class class1, Object value) throws RmfSerializerException {
970
                return loadObjectFromRmfFile(getRmfBlocksManager(), class1, value);
971
        }
972
        
973
        /**
974
         * Carga un objeto del fichero RMF especificado por parametro
975
         * @param file
976
         * @param class1
977
         * @param value
978
         * @return
979
         * @throws RmfSerializerException 
980
         */
981
        static public Object loadObjectFromRmfFile(String file, Class class1, Object value) throws RmfSerializerException {
982
                String fileRMF = RasterUtilities.getNameWithoutExtension(file) + ".rmf";
983
                RmfBlocksManager blocksManager = new RmfBlocksManager(fileRMF);
984
                return loadObjectFromRmfFile(blocksManager, class1, value);
985
        }
986
        
987
        /**
988
         * Guarda en el RMF el objecto actual en caso de que exista un serializador para el
989
         * @param value
990
         * @throws RmfSerializerException 
991
         */
992
        public void saveObjectToRmf(Object value) throws RmfSerializerException {
993
                saveObjectToRmf(value.getClass(), value);
994
        }
995

    
996
        /**
997
         * Carga un objecto desde un serializador usando el tipo del mismo objeto pasado por parametro.
998
         * Usa value para iniciar dicho serializador
999
         * @param value
1000
         * @return
1001
         * @throws RmfSerializerException 
1002
         */
1003
        public Object loadObjectFromRmf(Object value) throws RmfSerializerException {
1004
                return loadObjectFromRmf(value.getClass(), value);
1005
        }
1006
}