Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libRaster / src / org / gvsig / raster / util / RasterUtilities.java @ 30541

History | View | Annotate | Download (32.8 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2008 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.util;
20

    
21
import java.awt.Dimension;
22
import java.awt.geom.AffineTransform;
23
import java.awt.geom.Dimension2D;
24
import java.awt.geom.NoninvertibleTransformException;
25
import java.awt.geom.Point2D;
26
import java.awt.geom.Rectangle2D;
27
import java.io.BufferedOutputStream;
28
import java.io.BufferedReader;
29
import java.io.DataOutputStream;
30
import java.io.File;
31
import java.io.FileInputStream;
32
import java.io.FileNotFoundException;
33
import java.io.FileOutputStream;
34
import java.io.FileReader;
35
import java.io.IOException;
36
import java.io.InputStream;
37
import java.io.OutputStream;
38
import java.text.NumberFormat;
39

    
40
import org.gvsig.raster.buffer.RasterBuffer;
41
import org.gvsig.raster.dataset.io.rmf.RmfBlocksManager;
42
import org.gvsig.raster.dataset.serializer.GeoInfoRmfSerializer;
43
import org.gvsig.raster.datastruct.Extent;
44

    
45
import es.gva.cit.jgdal.Gdal;
46
/**
47
 * @author Nacho Brodin (nachobrodin@gmail.com)
48
 */
49
public class RasterUtilities {        
50
        public static final int MAX_BYTE_BIT_VALUE  = 255;
51
        public static final int MAX_SHORT_BIT_VALUE = 65535;
52

    
53
        // ---------------------------------------------------------------
54
        // TIPOS DE DATOS
55

    
56
        /**
57
         * Conversi?n de los tipos de datos de gdal a los tipos de datos de RasterBuf
58
         * @param gdalType Tipo de dato de gdal
59
         * @return Tipo de dato de RasterBuf
60
         */
61
        public static int getRasterBufTypeFromGdalType(int gdalType) {
62
                switch (gdalType) {
63
                        case 1:// Eight bit unsigned integer GDT_Byte = 1
64
                                return RasterBuffer.TYPE_BYTE;
65

    
66
                        case 3:// Sixteen bit signed integer GDT_Int16 = 3,
67
                                return RasterBuffer.TYPE_SHORT;
68

    
69
                        case 2:// Sixteen bit unsigned integer GDT_UInt16 = 2
70
                                //return RasterBuffer.TYPE_USHORT;
71
                                return RasterBuffer.TYPE_SHORT; //Apa?o para usar los tipos de datos que soportamos
72
                                
73
                        case 5:// Thirty two bit signed integer GDT_Int32 = 5
74
                                return RasterBuffer.TYPE_INT;
75

    
76
                        case 6:// Thirty two bit floating point GDT_Float32 = 6
77
                                return RasterBuffer.TYPE_FLOAT;
78

    
79
                        case 7:// Sixty four bit floating point GDT_Float64 = 7
80
                                return RasterBuffer.TYPE_DOUBLE;
81

    
82
                                // TODO:Estos tipos de datos no podemos gestionarlos. Habria que definir
83
                                // el tipo complejo y usar el tipo long que de momento no se gasta.
84
                        case 4:// Thirty two bit unsigned integer GDT_UInt32 = 4,
85
                                return RasterBuffer.TYPE_INT;
86
                                //return RasterBuffer.TYPE_UNDEFINED; // Deberia devolver un Long
87

    
88
                        case 8:// Complex Int16 GDT_CInt16 = 8
89
                        case 9:// Complex Int32 GDT_CInt32 = 9
90
                        case 10:// Complex Float32 GDT_CFloat32 = 10
91
                        case 11:// Complex Float64 GDT_CFloat64 = 11
92
                                return RasterBuffer.TYPE_UNDEFINED;
93
                }
94
                return RasterBuffer.TYPE_UNDEFINED;
95
        }
96

    
97
        /**
98
         * Conversi?n de los tipos de datos de RasterBuf en los de gdal.
99
         * @param rasterBufType Tipo de dato de RasterBuf
100
         * @return Tipo de dato de Gdal
101
         */
102
        public static int getGdalTypeFromRasterBufType(int rasterBufType) {
103
                switch (rasterBufType) {
104
                        case RasterBuffer.TYPE_BYTE: return Gdal.GDT_Byte;
105
                        case RasterBuffer.TYPE_USHORT: return Gdal.GDT_UInt16;
106
                        case RasterBuffer.TYPE_SHORT: return Gdal.GDT_Int16;
107
                        case RasterBuffer.TYPE_INT: return Gdal.GDT_Int32;
108
                        case RasterBuffer.TYPE_FLOAT: return Gdal.GDT_Float32;
109
                        case RasterBuffer.TYPE_DOUBLE: return Gdal.GDT_Float64;
110
                        case RasterBuffer.TYPE_UNDEFINED: return Gdal.GDT_Unknown;
111
                        case RasterBuffer.TYPE_IMAGE: return Gdal.GDT_Byte;
112
                }
113
                return Gdal.GDT_Unknown;
114
        }
115

    
116
        /**
117
         * Conversi?n de los tipos de datos de MrSID a los tipos de datos de RasterBuf
118
         * @param mrsidType Tipo de dato de MrSID
119
         * @return Tipo de dato de RasterBuf
120
         */
121
        public static int getRasterBufTypeFromMrSIDType(int mrsidType){
122
                switch (mrsidType) {
123
                        case 0: return RasterBuffer.TYPE_UNDEFINED;// INVALID
124
                        case 1:// UINT8
125
                        case 2: return RasterBuffer.TYPE_BYTE;// SINT8
126
                        case 3:// UINT16
127
                        case 4: return RasterBuffer.TYPE_SHORT;// SINT16
128
                        case 5:// UINT32
129
                        case 6: return RasterBuffer.TYPE_INT;// SINT32
130
                        case 7: return RasterBuffer.TYPE_FLOAT;// FLOAT32
131
                        case 8: return RasterBuffer.TYPE_DOUBLE;// FLOAT64
132
                }
133
                return RasterBuffer.TYPE_UNDEFINED;
134
        }
135

    
136
        /**
137
         * Obtiene el n?mero de bytes que ocupa un tipo de dato concreto. Los tipos de
138
         * datos son los utilizados en RasterBuffer
139
         * @param rasterBufType Tipo de dato del que se solicita el n?mero de bytes ocupados
140
         * @return
141
         */
142
        public static int getBytesFromRasterBufType(int rasterBufType) {
143
                switch (rasterBufType) {
144
                        case RasterBuffer.TYPE_BYTE: return 1;
145
                        case RasterBuffer.TYPE_USHORT:
146
                        case RasterBuffer.TYPE_SHORT: return 2;
147
                        case RasterBuffer.TYPE_INT:
148
                        case RasterBuffer.TYPE_FLOAT:
149
                        case RasterBuffer.TYPE_IMAGE: return 4;
150
                        case RasterBuffer.TYPE_DOUBLE: return 8;
151
                }
152
                return 0; // TYPE_UNDEFINED
153
        }
154

    
155
        /**
156
         * Devuelve el tama?o en bytes de una regi?n de un raster en funci?n de su tama?o, 
157
         * n?mero de bandas y tipo de dato.
158
         * @param width
159
         * @param height
160
         * @param rasterType
161
         * @param nBands
162
         * @return
163
         */
164
        public static long getBytesFromRaster(int width, int height, int rasterType, int nBands){
165
                int typeSize = getBytesFromRasterBufType(rasterType);
166
                return (long)width * (long)height * (long)nBands * (long)typeSize;
167
        }
168
        
169
        
170
        /**
171
         * Convierte un tipo de dato a cadena
172
         * @param type Tipo de dato
173
         * @return cadena que representa el tipo de dato
174
         */
175
        public static String typesToString(int type) {
176
                switch (type) {
177
                        case RasterBuffer.TYPE_IMAGE:
178
                                return new String("Image");
179

    
180
                        case RasterBuffer.TYPE_BYTE:
181
                                return new String("Byte");
182

    
183
                        case RasterBuffer.TYPE_DOUBLE:
184
                                return new String("Double");
185

    
186
                        case RasterBuffer.TYPE_FLOAT:
187
                                return new String("Float");
188

    
189
                        case RasterBuffer.TYPE_INT:
190
                                return new String("Integer");
191

    
192
                        case RasterBuffer.TYPE_USHORT:
193
                        case RasterBuffer.TYPE_SHORT:
194
                                return new String("Short");
195
                        case RasterBuffer.TYPE_UNDEFINED:
196
                                return new String("Undefined");
197
                }
198
                return null;
199
        }
200

    
201
        /**
202
         * Parseo de las proyecciones que genera gdal para meter espaciados y saltos
203
         * de l?nea HTML
204
         * @param proj Proyecci?n
205
         * @return Cadena con la proyecci?n parseada
206
         */
207
        public static String parserGdalProj(String proj) {
208
                if (proj == null)
209
                        return "";
210
                String[] list = proj.split(",");
211
                int level = 0;
212
                for (int i = 0; i < list.length; i++) {
213
                        if (list[i].indexOf("[") >= 0) {
214
                                level++;
215
                                String spaces = "";
216
                                for (int j = 0; j < level; j++)
217
                                        spaces += "&nbsp;&nbsp;";
218
                                list[i] = spaces + list[i];
219
                        }
220
                        if (list[i].indexOf("]]") >= 0)
221
                                level = level - 2;
222
                        else
223
                                if (list[i].indexOf("]") >= 0)
224
                                        level--;
225
                }
226
                StringBuffer str = new StringBuffer();
227
                for (int i = 0; i < list.length; i++) {
228
                        if (i < list.length) {
229
                                if (i + 1 < list.length && list[i + 1].indexOf("[") >= 0)
230
                                        str.append(list[i] + ",<BR>");
231
                                else
232
                                        str.append(list[i] + ",");
233
                        }
234
                }
235
                return str.toString();
236
        }
237

    
238
        // ---------------------------------------------------------------
239
        // ESPACIO DE COLOR
240

    
241
        /**
242
         * Descompone un entero que representa un ARGB en sus 4 valores byte Obtiene
243
         * un array de 4 elementos donde el elemento 0 es el Rojo, el 1 es el verde,
244
         * el 2 el azul y el 3 el alpha.
245
         * @param rgb Entero con el valor ARGB a descomponer;
246
         * @return Array de cuatro elementos
247
         */
248
        public static byte[] getARGBFromIntToByteArray(int rgb) {
249
                byte[] b = new byte[4];
250
                b[0] = (byte) ((rgb & 0x00ff0000) >> 16);
251
                b[1] = (byte) ((rgb & 0x0000ff00) >> 8);
252
                b[2] = (byte) (rgb & 0x000000ff);
253
                b[3] = (byte) ((rgb & 0xff000000) >> 24);
254
                return b;
255
        }
256

    
257
        /**
258
         * Descompone un entero que representa un ARGB en sus 4 valores byte Obtiene
259
         * un array de 4 elementos donde el elemento 0 es el Rojo, el 1 es el verde,
260
         * el 2 el azul y el 3 el alpha.
261
         * @param rgb Entero con el valor ARGB a descomponer;
262
         * @return
263
         */
264
        public static int[] getARGBFromIntToIntArray(int rgb) {
265
                int[] i = new int[4];
266
                i[0] = (((rgb & 0x00ff0000) >> 16) & 0xff);
267
                i[1] = (((rgb & 0x0000ff00) >> 8) & 0xff);
268
                i[2] = ((rgb & 0x000000ff) & 0xff);
269
                i[3] = (((rgb & 0xff000000) >> 24) & 0xff);
270
                return i;
271
        }
272

    
273
        /**
274
         * Obtiene un entero con los valores ARGB pasados por par?metro
275
         * @param a Valor de alpha
276
         * @param r Valor del rojo
277
         * @param g Valor del verde
278
         * @param b Valor del azul
279
         * @return entero con la mezcla de valores
280
         */
281
        public static int getIntFromARGB(int a, int r, int g, int b) {
282
                return (((a & 0xff) << 24) + ((r & 0xff) << 16) + ((g & 0xff) << 8) + (b & 0xff));
283
        }
284

    
285
        // ---------------------------------------------------------------
286
        // CONVERSI?N DE COORDENADAS
287

    
288
        /**
289
         * Convierte una ventana en coordenadas del mundo real a sus coordenadas
290
         * relativas en pixels teniendo en cuenta que la coordenada superior izquierda
291
         * es 0,0 y la inferior derecha es maxX y maY
292
         * @param extent Extent de la imagen original
293
         * @param widthPx Ancho en pixeles de la imagen original
294
         * @param heightPx Alto en pixeles de la imagen original
295
         * @param window Ventana en coordenadas reales a transportar a coordenadas pixel
296
         * @return Ventana en coordenadas pixel
297
         */
298
        public static Rectangle2D getPxRectFromMapRect(Rectangle2D extent, double widthPx, double heightPx, Rectangle2D window) {
299
                double widthWC = extent.getWidth();
300
                double heightWC = extent.getHeight();
301

    
302
                double wWindowWC = Math.abs(window.getMaxX() - window.getMinX());
303
                double hWindowWC = Math.abs(window.getMaxY() - window.getMinY());
304

    
305
                double wWindowPx = ((wWindowWC * widthPx) / widthWC);
306
                double hWindowPx = ((hWindowWC * heightPx) / heightWC);
307

    
308
                double initDistanceX = Math.abs(window.getMinX() - extent.getMinX());
309
                double initDistanceY = Math.abs(window.getMaxY() - extent.getMaxY());
310

    
311
                double initPxX = ((initDistanceX * widthPx) / widthWC);
312
                double initPxY = ((initDistanceY * heightPx) / heightWC);
313

    
314
                Rectangle2D pxRec = new Rectangle2D.Double(initPxX, initPxY, wWindowPx, hWindowPx);
315
                return pxRec;
316
        }
317

    
318
        /**
319
         * Convierte una ventana en coordenadas del mundo real a sus coordenadas
320
         * relativas en pixels teniendo en cuenta que la coordenada superior izquierda
321
         * es 0,0 y la inferior derecha es maxX y maY
322
         * @param extent Extent de la imagen original
323
         * @param widthPx Ancho en pixeles de la imagen original
324
         * @param heightPx Alto en pixeles de la imagen original
325
         * @param window Ventana en coordenadas reales a transportar a coordenadas pixel
326
         * @return Ventana en coordenadas pixel
327
         */
328
        public static Rectangle2D getMapRectFromPxRect(Rectangle2D extent, double widthPx, double heightPx, Rectangle2D pxWindow) {
329
                double wWindowWC = ((pxWindow.getWidth() * extent.getWidth()) / widthPx);
330
                double hWindowWC = ((pxWindow.getHeight() * extent.getHeight()) / heightPx);
331

    
332
                double initWCX = extent.getMinX() + ((pxWindow.getMinX() * extent.getWidth()) / widthPx);
333
                double initWCY = extent.getMaxY() - ((pxWindow.getMinY() * extent.getHeight()) / heightPx);
334

    
335
                Rectangle2D mapRec = new Rectangle2D.Double(initWCX, initWCY - hWindowWC, wWindowWC, hWindowWC);
336
                return mapRec;
337
        }
338

    
339
        /**
340
         * Convierte un punto en coordenadas del mundo a coordenadas pixel
341
         * @param p Punto a convertir
342
         * @param ext Extent completo de la imagen
343
         * @return Punto en coordenadas pixel
344
         */
345
        public static Point2D worldPointToRaster(Point2D p, Extent ext, int pxWidth, int pxHeight) {
346
                double x = p.getX() - ext.getMin().getX();
347
                double y = p.getY() - ext.getMin().getY();
348
                int pxX = (int) ((x * pxWidth) / ext.width());
349
                int pxY = (int) ((y * pxHeight) / ext.height());
350
                return new Point2D.Double(pxX, pxY);
351
        }
352

    
353
        /**
354
         * Ajusta la extensi?n pasada por par?metro a los valores m?ximos y m?nimos de
355
         * la imagen. Esto sirve para que la petici?n al driver nunca sobrepase los
356
         * l?mites de la imagen tratada aunque la vista donde se dibuje sea de mayor
357
         * tama?o.
358
         * @param imgExt Extent completo de la vista donde se va a dibujar.
359
         * @param extToAdj Extent a ajustar.
360
         * @return adjustedExtent Extent ajustado a m?ximos y m?nimos
361
         */
362
        public static Extent calculateAdjustedView(Extent extToAdj, Extent imgExt) {
363
                double vx = extToAdj.minX();
364
                double vy = extToAdj.minY();
365
                double vx2 = extToAdj.maxX();
366
                double vy2 = extToAdj.maxY();
367

    
368
                if (extToAdj.minX() < imgExt.minX())
369
                        vx = imgExt.minX();
370

    
371
                if (extToAdj.minY() < imgExt.minY())
372
                        vy = imgExt.minY();
373

    
374
                if (extToAdj.maxX() > imgExt.maxX())
375
                        vx2 = imgExt.maxX();
376

    
377
                if (extToAdj.maxY() > imgExt.maxY())
378
                        vy2 = imgExt.maxY();
379

    
380
                return new Extent(vx, vy, vx2, vy2);
381
        }
382

    
383
        /**
384
         * Ajusta la extensi?n pasada por par?metro a los valores m?ximos y m?nimos de
385
         * la imagen. Esto sirve para que la petici?n al driver nunca sobrepase los
386
         * l?mites de la imagen tratada aunque la vista donde se dibuje sea de mayor
387
         * tama?o. Este m?todo tiene en cuenta la rotaci?n aplicada al raster por lo
388
         * que no ajustamos a un extent sino a una matriz de transformaci?n. Esta
389
         * tiene los par?metros de traslaci?n, rotaci?n y escalado del raster destino.
390
         * Esta matriz transforma coordenadas pixel a real y viceversa.
391
         * @param imgExt Extent completo de la vista donde se va a dibujar.
392
         * @param AffineTransform Matriz de transformaci?n del raster destino
393
         * @return adjustedExtent Extent ajustado a m?ximos y m?nimos
394
         */
395
        public static Extent calculateAdjustedView(Extent extToAdj, AffineTransform at, Dimension2D dim) { 
396
                        // Obtenemos los cuatro puntos de la petici?n de origen
397
                Point2D ul = new Point2D.Double(extToAdj.getULX(), extToAdj.getULY());
398
                Point2D lr = new Point2D.Double(extToAdj.getLRX(), extToAdj.getLRY());
399

    
400
                // Los convertimos a coordenadas pixel con la matriz de transformaci?n
401
                try {
402
                        at.inverseTransform(ul, ul);
403
                        at.inverseTransform(lr, lr);
404
                } catch (NoninvertibleTransformException e) {
405
                        return extToAdj;
406
                }
407

    
408
                // Ajustamos a la dimensi?n del raster en pixeles
409
                if (ul.getX() < 0)
410
                        ul.setLocation(0, ul.getY());
411
                if (ul.getX() >= dim.getWidth())
412
                        ul.setLocation(dim.getWidth(), ul.getY());
413
                if (ul.getY() < 0)
414
                        ul.setLocation(ul.getX(), 0);
415
                if (ul.getY() >= dim.getHeight())
416
                        ul.setLocation(ul.getX(), dim.getHeight());
417

    
418
                if (lr.getX() < 0)
419
                        lr.setLocation(0, lr.getY());
420
                if (lr.getX() >= dim.getWidth())
421
                        lr.setLocation(dim.getWidth(), lr.getY());
422
                if (lr.getY() < 0)
423
                        lr.setLocation(lr.getX(), 0);
424
                if (lr.getY() >= dim.getHeight())
425
                        lr.setLocation(lr.getX(), dim.getHeight());
426

    
427
                // Lo convertimos a coordenadas reales nuevamente
428
                at.transform(ul, ul);
429
                at.transform(lr, lr);
430
                return new Extent(ul, lr);
431
        }
432

    
433
        /**
434
         * Comprueba si un Extent tiene alguna parte en com?n con otro Extent dado, es
435
         * decir, si ambos extents intersectan en alguna zona. La llamada tiene en
436
         * cuenta alguna transformaci?n aplicada al Extent.
437
         * @param e1
438
         * @param e2
439
         * @return true si intersectan y false si no lo hacen
440
         */
441
        public static boolean intersects(Extent e1, Extent e2, AffineTransform at) throws NoninvertibleTransformException {
442
                Point2D ulPxE1 = new Point2D.Double();
443
                Point2D lrPxE1 = new Point2D.Double();
444
                Point2D ulPxE2 = new Point2D.Double();
445
                Point2D lrPxE2 = new Point2D.Double();
446

    
447
                at.inverseTransform(new Point2D.Double(e1.getULX(), e1.getULY()), ulPxE1);
448
                at.inverseTransform(new Point2D.Double(e1.getLRX(), e1.getLRY()), lrPxE1);
449
                at.inverseTransform(new Point2D.Double(e2.getULX(), e2.getULY()), ulPxE2);
450
                at.inverseTransform(new Point2D.Double(e2.getLRX(), e2.getLRY()), lrPxE2);
451
                
452
                        if (((ulPxE1.getX() <= lrPxE2.getX()) && (lrPxE1.getX() >= lrPxE2.getX()) ||
453
                                         (ulPxE1.getX() <= ulPxE2.getX()) && (lrPxE1.getX() >= ulPxE2.getX()) ||
454
                                         (ulPxE1.getX() >= ulPxE2.getX()) && (lrPxE1.getX() <= lrPxE2.getX())) &&
455
                                        ((ulPxE1.getY() <= lrPxE2.getY()) && (lrPxE1.getY() >= lrPxE2.getY()) ||
456
                                         (ulPxE1.getY() <= ulPxE2.getY()) && (lrPxE1.getY() >= ulPxE2.getY()) ||
457
                                         (ulPxE1.getY() >= ulPxE2.getY()) && (lrPxE1.getY() <= lrPxE2.getY())))
458
                        return true;
459
                return false;
460
        }
461

    
462
        /**
463
         * Comprueba si un punto est? contenido dentro de un extend y devuelve true en
464
         * este caso. Se tiene en cuenta la transformaci?n aplicada al raster.
465
         * @param p1 Punto a comprobar si est? contenido en e1
466
         * @param e1 Extent sobre el que se comprueba si e1 est? dentro el punto
467
         * @return true si p1 est? dentro de e1
468
         */
469
        public static boolean isInside(Point2D p1, Extent e1, AffineTransform at) {
470
                // Convertimos los puntos a coordenadas pixel con la matriz de
471
                // transformaci?n
472
                Point2D p1Px = new Point2D.Double();
473
                Point2D ulPx = new Point2D.Double();
474
                Point2D lrPx = new Point2D.Double();
475
                try {
476
                        at.inverseTransform(p1, p1Px);
477
                        at.inverseTransform(new Point2D.Double(e1.getULX(), e1.getULY()), ulPx);
478
                        at.inverseTransform(new Point2D.Double(e1.getLRX(), e1.getLRY()), lrPx);
479
                } catch (NoninvertibleTransformException e) {
480
                        return false;
481
                }
482

    
483
                // Comprobamos si el punto est? dentro
484
                return ((p1Px.getX() >= ulPx.getX()) && (p1Px.getX() <= lrPx.getX()) &&
485
                                                (p1Px.getY() >= ulPx.getY()) && (p1Px.getY() <= lrPx.getY()));
486
        }
487

    
488
        /**
489
         * Comprueba si un extent est? contenido dentro de otro y devuelve true en
490
         * este caso.
491
         * @param e1 Extent a comprobar si est? contenido en e2
492
         * @param e2 Extent sobre el que se comprueba si e1 est? dentro
493
         * @return true si e1 est? dentro de e1
494
         */
495
        public static boolean isInside(Extent e1, Extent e2) {
496
                return ((e1.getMin().getX() >= e2.getMin().getX()) && (e1.getMin().getY() >= e2.getMin().getY()) && (e1.getMax().getX() <= e2.getMax().getX())) && (e1.getMax().getY() <= e2.getMax().getY());
497
        }
498

    
499
        /**
500
         * Comprueba si un punto est? contenido dentro de un extend y devuelve true en
501
         * este caso.
502
         * @param p1 Punto a comprobar si est? contenido en e1
503
         * @param e1 Extent sobre el que se comprueba si e1 est? dentro el punto
504
         * @return true si p1 est? dentro de e1
505
         */
506
        public static boolean isInside(Point2D p1, Extent e1) {
507
                return ((p1.getX() >= e1.getMin().getX()) && (p1.getX() <= e1.getMax().getX()) && (p1.getY() >= e1.getMin().getY())) && (p1.getY() <= e1.getMax().getY());
508
        }
509

    
510
        /**
511
         * Comprueba si un extent est? fuera de otro extent que tenemos como
512
         * referencia.
513
         * @param e1 Extent a comprobar si est? fuera
514
         * @param ref Extent de referencia
515
         * @return Devuelve true si todo el extent cae fuera de ref y false si no est?
516
         *         fuera.
517
         */
518
        public static boolean isOutside(Extent e1, Extent ref) {
519
                return ((e1.getMin().getX() > ref.getMax().getX()) || (e1.getMin().getY() > ref.getMax().getY()) ||
520
                                                (e1.getMax().getX() < ref.getMin().getX()) || (e1.getMax().getY() < ref.getMin().getY()));
521
        }
522

    
523
        /**
524
         * Compara dos extents y devuelve true si son iguales
525
         * @param e1 Extent a comparar
526
         * @param e2 Extent a comparar
527
         * @return true si los extents pasados por par?metro son iguales y false si no
528
         *         lo son
529
         */
530
        public static boolean compareExtents(Extent e1, Extent e2) {
531
                return ((e1.getMin().getX() == e2.getMin().getX()) && (e1.getMin().getY() == e2.getMin().getY()) &&
532
                                                (e1.getMax().getX() == e2.getMax().getX())) && (e1.getMax().getY() == e2.getMax().getY());
533
        }
534

    
535
        /**
536
         * Calcula los par?metros de un worl file a partir de las esquinas del raster.
537
         * 1. X pixel size A 2. X rotation term D 3. Y rotation term B 4. Y pixel size
538
         * E 5. X coordinate of upper left corner C 6. Y coordinate of upper left
539
         * corner F where the real-world coordinates x',y' can be calculated from the
540
         * image coordinates x,y with the equations x' = Ax + By + C and y' = Dx + Ey +
541
         * F. The signs of the first 4 parameters depend on the orientation of the
542
         * image. In the usual case where north is more or less at the top of the
543
         * image, the X pixel size will be positive and the Y pixel size will be
544
         * negative. For a south-up image, these signs would be reversed. You can
545
         * calculate the World file parameters yourself based on the corner
546
         * coordinates. The X and Y pixel sizes can be determined simply by dividing
547
         * the distance between two adjacent corners by the number of columns or rows
548
         * in the image. The rotation terms are calculated with these equations: # B =
549
         * (A * number_of_columns + C - lower_right_x') / number_of_rows * -1 # D = (E *
550
         * number_of_rows + F - lower_right_y') / number_of_columns * -1
551
         * @param corner (tl, tr, br, bl)
552
         * @return
553
         */
554
        public static double[] cornersToWorldFile(Point2D[] esq, Dimension size) {
555
                double a = 0, b = 0, c = 0, d = 0, e = 0, f = 0;
556
                double x1 = esq[0].getX(), y1 = esq[0].getY();
557
                double x2 = esq[1].getX(), y2 = esq[1].getY();
558
                double x3 = esq[2].getX(), y3 = esq[2].getY();
559
                double x4 = esq[3].getX(), y4 = esq[3].getY();
560
                // A: X-scale
561
                a = Math.abs(Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) / size.getWidth());
562

    
563
                // E: negative Y-scale
564
                e = -Math.abs(Math.sqrt((x1 - x4) * (x1 - x4) + (y1 - y4) * (y1 - y4)) / size.getHeight());
565

    
566
                // C, F: upper-left coordinates
567
                c = x1;
568
                f = y1;
569

    
570
                // B & D: rotation parameters
571
                b = (a * size.getWidth() + c - x3) / size.getHeight() * -1;
572
                d = (e * size.getHeight() + f - y3) / size.getWidth() * -1;
573

    
574
                double[] wf = { a, d, b, e, c, f };
575
                return wf;  
576
        }
577

    
578
        /**
579
         * Ajusta el valor del array de puntos pasado como primer par?metro a las
580
         * dimensiones de la imagen. Estas dimensiones ser?n 0-dim.getX() a
581
         * 0-dim.getY(). Para cada valor, si es menor que 0 se pondr? a 0 y si es
582
         * mayor del m?ximo se asignar? al m?ximo.
583
         * @param points Lista de puntos a ajustar
584
         * @param dim Dimension
585
         */
586
        public static void adjustToPixelSize(Point2D[] points, Point2D dim) {
587
                for (int i = 0; i < points.length; i++) {
588
                        if (points[i].getX() < 0)
589
                                points[i].setLocation(0, points[i].getY());
590
                        if (points[i].getX() >= (dim.getX() - 1))
591
                                points[i].setLocation(dim.getX() - 1, points[i].getY());
592
                        if (points[i].getY() < 0)
593
                                points[i].setLocation(points[i].getX(), 0);
594
                        if (points[i].getY() >= (dim.getY() - 1))
595
                                points[i].setLocation(points[i].getX(), dim.getY() - 1);
596
                }
597
        }
598

    
599
        // ---------------------------------------------------------------
600
        // TRATAMIENTO DE FICHEROS
601

    
602
        /**
603
         * Copia de ficheros
604
         * @param pathOrig Ruta de origen
605
         * @param pathDst Ruta de destino.
606
         */
607
        public static void copyFile(String pathOrig, String pathDst) throws FileNotFoundException, IOException {
608
                InputStream in;
609
                OutputStream out;
610

    
611
                if (pathOrig == null || pathDst == null) {
612
                        System.err.println("Error en path");
613
                        return;
614
                }
615

    
616
                File orig = new File(pathOrig);
617
                if (!orig.exists() || !orig.isFile() || !orig.canRead()) {
618
                        System.err.println("Error en fichero de origen");
619
                        return;
620
                }
621

    
622
                File dest = new File(pathDst);
623
                String file = new File(pathOrig).getName();
624
                if (dest.isDirectory())
625
                        pathDst += file;
626

    
627
                in = new FileInputStream(pathOrig);
628
                out = new FileOutputStream(pathDst);
629

    
630
                byte[] buf = new byte[1024];
631
                int len;
632

    
633
                while ((len = in.read(buf)) > 0)
634
                        out.write(buf, 0, len);
635

    
636
                in.close();
637
                out.close();
638
        }
639

    
640
        /**
641
         * Crea un fichero de georeferenciaci?n (world file) para un dataset
642
         * determinado
643
         * @param GdalDriver
644
         * @param fileName Nombre completo del fichero de raster
645
         * @param Extent
646
         * @param pxWidth Ancho en p?xeles
647
         * @param pxHeight Alto en p?xeles
648
         * @return
649
         * @throws IOException
650
         */
651
        public static void createWorldFile(String fileName, Extent ext, int pxWidth, int pxHeight) throws IOException {
652
                File tfw = null;
653

    
654
                String extWorldFile = ".wld";
655
                if (fileName.endsWith("tif"))
656
                        extWorldFile = ".tfw";
657
                if (fileName.endsWith("jpg") || fileName.endsWith("jpeg"))
658
                        extWorldFile = ".jpgw";
659

    
660
                tfw = new File(fileName.substring(0, fileName.lastIndexOf(".")) + extWorldFile);
661

    
662
                // Generamos un world file para gdal
663
                DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(tfw)));
