Statistics
| Revision:

root / trunk / libraries / libRaster / src / org / gvsig / raster / buffer / RasterBuffer.java @ 13932

History | View | Annotate | Download (16.7 KB)

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

    
21
import java.io.FileNotFoundException;
22

    
23
import org.gvsig.raster.RasterLibrary;
24
import org.gvsig.raster.buffer.cache.RasterCache;
25
import org.gvsig.raster.buffer.cache.RasterReadOnlyHugeBuffer;
26
import org.gvsig.raster.dataset.IBuffer;
27
import org.gvsig.raster.dataset.NotSupportedExtensionException;
28
import org.gvsig.raster.dataset.RasterDriverException;
29
import org.gvsig.raster.datastruct.Histogram;
30
import org.gvsig.raster.datastruct.HistogramException;
31
import org.gvsig.raster.hierarchy.IHistogramable;
32
import org.gvsig.raster.util.RasterUtilities;
33

    
34
/**
35
 * Rectangulo de pixeles. Para cada tipo de datos java hay un buffer distinto donde cada elemento es
36
 * accedido de la siguiente forma: [banda][fila][columna]
37
 * m[1][2][0] = cte;-> Sustituye el elemento de la fila 2 de la banda 1 columna 0
38
 * m[1][0] = array; -> Sustituye la fila 0 de la banda 1 
39
 * m[0] = matriz cuadrada; -> Sustituye la banda entera.
40
 * 
41
 */
