Statistics
| Revision:

root / trunk / libraries / libRaster / src / org / gvsig / raster / datastruct / ColorTable.java @ 12504

History | View | Annotate | Download (16.2 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2006 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 */
19
package org.gvsig.raster.datastruct;
20

    
21
import java.awt.Color;
22
import java.util.ArrayList;
23

    
24
import org.gvsig.raster.RasterLibrary;
25

    
26
import es.gva.cit.jgdal.GdalColorEntry;
27
import es.gva.cit.jgdal.GdalColorTable;
28
import es.gva.cit.jgdal.GdalException;
29
/**
30
 * Paleta para raster. Esta consta de los valores RGB de la paleta que son
31
 * almacenados en un vector donde cada elemento contiene en su interior el RGB
32
 * completo y del vector de rangos.
33
 *
34
 * @version 04/07/2007
35
 * @author Nacho Brodin (nachobrodin@gmail.com)
36
 * @author BorSanZa - Borja S?nchez Zamorano (borja.sanchez@iver.es)
37
 */
38
public class ColorTable implements Cloneable {
39
        /**
40
         * Lista de ColorItem donde estaran todos los valores de la paleta segun
41
         * el interfaz
42
         */
43
        private ArrayList   colorItems        = null;
44

    
45
        /**
46
         * Booleano que define si se interpolaran los valores de la paleta.
47
         */
48
        protected boolean   interpolated      = true;
49

    
50
        /**
51
         * Lista de rangos para paletas decimales
52
         */
53

    
54
        protected double[]  range             = null;
55
        /**
56
         * Lista de valores RGB
57
         */
58
        protected byte[][]  paletteByBand     = null;
59

    
60
        /**
61
         * Nombre de la clase asociada a la entrada
62
         */
63
        protected String[]  nameClass         = null;
64

    
65
        /**
66
         * Lista con todas las transparencias de la paleta
67
         */
68
        protected ArrayList transparencyRange = new ArrayList();
69

    
70
        /**
71
         * Nombre de la paleta
72
         */
73
        protected String    name              = null;
74

    
75
        /**
76
         * Ruta del fichero a la cual se asocia la paleta. Las bandas de un
77
         * GeoRasterMultiFile han de saber a que paleta van asociadas.
78
         */
79
        protected String    filePath          = null;
80

    
81
        /**
82
         * Constructor vac?o.
83
         * @param name
84
         */
85
        public ColorTable() {
86
                this.name = "";
87
        }
88

    
89
        /**
90
         * Constructor. Asigna el nombre de la paleta.
91
         * @param name
92
         */
93
        public ColorTable(String name) {
94
                this.name = name;
95
        }
96

    
97
        /**
98
         * Asigna el nombre de la paleta
99
         * @param Nombre de la paleta
100
         */
101
        public void setName(String name) {
102
                this.name = name;
103
        }
104

    
105
        /**
106
         * Obtiene el nombre de la paleta
107
         * @return Nombre de la paleta
108
         */
109
        public String getName() {
110
                return name;
111
        }
112

    
113
        public void createPaletteFromColorItems(ArrayList colorItems) {
114
                this.colorItems = colorItems;
115

    
116
                // Ordena la paleta
117
                sortPalette();
118

    
119
//                System.out.println(name);
120
//                System.out.println("----- Sin comprimir (" + colorItems.size() + ") -----");
121
/*
122
                if (name.equals("MDT1")) {
123
                        for (int i=0; i<colorItems.size(); i++) {
124
                                ColorItem c1 = ((ColorItem) colorItems.get(i));
125
                                Color co = c1.getColor();
126
                                System.out.println(c1.getValue() + ": " + co.getRed() + "," + co.getGreen() + "," + co.getBlue() + "," + co.getAlpha());
127
                        }
128
                }
129
*/
130
                // Mira que valores se pueden descartar y asi dejamos la paleta reducida
131
                // para poder hacer interpolaciones
132
                compressPalette();
133

    
134
//                System.out.println("------ Comprimido (" + colorItems.size() + ") ------");
135
/*
136
                if (name.equals("MDT1")) {
137
                        for (int i=0; i<colorItems.size(); i++) {
138
                                ColorItem c1 = ((ColorItem) colorItems.get(i));
139
                                Color co = c1.getColor();
140
                                System.out.println(c1.getValue() + ": " + co.getRed() + "," + co.getGreen() + "," + co.getBlue() + "," + co.getAlpha());
141
                        }
142
                }
143
*/
144
                // Genera la paleta final para poder ser usada
145
                applyPalette();
146
        }
147

    
148
        int error = 8;
149
        private boolean isEqualColor(Color c1, Color c2) {
150
                if (c2.getRed() < (c1.getRed() - error)) return false;
151
                if (c2.getGreen() < (c1.getGreen() - error)) return false;
152
                if (c2.getBlue() < (c1.getBlue() - error)) return false;
153
                if (c2.getAlpha() < (c1.getAlpha() - error)) return false;
154

    
155
                if (c2.getRed() > (c1.getRed() + error)) return false;
156
                if (c2.getGreen() > (c1.getGreen() + error)) return false;
157
                if (c2.getBlue() > (c1.getBlue() + error)) return false;
158
                if (c2.getAlpha() > (c1.getAlpha() + error)) return false;
159

    
160
                return true;
161
        }
162

    
163
        private boolean isCorrectColor(ColorItem c1, ColorItem c2, ColorItem c3) {
164
                double max = c2.getValue()-c1.getValue();
165
                int r = c1.getColor().getRed() + (int) (((c2.getColor().getRed() - c1.getColor().getRed()) * (c3.getValue() - c1.getValue())) / max);
166
                int g = c1.getColor().getGreen() + (int) (((c2.getColor().getGreen() - c1.getColor().getGreen()) * (c3.getValue() - c1.getValue())) / max);
167
                int b = c1.getColor().getBlue() + (int) (((c2.getColor().getBlue() - c1.getColor().getBlue()) * (c3.getValue() - c1.getValue())) / max);
168
                int a = c1.getColor().getAlpha() + (int) (((c2.getColor().getAlpha() - c1.getColor().getAlpha()) * (c3.getValue() - c1.getValue())) / max);
169
                Color aux = new Color(r & 0xff, g & 0xff, b & 0xff, a & 0xff);
170

    
171
                return isEqualColor(c3.getColor(), aux);
172
        }
173

    
174
        private boolean canDelete(int first, int last) {
175
                ColorItem c1 = (ColorItem) colorItems.get(first);
176
                ColorItem c2 = (ColorItem) colorItems.get(last);
177
                for (int i = (first + 1); i < last; i++) {
178
                        if (!isCorrectColor(c1, c2, (ColorItem) colorItems.get(i)))
179
                                return false;
180
                }
181
                return true;
182
        }
183

    
184
        private void compressPalette() {
185
                int init = 0;
186
                int posMax = 2;
187
                while (init < colorItems.size()) {
188
                        if ((posMax < colorItems.size()) && canDelete(init, posMax)) {
189
                                posMax++;
190
                                continue;
191
                        }
192
                        if ((init + 2) < posMax) {
193
                                if (canDelete(init, posMax - 1))
194
                                        for (int i = (posMax - 2); i > init; i--)
195
                                                if (i < colorItems.size())
196
                                                        colorItems.remove(i);
197
                        }
198
                        init++;
199
                        posMax = init + 2;
200
                }
201
        }
202

    
203
        /**
204
         * Crea una paleta a partir de un objeto GdalColorTable. Esto es necesario
205
         * para los ficheros que tienen una paleta asignada, como los gif, y que son
206
         * tratados por Gdal. Se pasa la tabla de color le?da desde gdal y se crea
207
         * directamente un objeto Palette.
208
         * @param table
209
         */
210
        public void createPaletteFromGdalColorTable(GdalColorTable table) {
211
                try {
212
                        colorItems = new ArrayList();
213
                        for (int iEntry = 0; iEntry < table.getColorEntryCount(); iEntry++) {
214
                                GdalColorEntry entry = table.getColorEntryAsRGB(iEntry);
215

    
216
                                ColorItem colorItem = new ColorItem();
217
                                colorItem.setNameClass("");
218
                                colorItem.setValue(iEntry);
219
                                colorItem.setColor(new Color(        (int) (entry.c1 & 0xff),
220
                                                                                                                                                        (int) (entry.c2 & 0xff),
221
                                                                                                                                                        (int) (entry.c3 & 0xff),
222
                                                                                                                                                        (int) (entry.c4 & 0xff)));
223

    
224
                                colorItems.add(colorItem);
225
                        }
226
                } catch (GdalException ex) {
227
                        // No se crea la paleta
228
                }
229
                sortPalette();
230
                applyPalette();
231
        }
232

    
233
        /**
234
         * Obtiene la transparencia por rangos asociada a la tabla de color actual.
235
         * @return Lista de objetos TransparencyRange
236
         */
237
        public ArrayList getTransparencyRanges() {
238
                return transparencyRange;
239
        }
240

    
241
        /**
242
         * Carga una paleta desde el fichero .rmf asociado a la imagen
243
         * @param file nombre del fichero de imagen
244
         */
245
        public void loadPaletteFromRMF(String file) {
246
                //TODO: FUNCIONALIDAD: Implemetar cargar paleta desde .rmf
247
        }
248

    
249
        /**
250
         * Salva una paleta desde al fichero .rmf asociado a la imagen
251
         * @param file nombre del fichero de imagen
252
         */
253
        public void savePaletteToRMF(String file) {
254
                //TODO: FUNCIONALIDAD: Implemetar salvar paleta a .rmf
255
        }
256

    
257
        /**
258
         * Obtiene la tabla de color
259
         * @return Paleta
260
         */
261
/*
262
        public int[] getColorTable() {
263
                return palette;
264
        }
265
*/
266

    
267
        /**
268
         * Obtiene la tabla de color por banda
269
         * @return Paleta
270
         */
271
        public byte[][] getColorTableByBand() {
272
                return paletteByBand;
273
        }
274

    
275

    
276
        /**
277
         * Asigna una paleta
278
         * @param palette Paleta
279
         */
280
        public void setColorTable(int[] palette) {
281
                paletteByBand = new byte[palette.length][3];
282
                for (int i = 0; i < palette.length; i++) {
283
                        paletteByBand[i][0] = (byte)((palette[i] & 0x00ff0000) >> 16);
284
                        paletteByBand[i][1] = (byte)((palette[i] & 0x0000ff00) >> 8);
285
                        paletteByBand[i][2] = (byte)(palette[i] & 0x000000ff);
286
                }
287
        }
288

    
289
        /**
290
         * Obtiene los nombres de las clases de la paleta
291
         * @return Array de cadenas. Cada una corresponde con un nombre de clase
292
         * que corresponde a cada rango de tipos.
293
         */
294
        public String[] getNameClass() {
295
                return nameClass;
296
        }
297

    
298
        /**
299
         * Asigna los nombres de las clases de la paleta
300
         * @param names Array de cadenas. Cada una corresponde con un nombre de clase
301
         * que corresponde a cada rango de tipos.
302
         */
303
        public void setNameClass(String[] names) {
304
                nameClass = names;
305
        }
306

    
307
        /**
308
         * Obtiene la ruta del fichero al que va asociada la paleta.
309
         * @return Ruta del fichero al que va asociada la paleta.
310
         */
311
        public String getFilePath() {
312
                return filePath;
313
        }
314

    
315
        /**
316
         * Asigna la ruta del fichero al que va asociada la paleta.
317
         * @param Ruta del fichero al que va asociada la paleta.
318
         */
319
        public void setFilePath(String filePath) {
320
                this.filePath = filePath;
321
        }
322

    
323
        /**
324
         * Obtiene los rangos de transparencia que tiene la paleta. Estos se obtienen
325
         * en un array de objetos TransparencyRange. Cada uno de ellos representa un
326
         * rango de pixeles
327
         * @return ArrayList
328
         */
329
        public ArrayList getTransparencyRange() {
330
                return transparencyRange;
331
        }
332

    
333
        /*
334
         * (non-Javadoc)
335
         * @see java.lang.Object#clone()
336
         */
337
        public Object clone() {
338
                ColorTable clone = null;
339
                try {
340
                        clone = (ColorTable) super.clone();
341
                } catch (CloneNotSupportedException e) {
342
                }
343

    
344
                if (filePath != null)
345
                        clone.filePath = new String(filePath);
346

    
347
                if (name != null)
348
                        clone.name = new String(name);
349

    
350
                if (nameClass != null) {
351
                        clone.nameClass = new String[nameClass.length];
352
                        for (int i = 0; i < nameClass.length; i++)
353
                                clone.nameClass[i] = new String(nameClass[i]);
354
                }
355

    
356
                if (paletteByBand != null) {
357
                        clone.paletteByBand = (byte[][]) paletteByBand.clone();
358
                        for (int i = 0; i < paletteByBand.length; i++)
359
                                clone.paletteByBand[i] = (byte[]) paletteByBand[i].clone();
360
                }
361

    
362
                return clone;
363
        }
364

    
365
        /**
366
         * Devuelve un color de interpolacion entre dos colores
367
         * @param value
368
         * @param pos
369
         * @return
370
         */
371
        private Color interpolatedColor(double value, int pos) {
372
                if ((pos + 1) == colorItems.size())
373
                        return ((ColorItem) colorItems.get(pos)).getColor();
374

    
375
                ColorItem item1 = (ColorItem) colorItems.get(pos);
376
                ColorItem item2 = (ColorItem) colorItems.get(pos + 1);
377

    
378
                double percValue = ((value - item1.getValue()) * 100) / (item2.getValue() - item1.getValue());
379

    
380
                Color halfColor = new Color(
381
                                (item2.getColor().getRed() + item1.getColor().getRed()) >> 1,
382
                                (item2.getColor().getGreen() + item1.getColor().getGreen()) >> 1,
383
                                (item2.getColor().getBlue() + item1.getColor().getBlue()) >> 1,
384
                                (item2.getColor().getAlpha() + item1.getColor().getAlpha()) >> 1);
385

    
386
                Color color1, color2;
387
                int perc1, perc2;
388

    
389
                if (percValue > item1.getInterpolated()) {
390
                        color1 = halfColor;
391
                        color2 = item2.getColor();
392
                        perc1 = item1.getInterpolated();
393
                        perc2 = 100;
394
                } else {
395
                        color1 = item1.getColor();
396
                        color2 = halfColor;
397
                        perc1 = 0;
398
                        perc2 = item1.getInterpolated();
399
                }
400

    
401
                double percNew = (percValue - perc1) / (perc2 - perc1);
402

    
403
                Color newColor = new Color(
404
                                (int) (color1.getRed() + ((color2.getRed() - color1.getRed()) * percNew)) & 0xff,
405
                                (int) (color1.getGreen() + ((color2.getGreen() - color1.getGreen()) * percNew)) & 0xff,
406
                                (int) (color1.getBlue() + ((color2.getBlue() - color1.getBlue()) * percNew)) & 0xff,
407
                                (int) (color1.getAlpha() + ((color2.getAlpha() - color1.getAlpha()) * percNew)) & 0xff);
408

    
409

    
410
                return newColor;
411
        }
412

    
413
        /*
414
         * TODO: RENDIMIENTO: Incluir una heuristica que dado un valor se compare con el
415
         * valor de la mitad de la tabla y si es menor se empieza a recorrer desde el principio
416
         * sino se empieza a recorrer desde la mitad de la tabla hasta abajo. Esto hace
417
         * que se reduzca la tabla a la mitad de valores haciendo solo una comparaci?n.
418
         */
419
        /**
420
         * Obtiene el valor RGB para un clave entera pasada por par?metro
421
         * @param value clave de la cual se quiere obtener el valor RGB de la paleta
422
         * @return valor RGB
423
         */
424
        public byte[] getRGBByBand(double value) {
425
                int init = 1;
426
                for (int i = init; i <= range.length; i++) {
427
                        if (i < range.length) {
428
                                if (value < range[i])
429
                                        return paletteByBand[i - 1];
430
                        } else {
431
                                return paletteByBand[i - 1];
432
                        }
433
                }
434
                return new byte[4];
435
        }
436

    
437
        /**
438
         * Ordena el ColorItems de manera ascendente. De momento se usa el m?todo de
439
         * ordenaci?n por burbuja.
440
         */
441
        // TODO: Usar el m?todo Quicksort para ordenar
442
        private void sortPalette() {
443
                for (int i = 0; i < colorItems.size(); i++) {
444
                        for (int j = i + 1; j < colorItems.size(); j++) {
445
                                if (((ColorItem) colorItems.get(j)).getValue() < ((ColorItem) colorItems.get(i)).getValue()) {
446
                                        Object aux = colorItems.get(i);
447
                                        colorItems.set(i, colorItems.get(j));
448
                                        colorItems.set(j, aux);
449
                                }
450
                        }
451
                }
452
        }
453

    
454
        /**
455
         * Genera una paleta intermedia para acelerar los calculos.
456
         */
457
        private void applyPalette() {
458
                ArrayList arrayColors = new ArrayList();
459

    
460
                paletteByBand = new byte[0][3];
461
                range = new double[0];
462
                nameClass = new String[0];
463

    
464
                if (colorItems.size()==0)
465
                        return;
466

    
467
                // Nos preparamos para hacer las particiones, sabiendo el minimo y maximo
468
                double min = ((ColorItem) colorItems.get(0)).getValue();
469
                double max = ((ColorItem) colorItems.get(colorItems.size() - 1)).getValue();
470

    
471
                if (min > max) {
472
                        double aux = max;
473
                        max = min;
474
                        min = aux;
475
                }
476

    
477
                Color color = Color.white;
478
                Color colorOld = null;
479

    
480
                // Hacemos las particiones, metiendo cada item calculado en un array
481
                int defaultColors = RasterLibrary.defaultNumberOfColors;
482
                for (int i = 0; i < defaultColors; i++) {
483
                        double value = min + ((i * (max - min)) / (defaultColors - 1));
484

    
485
                        int pos = 0;
486
                        for (int j = 1; j <= colorItems.size(); j++) {
487
                                if (j < colorItems.size()) {
488
                                        if (value < ((ColorItem) colorItems.get(j)).getValue()) {
489
                                                pos = j - 1;
490
                                                break;
491
                                        }
492
                                } else {
493
                                        pos = j - 1;
494
                                        break;
495
                                }
496
                        }
497

    
498
                        // Calculamos el color que corresponde, tanto interpolado como no
499
                        if (interpolated)
500
                                color = interpolatedColor(value, pos);
501
                        else
502
                                color = ((ColorItem) colorItems.get(pos)).getColor();
503

    
504
                        if (!color.equals(colorOld)) {
505
                                ColorItem colorItem = new ColorItem();
506
                                colorItem.setNameClass("");
507
                                colorItem.setValue(value);
508
                                colorItem.setColor(color);
509
                                arrayColors.add(colorItem);
510
                        }
511

    
512
                        colorOld = color;
513
                }
514

    
515
                // Una vez tenemos una paleta de 256 colores o inferior, rellenamos
516
                // los siguientes valores para hacer busquedas rapidas.
517

    
518
                paletteByBand = new byte[arrayColors.size()][3];
519
                range = new double[arrayColors.size()];
520
                nameClass = new String[arrayColors.size()];
521

    
522
                transparencyRange.clear();
523
                for (int i = 0; i < arrayColors.size(); i++) {
524
                        paletteByBand[i][0] = (byte) ((ColorItem) arrayColors.get(i)).getColor().getRed();
525
                        paletteByBand[i][1] = (byte) ((ColorItem) arrayColors.get(i)).getColor().getGreen();
526
                        paletteByBand[i][2] = (byte) ((ColorItem) arrayColors.get(i)).getColor().getBlue();
527
                        range[i] = ((ColorItem) arrayColors.get(i)).getValue();
528
                        nameClass[i] = ((ColorItem) arrayColors.get(i)).getNameClass();
529
                        if (((ColorItem) arrayColors.get(i)).getColor().getAlpha() != 255) {
530
                                TransparencyRange r = new TransparencyRange();
531
                                r.setRed(new int[] { ((ColorItem) arrayColors.get(i)).getColor().getRed(), ((ColorItem) arrayColors.get(i)).getColor().getRed() });
532
                                r.setGreen(new int[] { ((ColorItem) arrayColors.get(i)).getColor().getGreen(), ((ColorItem) arrayColors.get(i)).getColor().getGreen() });
533
                                r.setBlue(new int[] { ((ColorItem) arrayColors.get(i)).getColor().getBlue(), ((ColorItem) arrayColors.get(i)).getColor().getBlue() });
534
                                r.setAlpha(((ColorItem) arrayColors.get(i)).getColor().getAlpha());
535
                                r.setAnd(true);
536
                                r.loadStrEntryFromValues();
537
                                transparencyRange.add(r);
538
                        }
539
                }
540
        }
541

    
542
        public double[] getRange() {
543
                return range;
544
        }
545

    
546
        public void setRange(double[] range) {
547
                this.range = range;
548
        }
549

    
550
        public ArrayList getColorItems() {
551
                return colorItems;
552
        }
553

    
554
        public boolean isInterpolated() {
555
                return interpolated;
556
        }
557

    
558
        public void setInterpolated(boolean interpolated) {
559
                this.interpolated = interpolated;
560
                applyPalette();
561
        }
562
}