664
                dos.writeBytes((ext.getMax().getX() - ext.getMin().getX()) / pxWidth + "\n");
665
                dos.writeBytes("0.0\n");
666
                dos.writeBytes("0.0\n");
667
                dos.writeBytes((ext.getMin().getY() - ext.getMax().getY()) / pxHeight + "\n");
668
                dos.writeBytes("" + ext.getMin().getX() + "\n");
669
                dos.writeBytes("" + ext.getMax().getY() + "\n");
670
                dos.close();
671
        }
672
        
673
        /**
674
         * Comprueba si existe un worldfile para la imagen seleccionada.
675
         * @param fileName
676
         * @return
677
         * @throws IOException
678
         */
679
        public static boolean existsWorldFile(String fileName) throws IOException {
680
                File tfw = null;
681

    
682
                String extWorldFile = ".wld";
683
                if (fileName.endsWith("tif"))
684
                        extWorldFile = ".tfw";
685
                if (fileName.endsWith("jpg") || fileName.endsWith("jpeg"))
686
                        extWorldFile = ".jpgw";
687

    
688
                tfw = new File(fileName.substring(0, fileName.lastIndexOf(".")) + extWorldFile);
689
                
690
                return tfw.exists();
691
        }
692

    
693
        /**
694
         * Crea un fichero de georeferenciaci?n (world file) para un dataset
695
         * determinado
696
         * @param GdalDriver
697
         * @param fileName Nombre completo del fichero de raster
698
         * @param AffineTransform
699
         * @param pxWidth Ancho en p?xeles
700
         * @param pxHeight Alto en p?xeles
701
         * @return
702
         * @throws IOException
703
         */
