Statistics
| Revision:

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

History | View | Annotate | Download (18 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.RasterReadOnlyBuffer;
26
import org.gvsig.raster.buffer.cache.RasterReadOnlyHugeBuffer;
27
import org.gvsig.raster.dataset.IBuffer;
28
import org.gvsig.raster.dataset.IRasterDataSource;
29
import org.gvsig.raster.dataset.NotSupportedExtensionException;
30
import org.gvsig.raster.dataset.RasterDriverException;
31
import org.gvsig.raster.datastruct.Histogram;
32
import org.gvsig.raster.process.RasterTask;
33
import org.gvsig.raster.process.RasterTaskQueue;
34
import org.gvsig.raster.util.RasterUtilities;
35

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

    
47
        public double                        noDataValue = -99999;
48

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

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

    
83
  /**
84
   * Genera instancias del buffer de datos adecuado al tama?o del raster. Si no hay muchos datos
85
   * (menos de cacheMemorySize) crear? un buffer en memoria. Si hay m?s de esta cantidad
86
   * entonces crearemos un buffer cacheado (RasterCache). A partir de la cantidad se?alada
87
   * por multicacheMemorySize haremos un buffer cacheado donde cada p?gina no ocupa todo
88
   * el ancho del raster ya que este ser? muy grande. La gesti?n de una cache donde cada
89
   * pagina ha de partir una l?nea lleva una complejidad a?adida.
90
   *  
91
   * @param dataType Tipo de dato
92
   * @param width Ancho
93
   * @param height Alto
94
   * @param bandNr Banda
95
   * @param flag En caso de buffers de memoria este flag a true significa que se reserva la memoria
96
   * para el buffer de forma normal y si est? a false no se reserva por lo que la reserva deber? ser
97
   * posterior. 
98
   * @return Objeto RasterBuffer
99
   * @throws RasterDriverException 
100
   * @throws NotSupportedExtensionException 
101
   * @throws FileNotFoundException 
102
   */
103
  public static RasterBuffer getBuffer(int dataType, int width, int height, int bandNr, boolean malloc) 
104
          /*throws FileNotFoundException, NotSupportedExtensionException, RasterDriverException*/{
105
          //Opci?n de cachear siempre activada (Solo DEBUG)
106
          if(forceToLoadInCache)
107
                  return new RasterCache(dataType, width, height, bandNr);
108
          if(forceToLoadInReadOnlyCache){
109
                try {
110
                        return new RasterReadOnlyHugeBuffer(dataType, width, height, bandNr);
111
                } catch (FileNotFoundException e) {
112
                        //TODO: EXCEPTION: Modificar el lanzamiento de excepciones del RasterBuffer
113
                        e.printStackTrace();
114
                } catch (NotSupportedExtensionException e) {
115
                        e.printStackTrace();
116
                } catch (RasterDriverException e) {
117
                        e.printStackTrace();
118
                }
119
          }
120
                  
121
          if(cacheOn){
122
            long size = (RasterUtilities.getBytesFromRasterBufType(dataType) * width * height * bandNr) / 1024;
123
            long ms1 = RasterLibrary.cacheSize * 1024;
124
            if(size <= ms1)
125
                    return new RasterMemoryBuffer(dataType, width, height, bandNr, malloc);
126
            else
127
                    return new RasterCache(dataType, width, height, bandNr);
128
          }else
129
                  return new RasterMemoryBuffer(dataType, width, height, bandNr, malloc);
130
  }
131
  
132
  /**
133
   * Devuelve true si el tama?o del dataset es menor que el de la cach? y false 
134
   * si no lo es.
135
   * @param datasource Fuente de datos
136
   * @return true si podemos cargar en memoria el raster
137
   */
138
  public static boolean loadInMemory(IRasterDataSource datasource) {
139
          return (datasource.getFileSize() < (RasterLibrary.cacheSize * 1048576));
140
  }
141
  
142
  /**
143
   * Genera una instancia del buffer de solo lectura. Este buffer consta de una cache y unos apuntadores
144
   * a las p?ginas en disco. Cuando se accede a los datos se carga en memoria la p?gina pedida.
145
   *  
146
   * @param dataType Tipo de dato
147
   * @param width Ancho
148
   * @param height Alto
149
   * @param bandNr Banda
150
   */
151
  public static RasterBuffer getReadOnlyBuffer(int dataType, int width, int height, int bandNr) {
152
          return new RasterReadOnlyBuffer(dataType, width, height, bandNr);
153
  }
154
  
155
  /**
156
   * Genera una instancia del buffer de solo lectura. Este buffer consta de una cache y unos apuntadores
157
   * a las p?ginas en disco. Cuando se accede a los datos se carga en memoria la p?gina pedida.
158
   *  
159
   * @param dataType Tipo de dato
160
   * @param width Ancho
161
   * @param height Alto
162
   * @param bandNr Banda
163
   * @param flag En caso de buffers de memoria este flag a true significa que se reserva la memoria
164
   * para el buffer de forma normal y si est? a false no se reserva por lo que la reserva deber? ser
165
   * posterior. 
166
   */
167
  public static RasterBuffer getMemoryBuffer(int dataType, int width, int height, int bandNr, boolean malloc) {
168
          return new RasterMemoryBuffer(dataType, width, height, bandNr, malloc);
169
  }
170
  
171
  /**
172
   * Reserva de memoria para el rasterbuf
173
   * @param dataType Tipo de dato
174
   * @param width Ancho
175
   * @param height Alto
176
   * @param bandNr Numero de bandas
177
   * @param orig
178
   */
179
  public abstract void malloc(int dataType, int width, int height, int bandNr);
180
 
181
  /*
182
   *  (non-Javadoc)
183
   * @see org.gvsig.fmap.driver.IBuffer#getWidth()
184
   */
185
  public int getWidth() {
186
      return width;
187
  }
188

    
189
 /*
190
  *  (non-Javadoc)
191
  * @see org.gvsig.fmap.driver.IBuffer#getHeight()
192
  */
193
  public int getHeight() {
194
      return height;
195
  }
196

    
197
  /*
198
   *  (non-Javadoc)
199
   * @see org.gvsig.fmap.driver.IBuffer#getBandCount()
200
   */
201
  public int getBandCount() {
202
      return nBands;
203
  }
204

    
205
  /**
206
   * Obtiene el tipo de dato. Los tipos de dato posibles est?n definidos en IRaster.
207
   * @return tipo de datos
208
   */
209
        public int getDataType() {
210
                return dataType;
211
        }
212
        
213
        /**
214
         * Asigna el tipo de dato. Los tipos de dato posibles est?n definidos en IRaster.
215
         * @param dataType Tipo de dato del buffer
216
         */
217
        public void setDataType(int dataType) {
218
                this.dataType = dataType;
219
        }
220

    
221
  /**
222
   * Obtiene el tama?o del tipo de dato en bytes
223
   * @return Tipo de dato
224
   */
225
  public int getDataSize() {
226
      if (dataType == TYPE_BYTE) {
227
          return 1;
228
      } else if ((dataType == TYPE_SHORT) | (dataType == TYPE_USHORT)) {
229
          return 2;
230
      } else if (dataType == TYPE_INT) {
231
          return 4;
232
      }else if (dataType == TYPE_FLOAT) {
233
          return 8;
234
      }else if (dataType == TYPE_DOUBLE) {
235
          return 16;
236
      }
237

    
238
      return 0;
239
  }
240

    
241
  /**
242
   * Obtiene el tama?o del buffer
243
   * @return tama?o del buffer
244
   */
245
  public long sizeof() {
246
      return getDataSize() * width * height * nBands;
247
  }
248
  
249
  /**
250
   * Replica la banda de una posici?n sobre otra. Si la banda de destino no existe
251
   * se crea nueva. Si la posici?n de la banda de destino est? intercalada entre bandas 
252
   * que ya existen las otras se desplazan hacia abajo, NO se machacan los datos de ninguna.
253
   * Los datos se replican por referencia por lo que al modificar la banda original las
254
   * del resto quedar?n afectadas.
255
   * @param orig. Posici?n de la banda de origen. 
256
   * @param dest. Posici?n de la banda destino
257
   */   
258
  public abstract void replicateBand(int orig, int dest);
259
  
260
  /**
261
   * Cambia bandas de posici?n. Las posiciones deben existir como bandas del raster. 
262
   * Cada elemento del array representa una banda existente en el buffer (de longitud
263
   * rasterBuf.length) y el valor contenido dentro la banda que le corresponde. Por ejemplo
264
   * si pasamos un array {1, 0, 3, 2} significa que el buffer tiene cuatro bandas y que 
265
   * cambiamos la 0 por la 1 y la 2 por la 3. Un array {0, 1, 2, 3} en el mismo 
266
   * caso no producir?a nig?n cambio.
267
   * 
268
   * Si quisieramos asignar en un buffer monobanda su banda a la segunda posici?n habria
269
   * que insertar una vacia, por ejemplo con addBandFloat(0, null) se insertaria una 
270
   * banda nula en la posici?n 0 y la banda que estaba en la 0 pasar?a a la segunda.
271
   * 
272
   */
273
  public abstract void switchBands(int[] bandPosition);
274
          
275
  /**
276
   * Convierte un tipo de dato a cadena
277
   * @param type Tipo de dato
278
   * @return cadena  que representa el tipo de dato
279
   */
280
  public static String typesToString(int type) {
281
      switch (type) {
282
      case RasterBuffer.TYPE_IMAGE:
283
          return new String("Image");
284

    
285
      case RasterBuffer.TYPE_BYTE:
286
          return new String("Byte");
287

    
288
      case RasterBuffer.TYPE_DOUBLE:
289
          return new String("Double");
290

    
291
      case RasterBuffer.TYPE_FLOAT:
292
          return new String("Float");
293

    
294
      case RasterBuffer.TYPE_INT:
295
              return new String("Integer");
296
              
297
      case RasterBuffer.TYPE_USHORT:
298
      case RasterBuffer.TYPE_SHORT:
299
          return new String("Short");
300
      }
301

    
302
      return null;
303
  }
304
  
305
  /*
306
   * (non-Javadoc)
307
   * @see org.gvsig.raster.dataset.IBuffer#isInside(int, int)
308
   */
309
  public boolean isInside(int x, int y) {
310
          if (x < 0 || y < 0 || x >= getWidth() || y >= getHeight())
311
                  return false;
312
          return true;
313
  }
314
      
315
  /*
316
   *  (non-Javadoc)
317
   * @see org.gvsig.fmap.driver.IBuffer#getNoDataValue()
318
   */
319
  public double getNoDataValue() {
320
          return noDataValue;
321
  }
322
  
323
  /*
324
   *  (non-Javadoc)
325
   * @see org.gvsig.fmap.driver.IBuffer#getByteNoDataValue()
326
   */
327
  public byte getByteNoDataValue() {
328
          return (byte)noDataValue;
329
  }
330
  
331
  /*
332
   *  (non-Javadoc)
333
   * @see org.gvsig.fmap.driver.IBuffer#getShortNoDataValue()
334
   */
335
  public short getShortNoDataValue(){
336
          return (short)noDataValue;
337
  }
338
  
339
  /*
340
   *  (non-Javadoc)
341
   * @see org.gvsig.fmap.driver.IBuffer#getIntNoDataValue()
342
   */
343
  public int getIntNoDataValue(){
344
          return (int)noDataValue;
345
  }
346
  
347
  /*
348
   *  (non-Javadoc)
349
   * @see org.gvsig.fmap.driver.IBuffer#getFloatNoDataValue()
350
   */
351
  public float getFloatNoDataValue(){
352
          return (float)noDataValue;
353
  }
354
  
355
  /*
356
   *  (non-Javadoc)
357
   * @see org.gvsig.fmap.driver.IBuffer#setNoDataValue(double)
358
   */
359
  public void setNoDataValue(double nd){
360
          noDataValue = nd;
361
  }
362
  
363
  /*
364
   *  (non-Javadoc)
365
   * @see org.gvsig.fmap.driver.IBuffer#getNotValidValue()
366
   */
367
  public double getNotValidValue(){
368
          return notValidValue;
369
  }
370
  
371
  /*
372
   *  (non-Javadoc)
373
   * @see org.gvsig.fmap.driver.IBuffer#setNotValidValue(java.lang.Object)
374
   */
375
  public void setNotValidValue(double value){
376
          this.notValidValue = value;
377
  }
378
  
379
  /*
380
   *  (non-Javadoc)
381
   * @see org.gvsig.fmap.driver.IBuffer#cloneBuffer()
382
   */
383
  public abstract IBuffer cloneBuffer();
384
  
385
        /**
386
         * Ajusta el ?rea del grid a un ancho y un alto dado en pixeles. Este ajuste se har? 
387
         * en relaci?n a un m?todo de interpolaci?n definido en el par?metro.
388
         * @param w Ancho de la nueva imagen.
389
         * @param h Alto de la nueva imagen.
390
         * @param interpolation M?todo de interpolaci?n que se usar? en el ajuste.
391
         */
392
        public RasterBuffer getAdjustedWindow(int w, int h, int interpolationMethod) {
393
                if(interp == null)
394
                        interp = new BufferInterpolation(this);
395
                
396
                if(w == getWidth() && h == getHeight())
397
                        return this;
398
                RasterBuffer rasterBuf = null;
399
                switch(interpolationMethod) {
400
                case BufferInterpolation.INTERPOLATION_NearestNeighbour:
401
                                rasterBuf = interp.adjustRasterNearestNeighbourInterpolation(w, h);
402
                                break;
403
                case BufferInterpolation.INTERPOLATION_Bilinear:
404
                                rasterBuf = interp.adjustRasterBilinearInterpolation(w, h);
405
                                break;
406
                case BufferInterpolation.INTERPOLATION_InverseDistance:
407
                                rasterBuf = interp.adjustRasterInverseDistanceInterpolation(w, h);
408
                                break;
409
                case BufferInterpolation.INTERPOLATION_BicubicSpline:
410
                                rasterBuf = interp.adjustRasterBicubicSplineInterpolation(w, h);
411
                                break;
412
                case BufferInterpolation.INTERPOLATION_BSpline:
413
                                rasterBuf = interp.adjustRasterBSplineInterpolation(w, h);
414
                                break;
415
                }
416
                if(rasterBuf != null)
417
                        return rasterBuf;
418
                else 
419
                        return this;
420
        }
421
  
422
  /**
423
   * Calcula el m?nimo y el m?ximo del histograma previamente.
424
   * @return double[] con el m?nimo y el m?ximo.
425
   * @throws InterruptedException 
426
   */
427
  private double[] getLimits() throws InterruptedException {
428
          RasterTask task = RasterTaskQueue.get(Thread.currentThread().toString());
429
          double max = Double.NEGATIVE_INFINITY;
430
          double min = Double.MAX_VALUE;
431
          double value = 0;
432

    
433
                switch (getDataType()) {
434
                        case IBuffer.TYPE_BYTE:
435
                                for (int i = 0; i < getBandCount(); i++)
436
                                        for (int r = 0; r < getHeight(); r++) {
437
                                                for (int c = 0; c < getWidth(); c++) {
438
                                                        value = (double) ((getElemByte(r, c, i)));
439
                                                        if (value > max) max = value;
440
                                                        if (value < min) min = value;
441
                                                }
442
                                                if (task.getEvent() != null)
443
                                                        task.manageEvent(task.getEvent());
444
                                        }
445
                                break;
446
                        case IBuffer.TYPE_SHORT:
447
                                for (int i = 0; i < getBandCount(); i++)
448
                                        for (int r = 0; r < getHeight(); r++) {
449
                                                for (int c = 0; c < getWidth(); c++) {
450
                                                        value = (double) getElemShort(r, c, i);
451
                                                        if (value > max) max = value;
452
                                                        if (value < min) min = value;
453
                                                }
454
                                                if (task.getEvent() != null)
455
                                                        task.manageEvent(task.getEvent());
456
                                        }
457
                                break;
458
                        case IBuffer.TYPE_INT:
459
                                for (int i = 0; i < getBandCount(); i++)
460
                                        for (int r = 0; r < getHeight(); r++) {
461
                                                for (int c = 0; c < getWidth(); c++) {
462
                                                        value = (double) getElemInt(r, c, i);
463
                                                        if (value > max) max = value;
464
                                                        if (value < min) min = value;
465
                                                }
466
                                                if (task.getEvent() != null)
467
                                                        task.manageEvent(task.getEvent());
468
                                        }
469
                                break;
470
                        case IBuffer.TYPE_FLOAT:
471
                                for (int i = 0; i < getBandCount(); i++)
472
                                        for (int r = 0; r < getHeight(); r++) {
473
                                                for (int c = 0; c < getWidth(); c++) {
474
                                                        value =  (double) getElemFloat(r, c, i);
475
                                                        if (value > max) max = value;
476
                                                        if (value < min) min = value;
477
                                                }
478
                                                if (task.getEvent() != null)
479
                                                        task.manageEvent(task.getEvent());
480
                                        }
481
                                break;
482
                        case IBuffer.TYPE_DOUBLE:
483
                                for (int i = 0; i < getBandCount(); i++)
484
                                        for (int r = 0; r < getHeight(); r++) {
485
                                                for (int c = 0; c < getWidth(); c++) {
486
                                                        value = getElemDouble(r, c, i);
487
                                                        if (value > max) max = value;
488
                                                        if (value < min) min = value;
489
                                                }
490
                                                if (task.getEvent() != null)
491
                                                        task.manageEvent(task.getEvent());
492
                                        }
493
                                break;
494
                }
495
                double[] values = new double[2];
496
                values[0] = min;
497
                values[1] = max;
498
          return values;
499
  }
500

    
501
  /*
502
   * (non-Javadoc)
503
   * @see org.gvsig.raster.driver.datasetproperties.IHistogramable#getHistogram()
504
   */
505
        public Histogram getHistogram() throws InterruptedException {
506
                RasterTask task = RasterTaskQueue.get(Thread.currentThread().toString());
507
                percent = 0;
508
                Histogram hist = null;
509
                double[] limits = getLimits();
510

    
511
                if (limits == null)
512
                        return null;
513

    
514
                if (getDataType() == IBuffer.TYPE_BYTE)
515
                        hist = new Histogram(getBandCount(), 256, limits[0], limits[1]);
516
                else
517
                        hist = new Histogram(getBandCount(), RasterLibrary.defaultNumberOfClasses, limits[0], limits[1]);
518
                                
519
                for (int iBand = 0; iBand < getBandCount(); iBand++) {
520
                        for (int row = 0; row < getHeight(); row++) {
521
                                switch(getDataType()) {
522
                                case IBuffer.TYPE_BYTE:
523
                                        for (int col = 0; col < getWidth(); col++) 
524
                                                hist.incrementPxValue(iBand, (double)(getElemByte(row, col, iBand)));
525
                                        break;
526
                                case IBuffer.TYPE_SHORT:
527
                                        for (int col = 0; col < getWidth(); col++) 
528
                                                hist.incrementPxValue(iBand, (double)(getElemShort(row, col, iBand)));
529
                                        break;
530
                                case IBuffer.TYPE_INT:
531
                                        for (int col = 0; col < getWidth(); col++) 
532
                                                hist.incrementPxValue(iBand, (double)(getElemInt(row, col, iBand)));
533
                                        break;
534
                                case IBuffer.TYPE_FLOAT:
535
                                        for (int col = 0; col < getWidth(); col++) 
536
                                                hist.incrementPxValue(iBand, (double)getElemFloat(row, col, iBand));
537
                                        break;
538
                                case IBuffer.TYPE_DOUBLE:
539
                                        for (int col = 0; col < getWidth(); col++) 
540
                                                hist.incrementPxValue(iBand, getElemDouble(row, col, iBand));
541
                                        break;
542
                                }
543
                                
544
                                if (task.getEvent() != null)
545
                                        task.manageEvent(task.getEvent());
546

    
547
                                percent = ((iBand*getHeight() + row) * 100) /(getHeight() * getBandCount());
548
                        }
549
                }
550
                percent = 100;
551
                return hist;
552
        }
553

    
554
        /*
555
         * (non-Javadoc)
556
         * @see org.gvsig.raster.util.IHistogramable#resetPercent()
557
         */
558
        public void resetPercent() {
559
                percent = 0;
560
        }
561

    
562
        /*
563
         * (non-Javadoc)
564
         * @see org.gvsig.raster.util.IHistogramable#getPercent()
565
         */
566
        public int getPercent() {
567
                return percent;
568
        }
569
}