42
public abstract class RasterBuffer implements IBuffer {
43
        public static final int        CANCEL_HISTOGRAM = IHistogramable.CANCEL_HISTOGRAM;
44
        protected boolean[]                cancel = new boolean[1];
45

    
46
        public double                        noDataValue = -99999;
47

    
48
        protected int                        percent = 0;
49
        protected boolean                canceled = false;
50

    
51
        protected int                        width;
52
        protected int                        height;
53
        protected int                        nBands;
54
        protected int                        dataType;
55
  
56
  /**
57
   * Variable est?tica que si est? a false desactiva el uso de cach?. Puede ser usada por un cliente
58
   * para cargar siempre los datos en memoria. independientemente de su tama?o. 
59
   */
60
  public static boolean                cacheOn = true;
61
  /**
62
   * Fuerza la carga de los datos en cach? independientemente de su tama?o. Su
63
   * uso suele ser util solo para depuraci?n. Su valor por defecto y recomendado
64
   * es siempre false.
65
   */
66
  public static boolean         forceToLoadInCache = false;
67
  /**
68
   * Fuerza la carga de los datos en cach? de solo lectura independientemente de su tama?o. Su
69
   * uso suele ser util solo para depuraci?n. Su valor por defecto y recomendado
70
   * es siempre false.
71
   */
72
  public static boolean         forceToLoadInReadOnlyCache = false;
73
  /**
74
   * Valor con el que se rellena una banda no valida del buffer. Una banda no valida es la que 
75
   * no tiene datos asignados y tampoco puede ser null. Todas las bandas no validas de un buffer
76
   * apuntan por referencia a la misma banda.
77
   */
78
  protected double                        notValidValue = 0D;
79
  
80
  private BufferInterpolation        interp = null;
81

    
82
  /**
83
   * Genera instancias del buffer de datos adecuado al tama?o del raster. Si no hay muchos datos
84
   * (menos de cacheMemorySize) crear? un buffer en memoria. Si hay m?s de esta cantidad
85
   * entonces crearemos un buffer cacheado (RasterCache). A partir de la cantidad se?alada
86
   * por multicacheMemorySize haremos un buffer cacheado donde cada p?gina no ocupa todo
87
   * el ancho del raster ya que este ser? muy grande. La gesti?n de una cache donde cada
88
   * pagina ha de partir una l?nea lleva una complejidad a?adida.
89
   *  
90
   * @param dataType Tipo de dato
91
   * @param width Ancho
92
   * @param height Alto
93
   * @param bandNr Banda
94
   * @param flag En caso de buffers de memoria este flag a true significa que se reserva la memoria
95
   * para el buffer de forma normal y si est? a false no se reserva por lo que la reserva deber? ser
96
   * posterior. 
97
   * @return Objeto RasterBuffer
98
   * @throws RasterDriverException 
99
   * @throws NotSupportedExtensionException 
100
   * @throws FileNotFoundException 
101
   */
102
  public static RasterBuffer getBuffer(int dataType, int width, int height, int bandNr, boolean malloc) 
103
          /*throws FileNotFoundException, NotSupportedExtensionException, RasterDriverException*/{
104
          //Opci?n de cachear siempre activada (Solo DEBUG)
105
          if(forceToLoadInCache)
106
                  return new RasterCache(dataType, width, height, bandNr);
107
          if(forceToLoadInReadOnlyCache){
108
                try {
109
                        return new RasterReadOnlyHugeBuffer(dataType, width, height, bandNr);
110
                } catch (FileNotFoundException e) {
111
                        //TODO: EXCEPTION: Modificar el lanzamiento de excepciones del RasterBuffer
112
                        e.printStackTrace();
113
                } catch (NotSupportedExtensionException e) {
114
                        e.printStackTrace();
115
                } catch (RasterDriverException e) {
116
                        e.printStackTrace();
117
                }
118
          }
119
                  
120
          if(cacheOn){
121
            long size = (RasterUtilities.getBytesFromRasterBufType(dataType) * width * height * bandNr) / 1024;
122
            long ms1 = RasterLibrary.cacheSize * 1024;
123
            //long ms2 = multicacheMemorySize * 1024;
124
            if(size <= ms1)
125
                    return new RasterMemoryBuffer(dataType, width, height, bandNr, malloc);
126
            else{
127
                    //if(filePath == null)
128
                            return new RasterCache(dataType, width, height, bandNr);
129
                    /*else 
130
                            return new RasterReadOnlyHugeBuffer(dataType, width, height, bandNr, filePath);*/
131
            }        
132
          }else
133
                  return new RasterMemoryBuffer(dataType, width, height, bandNr, malloc);
134
  }
135
  
136
  /**
137
   * Reserva de memoria para el rasterbuf
138
   * @param dataType Tipo de dato
139
   * @param width Ancho
140
   * @param height Alto
141
   * @param bandNr Numero de bandas
142
   * @param orig
143
   */
144
  public abstract void malloc(int dataType, int width, int height, int bandNr);
145
 
146
  /*
147
   *  (non-Javadoc)
148
   * @see org.gvsig.fmap.driver.IBuffer#getWidth()
149
   */
150
  public int getWidth() {
151
      return width;
152
  }
153

    
154
 /*
155
  *  (non-Javadoc)
156
  * @see org.gvsig.fmap.driver.IBuffer#getHeight()
157
  */
158
  public int getHeight() {
159
      return height;
160
  }
161

    
162
  /*
163
   *  (non-Javadoc)
164
   * @see org.gvsig.fmap.driver.IBuffer#getBandCount()
165
   */
166
  public int getBandCount() {
167
      return nBands;
168
  }
169

    
170
  /**
171
   * Obtiene el tipo de dato. Los tipos de dato posibles est?n definidos en IRaster.
172
   * @return tipo de datos
173
   */
174
        public int getDataType() {
175
                return dataType;
176
        }
177
        
178
        /**
179
         * Asigna el tipo de dato. Los tipos de dato posibles est?n definidos en IRaster.
180
         * @param dataType Tipo de dato del buffer
181
         */
182
        public void setDataType(int dataType) {
183
                this.dataType = dataType;
184
        }
185

    
186
  /**
187
   * Obtiene el tama?o del tipo de dato en bytes
188
   * @return Tipo de dato
189
   */
190
  public int getDataSize() {
191
      if (dataType == TYPE_BYTE) {
192
          return 1;
193
      } else if ((dataType == TYPE_SHORT) | (dataType == TYPE_USHORT)) {
194
          return 2;
195
      } else if (dataType == TYPE_INT) {
196
          return 4;
197
      }else if (dataType == TYPE_FLOAT) {
198
          return 8;
199
      }else if (dataType == TYPE_DOUBLE) {
200
          return 16;
201
      }
202

    
203
      return 0;
204
  }
205

    
206
  /**
207
   * Obtiene el tama?o del buffer
208
   * @return tama?o del buffer
209
   */
210
  public long sizeof() {
211
      return getDataSize() * width * height * nBands;
212
  }
213
  
214
  /**
215
   * Replica la banda de una posici?n sobre otra. Si la banda de destino no existe
216
   * se crea nueva. Si la posici?n de la banda de destino est? intercalada entre bandas 
217
   * que ya existen las otras se desplazan hacia abajo, NO se machacan los datos de ninguna.
218
   * Los datos se replican por referencia por lo que al modificar la banda original las
219
   * del resto quedar?n afectadas.
220
   * @param orig. Posici?n de la banda de origen. 
221
   * @param dest. Posici?n de la banda destino
222
   */   
223
  public abstract void replicateBand(int orig, int dest);
224
  
225
  /**
226
   * Cambia bandas de posici?n. Las posiciones deben existir como bandas del raster. 
227
   * Cada elemento del array representa una banda existente en el buffer (de longitud
228
   * rasterBuf.length) y el valor contenido dentro la banda que le corresponde. Por ejemplo
229
   * si pasamos un array {1, 0, 3, 2} significa que el buffer tiene cuatro bandas y que 
230
   * cambiamos la 0 por la 1 y la 2 por la 3. Un array {0, 1, 2, 3} en el mismo 
231
   * caso no producir?a nig?n cambio.
232
   * 
233
   * Si quisieramos asignar en un buffer monobanda su banda a la segunda posici?n habria
234
   * que insertar una vacia, por ejemplo con addBandFloat(0, null) se insertaria una 
235
   * banda nula en la posici?n 0 y la banda que estaba en la 0 pasar?a a la segunda.
236
   * 
237
   */
238
  public abstract void switchBands(int[] bandPosition);
239
          
240
  /**
241
   * Convierte un tipo de dato a cadena
242
   * @param type Tipo de dato
243
   * @return cadena  que representa el tipo de dato
244
   */
245
  public static String typesToString(int type) {
246
      switch (type) {
247
      case RasterBuffer.TYPE_IMAGE:
248
          return new String("Image");
249

    
250
      case RasterBuffer.TYPE_BYTE:
251
          return new String("Byte");
252

    
253
      case RasterBuffer.TYPE_DOUBLE:
254
          return new String("Double");
255

    
256
      case RasterBuffer.TYPE_FLOAT:
257
          return new String("Float");
258

    
259
      case RasterBuffer.TYPE_INT:
260
              return new String("Integer");
261
              
262
      case RasterBuffer.TYPE_USHORT:
263
      case RasterBuffer.TYPE_SHORT:
264
          return new String("Short");
265
      }
266

    
267
      return null;
268
  }
269
  
270
  /*
271
   * (non-Javadoc)
272
   * @see org.gvsig.raster.dataset.IBuffer#isInside(int, int)
273
   */
274
  public boolean isInside(int x, int y) {
275
          if (x < 0 || y < 0 || x >= getWidth() || y >= getHeight())
276
                  return false;
277
          return true;
278
  }
279
      
280
  /*
281
   *  (non-Javadoc)
282
   * @see org.gvsig.fmap.driver.IBuffer#getNoDataValue()
283
   */
284
  public double getNoDataValue() {
285
          return noDataValue;
286
  }
287
  
288
  /*
289
   *  (non-Javadoc)
290
   * @see org.gvsig.fmap.driver.IBuffer#getByteNoDataValue()
291
   */
292
  public byte getByteNoDataValue() {
293
          return (byte)noDataValue;
294
  }
295
  
296
  /*
297
   *  (non-Javadoc)
298
   * @see org.gvsig.fmap.driver.IBuffer#getShortNoDataValue()
299
   */
300
  public short getShortNoDataValue(){
301
          return (short)noDataValue;
302
  }
303
  
304
  /*
305
   *  (non-Javadoc)
306
   * @see org.gvsig.fmap.driver.IBuffer#getIntNoDataValue()
307
   */
308
  public int getIntNoDataValue(){
309
          return (int)noDataValue;
310
  }
311
  
312
  /*
313
   *  (non-Javadoc)
314
   * @see org.gvsig.fmap.driver.IBuffer#getFloatNoDataValue()
315
   */
316
  public float getFloatNoDataValue(){
317
          return (float)noDataValue;
318
  }
319
  
320
  /*
321
   *  (non-Javadoc)
322
   * @see org.gvsig.fmap.driver.IBuffer#setNoDataValue(double)
323
   */
324
  public void setNoDataValue(double nd){
325
          noDataValue = nd;
326
  }
327
  
328
  /*
329
   *  (non-Javadoc)
330
   * @see org.gvsig.fmap.driver.IBuffer#getNotValidValue()
331
   */
332
  public double getNotValidValue(){
333
          return notValidValue;
334
  }
335
  
336
  /*
337
   *  (non-Javadoc)
338
   * @see org.gvsig.fmap.driver.IBuffer#setNotValidValue(java.lang.Object)
339
   */
340
  public void setNotValidValue(double value){
341
          this.notValidValue = value;
342
  }
343
  
344
  /*
345
   *  (non-Javadoc)
346
   * @see org.gvsig.fmap.driver.IBuffer#cloneBuffer()
347
   */
348
  public abstract IBuffer cloneBuffer();
349
  
350
        /**
351
         * Ajusta el ?rea del grid a un ancho y un alto dado en pixeles. Este ajuste se har? 
352
         * en relaci?n a un m?todo de interpolaci?n definido en el par?metro.
353
         * @param w Ancho de la nueva imagen.
354
         * @param h Alto de la nueva imagen.
355
         * @param interpolation M?todo de interpolaci?n que se usar? en el ajuste.
356
         */
357
        public RasterBuffer getAdjustedWindow(int w, int h, int interpolationMethod) {
358
                if(interp == null)
359
                        interp = new BufferInterpolation(this);
360
                
361
                if(w == getWidth() && h == getHeight())
362
                        return this;
363
                RasterBuffer rasterBuf = null;
364
                switch(interpolationMethod) {
365
                case BufferInterpolation.INTERPOLATION_NearestNeighbour:
366
                                rasterBuf = interp.adjustRasterNearestNeighbourInterpolation(w, h);
367
                                break;
368
                case BufferInterpolation.INTERPOLATION_Bilinear:
369
                                rasterBuf = interp.adjustRasterBilinearInterpolation(w, h);
370
                                break;
371
                case BufferInterpolation.INTERPOLATION_InverseDistance:
372
                                rasterBuf = interp.adjustRasterInverseDistanceInterpolation(w, h);
373
                                break;
374
                case BufferInterpolation.INTERPOLATION_BicubicSpline:
375
                                rasterBuf = interp.adjustRasterBicubicSplineInterpolation(w, h);
376
                                break;
377
                case BufferInterpolation.INTERPOLATION_BSpline:
378
                                rasterBuf = interp.adjustRasterBSplineInterpolation(w, h);
379
                                break;
380
                }
381
                if(rasterBuf != null)
382
                        return rasterBuf;
383
                else 
384
                        return this;
385
        }
386
  
387
  /**
388
   * Calcula el m?nimo y el m?ximo del histograma previamente.
389
   * @return double[] con el m?nimo y el m?ximo.
390
   */
391
  private double[] getLimits() {
392
          double max = Double.NEGATIVE_INFINITY;
393
          double min = Double.MAX_VALUE;
394
          double value = 0;
395

    
396
                switch (getDataType()) {
397
                        case IBuffer.TYPE_BYTE:
398
                                for (int i = 0; i < getBandCount(); i++)
399
                                        for (int r = 0; r < getHeight(); r++) {
400
                                                for (int c = 0; c < getWidth(); c++) {
401
                                                        value = (double) (getElemByte(r, c, i));
402
                                                        if (value > max) max = value;
403
                                                        if (value < min) min = value;
404
                                                }
405
                                                if (isCanceled(CANCEL_HISTOGRAM))
406
                                                        return null;
407
                                        }
408
                                break;
409
                        case IBuffer.TYPE_SHORT:
410
                                for (int i = 0; i < getBandCount(); i++)
411
                                        for (int r = 0; r < getHeight(); r++) {
412
                                                for (int c = 0; c < getWidth(); c++) {
413
                                                        value = (double) getElemShort(r, c, i);
414
                                                        if (value > max) max = value;
415
                                                        if (value < min) min = value;
416
                                                }
417
                                                if (isCanceled(CANCEL_HISTOGRAM))
418
                                                        return null;
419
                                        }
420
                                break;
421
                        case IBuffer.TYPE_INT:
422
                                for (int i = 0; i < getBandCount(); i++)
423
                                        for (int r = 0; r < getHeight(); r++) {
424
                                                for (int c = 0; c < getWidth(); c++) {
425
                                                        value = (double) getElemInt(r, c, i);
426
                                                        if (value > max) max = value;
427
                                                        if (value < min) min = value;
428
                                                }
429
                                                if (isCanceled(CANCEL_HISTOGRAM))
430
                                                        return null;
431
                                        }
432
                                break;
433
                        case IBuffer.TYPE_FLOAT:
434
                                for (int i = 0; i < getBandCount(); i++)
435
                                        for (int r = 0; r < getHeight(); r++) {
436
                                                for (int c = 0; c < getWidth(); c++) {
437
                                                        value =  (double) getElemFloat(r, c, i);
438
                                                        if (value > max) max = value;
439
                                                        if (value < min) min = value;
440
                                                }
441
                                                if (isCanceled(CANCEL_HISTOGRAM))
442
                                                        return null;
443
                                        }
444
                                break;
445
                        case IBuffer.TYPE_DOUBLE:
446
                                for (int i = 0; i < getBandCount(); i++)
447
                                        for (int r = 0; r < getHeight(); r++) {
448
                                                for (int c = 0; c < getWidth(); c++) {
449
                                                        value = getElemDouble(r, c, i);
450
                                                        if (value > max) max = value;
451
                                                        if (value < min) min = value;
452
                                                }
453
                                                if (isCanceled(CANCEL_HISTOGRAM))
454
                                                        return null;
455
                                        }
456
                                break;
457
                }
458
                double[] values = new double[2];
459
                values[0] = min;
460
                values[1] = max;
461
          return values;
462
  }
463

    
464
  /*
465
   * (non-Javadoc)
466
   * @see org.gvsig.raster.driver.datasetproperties.IHistogramable#getHistogram()
467
   */
468
        public Histogram getHistogram() throws HistogramException {
469
                percent = 0;
470
                Histogram hist = null;
471
                double[] limits = getLimits();
472

    
473
                if (limits == null)
474
                        return null;
475

    
476
                if (getDataType() == IBuffer.TYPE_BYTE)
477
                        hist = new Histogram(getBandCount(), 256, limits[0], limits[1]);
478
                else
479
                        hist = new Histogram(getBandCount(), RasterLibrary.defaultNumberOfClasses, limits[0], limits[1]);
480
                                
481
                for (int iBand = 0; iBand < getBandCount(); iBand++) {
482
                        for (int row = 0; row < getHeight(); row++) {
483
                                switch(getDataType()) {
484
                                case IBuffer.TYPE_BYTE:
485
                                        for (int col = 0; col < getWidth(); col++) 
486
                                                hist.incrementPxValue(iBand, (double)(getElemByte(row, col, iBand)));
487
                                        break;
488
                                case IBuffer.TYPE_SHORT:
489
                                        for (int col = 0; col < getWidth(); col++) 
490
                                                hist.incrementPxValue(iBand, (double)(getElemShort(row, col, iBand)));
491
                                        break;
492
                                case IBuffer.TYPE_INT:
493
                                        for (int col = 0; col < getWidth(); col++) 
494
                                                hist.incrementPxValue(iBand, (double)(getElemInt(row, col, iBand)));
495
                                        break;
496
                                case IBuffer.TYPE_FLOAT:
497
                                        for (int col = 0; col < getWidth(); col++) 
498
                                                hist.incrementPxValue(iBand, (double)getElemFloat(row, col, iBand));
499
                                        break;
500
                                case IBuffer.TYPE_DOUBLE:
501
                                        for (int col = 0; col < getWidth(); col++) 
502
                                                hist.incrementPxValue(iBand, getElemDouble(row, col, iBand));
503
                                        break;
504
                                }
505
                                
506
                                if (isCanceled(CANCEL_HISTOGRAM))
507
                                        return null;
508

    
509
                                percent = ((iBand*getHeight() + row) * 100) /(getHeight() * getBandCount());
510
                        }
511
                }
512
                percent = 100;
513
                return hist;
514
        }
515

    
516
        /*
517
         * (non-Javadoc)
518
         * @see org.gvsig.raster.util.IHistogramable#resetPercent()
519
         */
520
        public void resetPercent() {
521
                percent = 0;
522
        }
523

    
524
        /*
525
         * (non-Javadoc)
526
         * @see org.gvsig.raster.util.IHistogramable#getPercent()
527
         */
528
        public int getPercent() {
529
                return percent;
530
        }
531

    
532
        /*
533
         * (non-Javadoc)
534
         * @see org.gvsig.raster.util.ICancellable#isCanceled()
535
         */
536
        public boolean isCanceled(int process) {
537
                if(process == CANCEL_HISTOGRAM)
538
                        return cancel[0];
539
                return false;
540
        }
541
        
542
        /*
543
         * (non-Javadoc)
544
         * @see org.gvsig.raster.util.ICancellable#setCanceled(boolean)
545
         */
546
        public void setCanceled(boolean value, int process) {
547
                if(process == CANCEL_HISTOGRAM || process == 0)
548
                        cancel[0] = value;
549
        }
550
}