704
        public static void createWorldFile(String fileName, AffineTransform at, int pxWidth, int pxHeight) throws IOException {
705
                File tfw = null;
706

    
707
                String extWorldFile = ".wld";
708
                if (fileName.endsWith("tif"))
709
                        extWorldFile = ".tfw";
710
                if (fileName.endsWith("jpg") || fileName.endsWith("jpeg"))
711
                        extWorldFile = ".jpgw";
712

    
713
                tfw = new File(fileName.substring(0, fileName.lastIndexOf(".")) + extWorldFile);
714

    
715
                // Generamos un world file para gdal
716
                DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(tfw)));
717
                dos.writeBytes(at.getScaleX() + "\n");
718
                dos.writeBytes(at.getShearX() + "\n");
719
                dos.writeBytes(at.getShearY() + "\n");
720
                dos.writeBytes(at.getScaleY() + "\n");
721
                dos.writeBytes("" + at.getTranslateX() + "\n");
722
                dos.writeBytes("" + at.getTranslateY() + "\n");
723
                dos.close();
724
        }
725

    
726
        /**
727
         * Formatea en forma de cadena un tama?o dado en bytes. El resultado ser? una
728
         * cadena con GB, MB, KB y B
729
         * @param size tama?o a formatear
730
         * @return cadena con la cantidad formateada
731
         */
732
        public static String formatFileSize(long size) {
733
                double bytes = (double) size;
734
                double kBytes = 0.0;
735
                double mBytes = 0.0;
736
                double gBytes = 0.0;
737
                if (bytes >= 1024.0) {
738
                        kBytes = bytes / 1024.0;
739
                        if (kBytes >= 1024.0) {
740
                                mBytes = kBytes / 1024.0;
741
                                if (mBytes >= 1024.0)
742
                                        gBytes = mBytes / 1024.0;
743
                        }
744
                }
745

    
746
                String texto = "";
747
                NumberFormat numberFormat = NumberFormat.getNumberInstance();
748
                numberFormat.setMinimumFractionDigits(0);
749

    
750
                do {
751
                        if (gBytes > 0) {
752
                                numberFormat.setMaximumFractionDigits(2 - (int) Math.log10(gBytes));
753
                                texto = numberFormat.format(gBytes) + " GB";
754
                                break;
755
                        }
756
                        if (mBytes > 0) {
757
                                numberFormat.setMaximumFractionDigits(2 - (int) Math.log10(mBytes));
758
                                texto = numberFormat.format(mBytes) + " MB";
759
                                break;
760
                        }
761
                        if (kBytes > 0) {
762
                                numberFormat.setMaximumFractionDigits(2 - (int) Math.log10(kBytes));
763
                                texto = numberFormat.format(kBytes) + " KB";
764
                                break;
765
                        }
766
                        if (bytes != 0) {
767
                                numberFormat.setMaximumFractionDigits(0);
768
                                texto = numberFormat.format(bytes) + " bytes";
769
                                break;
770
                        }
771
                } while (false);
772

    
773
                numberFormat.setMaximumFractionDigits(0);
774

    
775
                return texto + " (" + numberFormat.format(bytes) + " bytes)";
776
        }
777

    
778
        /**
779
         * Obtiene la extensi?n del fichero a partir de su nombre.
780
         * @param file Nombre o ruta del fichero
781
         * @return Cadena con la extensi?n que representa el tipo de fichero. Devuelve
782
         *         null si no tiene extension.
783
         */
784
        public static String getExtensionFromFileName(String file) {
785
                return file.substring(file.lastIndexOf(".") + 1).toLowerCase();
786
        }
787

    
788
        /**
789
         * Obtiene el nombre de fichero sin la extensi?n.
790
         * @param file Nombre o ruta del fichero
791
         * @return Cadena con la extensi?n que representa el tipo de fichero. Si no
792
         *         tiene extensi?n devuelve el mismo fichero de entrada
793
         */
794
        public static String getNameWithoutExtension(String file) {
795
                if (file == null)
796
                        return null;
797

    
798
                int n = file.lastIndexOf(".");
799
                if (n != -1)
800
                        return file.substring(0, n);
801
                return file;
802
        }
803
        
804
        /**
805
         * Obtiene el nombre de fichero sin la extensi?n ni la ruta.
806
         * @param file Ruta del fichero
807
         * @return Cadena que representa el nombre del fichero sin extensi?n ni path de directorios
808
         */
809
        public static String getFileNameFromCanonical(String file) {
810
                if (file == null)
811
                        return null;
812
                
813
                int n = file.lastIndexOf(".");
814
                if (n != -1)
815
                        file = file.substring(0, n);
816
                
817
                n = file.lastIndexOf(File.separator);
818
                if(n != -1)
819
                        file = file.substring(n + 1, file.length());
820
                
821
                return file;
822
        }
823

    
824
        /**
825
         * Obtiene el ?ltimo trozo de la cadena a partir de los caracteres que
826
         * coincidan con el patr?n. En caso de que el patr?n no exista en la cadena
827
         * devuelve esta completa
828
         * @param string
829
         * @param pattern
830
         * @return
831
         */
832
        public static String getLastPart(String string, String pattern) {
833
                int n = string.lastIndexOf(pattern);
834
                if (n > 0)
835
                        return string.substring(n + 1, string.length());
836
                return string;
837
        }
838

    
839
        /**
840
         * Obtiene la codificaci?n de un fichero XML
841
         * @param file Nombre del fichero XML
842
         * @return Codificaci?n
843
         */
844
        public static String readFileEncoding(String file) {
845
                FileReader fr;
846
                String encoding = null;
847
                try {
848
                        fr = new FileReader(file);
849
                        BufferedReader br = new BufferedReader(fr);
850
                        char[] buffer = new char[100];
851
                        br.read(buffer);
852
                        StringBuffer st = new StringBuffer(new String(buffer));
853
                        String searchText = "encoding=\"";
854
                        int index = st.indexOf(searchText);
855
                        if (index > -1) {
856
                                st.delete(0, index + searchText.length());
857
                                encoding = st.substring(0, st.indexOf("\""));
858
                        }
859
                        fr.close();
860
                } catch (FileNotFoundException ex) {
861
                        ex.printStackTrace();
862
                } catch (IOException e) {
863
                        e.printStackTrace();
864
                }
865
                return encoding;
866
        }
867

    
868
        /**
869
         * Guarda la informaci?n de georreferenciaci?n de un raster en su fichero rmf
870
         * adjunto.
871
         * @param path
872
         * @param at
873
         * @param dim
874
         * @throws IOException
875
         */
876
        public static void saveGeoInfo(String outRmf, AffineTransform at, Point2D dim) throws IOException {
877
                RmfBlocksManager manager = new RmfBlocksManager(outRmf + ".rmf");
878
                GeoInfoRmfSerializer ser3 = new GeoInfoRmfSerializer(at, dim);
879
                manager.addClient(ser3);
880
                manager.write();
881
        }
882

    
883
        /**
884
         * Obtiene el nombre del fichero RMF a partir del nombre del fichero. Si el
885
         * nombre del fichero tiene una extensi?n esta llamada sustituir? la extensi?n
886
         * existente por .rmf. Si el fichero pasado no tiene extensi?n esta llamada
887
         * a?adir? .rm al final.
888
         * @param fileName Nombre del fichero raster de origen
889
         * @return Nombre del fichero rmf asociado al raster.
890
         */
891
        public static String getRMFNameFromFileName(String fileName) {
892
                return getNameWithoutExtension(fileName) + ".rmf";
893
        }
894

    
895
        // ---------------------------------------------------------------
896
        // VARIOS
897

    
898
        /**
899
         * Formatea el tiempo en milisegundos devolviendo un String en formato . dias,
900
         * horas, minutos y segundos.
901
         * @param time Tiempo en milisegundos
902
         */
903
        public static String formatTime(long time) {
904
                int days = 0;
905
                int hours = 0;
906
                int minuts = 0;
907
                int seconds = (int) (time / 1000D);
908
                if (seconds >= 60) {
909
                        minuts = (int) (seconds / 60);
910
                        seconds = (int) (seconds - (minuts * 60));
911
                        if (minuts >= 60) {
912
                                hours = (int) (minuts / 60);
913
                                minuts = (int) (minuts - (hours * 60));
914
                                if (hours >= 24) {
915
                                        days = (int) (hours / 24);
916
                                        hours = (int) (hours - (days * 24));
917
                                }
918
                        }
919
                }
920
                StringBuffer s = new StringBuffer();
921
                if (days != 0)
922
                        s.append(days + " d ");
923
                if (hours != 0)
924
                        s.append(hours + " h ");
925
                if (minuts != 0)
926
                        s.append(minuts + " min ");
927
                if (seconds != 0)
928
                        s.append(seconds + " s ");
929
                if (s.length() == 0)
930
                        s.append(" < 1s");
931
                return s.toString();
932
        }
933

    
934
        /**
935
         * Obtiene un texto con las coordenadas a partir de n?meros en coma flotante.
936
         * @param minx coordenada m?nima de X
937
         * @param miny coordenada m?nima de Y
938
         * @param maxx coordenada m?xima de X
939
         * @param maxy coordenada m?xima de Y
940
         * @param dec N?mero de decimales a mostrar en la caja de texto
941
         */
942
        public static String[] getCoord(double minx, double miny, double maxx, double maxy, int dec) {
943
                String[] coordPx = new String[4];
944
                int indexPoint = String.valueOf(minx).indexOf('.');
945
                try {
946
                        coordPx[0] = String.valueOf(minx).substring(0, indexPoint + dec);
947
                } catch (StringIndexOutOfBoundsException ex) {
948
                        coordPx[0] = String.valueOf(minx);
949
                }
950
                indexPoint = String.valueOf(miny).indexOf('.');
951
                try {
952
                        coordPx[1] = String.valueOf(miny).substring(0, indexPoint + dec);
953
                } catch (StringIndexOutOfBoundsException ex) {
954
                        coordPx[1] = String.valueOf(miny);
955
                }
956
                indexPoint = String.valueOf(maxx).indexOf('.');
957
                try {
958
                        coordPx[2] = String.valueOf(maxx).substring(0, indexPoint + dec);
959
                } catch (StringIndexOutOfBoundsException ex) {
960
                        coordPx[2] = String.valueOf(maxx);
961
                }
962
                indexPoint = String.valueOf(maxy).indexOf('.');
963
                try {
964
                        coordPx[3] = String.valueOf(maxy).substring(0, indexPoint + dec);
965
                } catch (StringIndexOutOfBoundsException ex) {
966
                        coordPx[3] = String.valueOf(maxy);
967
                }
968
                return coordPx;
969
        }
970
}