Statistics
| Revision:

gvsig-raster / org.gvsig.raster / branches / org.gvsig.raster.2.4 / org.gvsig.raster / org.gvsig.raster.lib / org.gvsig.raster.lib.legend / org.gvsig.raster.lib.legend.impl / src / main / java / org / gvsig / raster / lib / legend / impl / DefaultRasterLegend.java @ 6069

History | View | Annotate | Download (18.1 KB)

1
package org.gvsig.raster.lib.legend.impl;
2

    
3
import java.awt.Graphics;
4
import java.awt.Image;
5
import java.awt.geom.AffineTransform;
6
import java.awt.geom.NoninvertibleTransformException;
7
import java.awt.image.BufferedImage;
8

    
9
import org.cresques.cts.ICoordTrans;
10
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
11
import org.gvsig.fmap.geom.GeometryLocator;
12
import org.gvsig.fmap.geom.exception.CreateGeometryException;
13
import org.gvsig.fmap.geom.primitive.Envelope;
14
import org.gvsig.fmap.geom.primitive.Point;
15
import org.gvsig.fmap.mapcontext.ViewPort;
16
import org.gvsig.raster.lib.buffer.api.Band;
17
import org.gvsig.raster.lib.buffer.api.Buffer;
18
import org.gvsig.raster.lib.buffer.api.FilterList;
19
import org.gvsig.raster.lib.buffer.api.exceptions.BufferException;
20
import org.gvsig.raster.lib.legend.api.ColorInterpretation;
21
import org.gvsig.raster.lib.legend.api.ColorTable;
22
import org.gvsig.raster.lib.legend.api.RasterLegend;
23
import org.gvsig.raster.lib.legend.api.Transparency;
24
import org.gvsig.tools.ToolsLocator;
25
import org.gvsig.tools.dynobject.DynStruct;
26
import org.gvsig.tools.persistence.PersistenceManager;
27
import org.gvsig.tools.persistence.PersistentState;
28
import org.gvsig.tools.persistence.exception.PersistenceException;
29
import org.gvsig.tools.task.SimpleTaskStatus;
30
import org.gvsig.tools.task.TaskStatusManager;
31
import org.slf4j.Logger;
32
import org.slf4j.LoggerFactory;
33

    
34
/**
35
 * Default implementation of {@link RasterLegend}. This object can draw buffers
36
 * with a {@link ColorInterpretation}, {@link ColorTable} and {@link FilterList}
37
 *
38
 *
39
 * @author <a href="mailto:lmarques@disid.com">Lluis Marques</a>
40
 *
41
 */
42
public class DefaultRasterLegend implements RasterLegend {
43

    
44
    private static final Logger LOG = LoggerFactory.getLogger(DefaultRasterLegend.class);
45

    
46
    private ColorInterpretation colorInterpretation;
47
    private ColorTable colorTable;
48
    private Transparency transparency;
49
    private FilterList filters;
50

    
51
    /**
52
     * Persistence definition name
53
     */
54
    public static final String PERSISTENT_NAME = "RasterLegendPersistence";
55
    /**
56
     * Description of persistence definition
57
     */
58
    public static final String PERSISTENT_DESCRIPTION = "Persistence definition of raster legend";
59

    
60
    private final static String COLOR_TABLE_PERSISTENCE_FIELD = "colorTable";
61
    private final static String COLOR_INTERPRETATION_PERSISTENCE_FIELD = "colorInterpretation";
62
    private final static String FILTERS_PERSISTENCE_FIELD = "filters";
63

    
64
    /**
65
     * Empty constructor
66
     */
67
    public DefaultRasterLegend() {
68

    
69
    }
70

    
71
    /**
72
     * Default {@link RasterLegend} constructor
73
     *
74
     * @param colorInterpretation
75
     *            Color interpretation of legend
76
     */
77
    public DefaultRasterLegend(ColorInterpretation colorInterpretation) {
78
        this.colorInterpretation = colorInterpretation;
79
    }
80

    
81
    /**
82
     * Default {@link RasterLegend} constructor
83
     *
84
     * @param colorTable
85
     *            Color table of legend
86
     * @param colorInterpretation
87
     *            Color interpretation of legend
88
     * @param transparency
89
     *            Transparency of legend
90
     * @param filters
91
     *            Filters of legend
92
     */
93
    public DefaultRasterLegend(ColorInterpretation colorInterpretation, ColorTable colorTable,
94
        Transparency transparency, FilterList filters) {
95
        this.colorInterpretation = colorInterpretation;
96
        this.colorTable = colorTable;
97
        this.transparency = transparency;
98
        this.filters = filters;
99
    }
100

    
101
    @Override
102
    public void draw(Graphics graphics, Buffer buffer, ViewPort viewPort,
103
        SimpleTaskStatus taskStatus) {
104

    
105
        boolean isMyTask = false;
106
        if (taskStatus == null) {
107
            TaskStatusManager taskStatusManager = ToolsLocator.getTaskStatusManager();
108
            taskStatus =
109
                taskStatusManager.createDefaultSimpleTaskStatus("_drawing_buffer_XxellipsisxX");
110
            taskStatus.setAutoremove(true);
111
            taskStatus.add();
112
            isMyTask = true;
113
        } else {
114
            taskStatus.push();
115
        }
116

    
117
        taskStatus.setIndeterminate();
118

    
119
        if (this.colorInterpretation == null || !this.colorInterpretation.hasInterpretation()
120
            || this.colorInterpretation.isUndefined()) {
121
            taskStatus.abort();
122
            throw new IllegalStateException(
123
                "To draw buffer, raster legend has to have a color interpretation");
124
        }
125

    
126
        if ((this.colorInterpretation.isRGB() || this.colorInterpretation.isBGR() || this.colorInterpretation
127
            .isRGBA()) && this.colorTable != null) {
128
            taskStatus.abort();
129
            throw new IllegalStateException(
130
                "If color interpretation is RGB, RGBA or BGR, raster legend can not have a color table");
131
        }
132

    
133
        // Check if viewport projection is the same as buffer projection
134
        Buffer bufferToDraw = null;
135
        if (!viewPort.getProjection().equals(buffer.getProjection())) {
136

    
137
            // Convert extension to check if envelopes intersect
138
            ICoordTrans coordTrans = viewPort.getProjection().getCT(buffer.getProjection());
139
            Envelope convertedEnvelope = viewPort.getEnvelope().convert(coordTrans);
140
            if (!convertedEnvelope.intersects(buffer.getEnvelope())) {
141
                return;
142
            }
143
            try {
144
                // Clip buffer with doubled converted envelope
145
                bufferToDraw = buffer.clip(convertedEnvelope);
146

    
147
                // Convert interpolated clipped buffer
148
                bufferToDraw = bufferToDraw.convert(coordTrans.getInverted(), taskStatus);
149

    
150
                double widthPixel =
151
                    getWidthPixel(bufferToDraw.getEnvelope(), viewPort.getEnvelope().getLength(0)
152
                        / viewPort.getImageWidth());
153
                double heightPixel =
154
                    getHeightPixel(bufferToDraw.getEnvelope(), viewPort.getEnvelope().getLength(1)
155
                        / viewPort.getImageHeight());
156

    
157
                bufferToDraw =
158
                    bufferToDraw.createInterpolated((int) Math.floor(heightPixel),
159
                        (int) Math.floor(widthPixel), Buffer.INTERPOLATION_BicubicSpline,
160
                        taskStatus);
161

    
162
            } catch (BufferException e) {
163
                LOG.warn("Buffer can not be clipped, converted or interpolated", e);
164
                taskStatus.abort();
165
                return;
166
            }
167
        } else if (viewPort.getEnvelope().intersects(buffer.getEnvelope())) {
168

    
169
            double widthPixel = 0;
170
            double heightPixel = 0;
171
            try {
172
                // Clip and interpolate buffer with view port envelope
173
                bufferToDraw = buffer.clip(viewPort.getEnvelope());
174
                widthPixel =
175
                    getWidthPixel(bufferToDraw.getEnvelope(), viewPort.getEnvelope().getLength(0)
176
                        / viewPort.getImageWidth());
177
                heightPixel =
178
                    getHeightPixel(bufferToDraw.getEnvelope(), viewPort.getEnvelope().getLength(1)
179
                        / viewPort.getImageHeight());
180

    
181
                bufferToDraw =
182
                    bufferToDraw.createInterpolated((int) Math.floor(heightPixel),
183
                        (int) Math.floor(widthPixel), Buffer.INTERPOLATION_NearestNeighbour,
184
                        taskStatus);
185
            } catch (BufferException e) {
186
                LOG.warn(
187
                    "Buffer can not be interpolated with [rows: {} , columns: {}, method: {}]",
188
                    new String[] { String.valueOf((int) Math.floor(heightPixel)),
189
                        String.valueOf((int) Math.floor(widthPixel)),
190
                        String.valueOf(Buffer.INTERPOLATION_NearestNeighbour) });
191
                taskStatus.abort();
192
                return;
193
            }
194
        } else {
195
            // Do nothing view port envelope does not intersect with buffer
196
            return;
197
        }
198

    
199
        // Draw buffer
200
        Image image = null;
201
        if (this.colorInterpretation.isGray() && this.colorTable != null) {
202

    
203
            // Draw buffer with table color
204
            image = drawBuffer(graphics, bufferToDraw, colorTable, transparency, filters);
205

    
206
        } else if (this.colorInterpretation.isRGBA() || this.colorInterpretation.isRGB()
207
            || this.colorInterpretation.isBGR()) {
208

    
209
            // Draw RGB, RGBA or BGR buffer without color table
210
            image = drawBuffer(graphics, bufferToDraw, colorInterpretation, transparency, filters);
211
        }
212

    
213
        // Calculate where image has to be drawn
214
        double x = bufferToDraw.getEnvelope().getMinimum(0);
215
        double y = bufferToDraw.getEnvelope().getMaximum(1);
216
        AffineTransform affineTransform =
217
            calculateAffineTransform(viewPort.getEnvelope(), viewPort.getImageWidth(),
218
                viewPort.getImageHeight());
219

    
220
        Point point;
221
        try {
222
            point = GeometryLocator.getGeometryManager().createPoint(x, y, SUBTYPES.GEOM2D);
223
            point.transform(affineTransform.createInverse());
224
            graphics.drawImage(image, (int) Math.floor(point.getX()),
225
                (int) Math.floor(point.getY()), null);
226
        } catch (CreateGeometryException | NoninvertibleTransformException e) {
227
            LOG.warn("Can not calculate the point of buffer in viewport image", e);
228
            taskStatus.abort();
229
            return;
230
        }
231

    
232
        if (!isMyTask) {
233
            taskStatus.pop();
234
        }
235
    }
236

    
237
    private AffineTransform calculateAffineTransform(Envelope envelope, double imageWidth,
238
        double imageHeight) {
239
        double pixelSizeX = envelope.getLength(0) / imageWidth;
240
        double rotationX = 0;
241
        double x = envelope.getMinimum(0);
242
        double rotationY = 0;
243
        double pixelSizeY = -envelope.getLength(1) / imageHeight;
244
        double y = envelope.getMaximum(1);
245
        return new AffineTransform(pixelSizeX, rotationY, rotationX, pixelSizeY, x, y);
246
    }
247

    
248
    private double getWidthPixel(Envelope envelope, double dist1pixel) {
249
        double widthEnvelope = envelope.getLength(0);
250
        return widthEnvelope / dist1pixel;
251
    }
252

    
253
    private double getHeightPixel(Envelope envelope, double dist1pixel) {
254
        double heightEnvelope = envelope.getLength(1);
255
        return heightEnvelope / dist1pixel;
256
    }
257

    
258
    private Image drawBuffer(Graphics graphics, Buffer buffer,
259
        ColorInterpretation colorInterpretation, Transparency transparency, FilterList filters) {
260

    
261
        BufferedImage image = null;
262

    
263
        if (colorInterpretation.isRGB() || colorInterpretation.isRGBA()) {
264
            image =
265
                new BufferedImage(buffer.getColumns(), buffer.getRows(),
266
                    BufferedImage.TYPE_INT_ARGB);
267
        } else if (colorInterpretation.isBGR()) {
268
            image =
269
                new BufferedImage(buffer.getColumns(), buffer.getRows(), BufferedImage.TYPE_INT_BGR);
270
        }
271

    
272
        if (image == null) {
273
            throw new IllegalStateException(
274
                "Color interpretation is not RGB,RGBA or BGR and buffer was be drawn without color table");
275
        }
276

    
277
        for (int i = 0; i < buffer.getRows(); i++) {
278
            for (int j = 0; j < buffer.getColumns(); j++) {
279
                //TODO Review this bucle
280
                int redBandIndex = colorInterpretation.getBand(ColorInterpretation.RED_BAND);
281
                int greenBandIndex = colorInterpretation.getBand(ColorInterpretation.GREEN_BAND);
282
                int blueBandIndex = colorInterpretation.getBand(ColorInterpretation.BLUE_BAND);
283

    
284
                Band redBand = buffer.getBand(redBandIndex);
285
                Band greenBand = buffer.getBand(greenBandIndex);
286
                Band blueBand = buffer.getBand(blueBandIndex);
287
                Band alphaBand = null;
288
                if (colorInterpretation.hasAlphaBand()) {
289
                    int alphaBandIndex =
290
                        colorInterpretation.getBand(ColorInterpretation.ALPHA_BAND);
291
                    alphaBand = buffer.getBand(alphaBandIndex);
292
                }
293

    
294
                Number redValue = (Number) redBand.get(i, j);
295
                Number blueValue = (Number) blueBand.get(i, j);
296
                Number greenValue = (Number) greenBand.get(i, j);
297
                Number alphaValue = 255;
298
                if (alphaBand != null) {
299
                    alphaValue = (Number) alphaBand.get(i, j);
300
                }
301

    
302
                if (transparency != null) {
303
                    // Apply defined transparency ranges
304

    
305
                    alphaValue = alphaValue.byteValue() & 0xFF;
306
                    int newAlpha =
307
                        transparency.getTransparencyRangeAlpha(redValue.byteValue(),
308
                            blueValue.byteValue(), greenValue.byteValue());
309
                    alphaValue = getNewAlpha(alphaValue.intValue(), newAlpha);
310

    
311
                    // Apply general transparency
312
                    int transparencyValue = transparency.getAlpha();
313
                    alphaValue = getNewAlpha(alphaValue.intValue(), transparencyValue);
314
                }
315

    
316
                if (filters != null) {
317
                    // TODO Apply filters
318
                }
319

    
320
                int intRGB = 0;
321
                if (colorInterpretation.isRGB() || colorInterpretation.isRGBA()) {
322
                    intRGB = ((alphaValue.byteValue() & 0xFF) << 24) | // red
323
                        ((redValue.byteValue() & 0xFF) << 16) | // red
324
                        ((greenValue.byteValue() & 0xFF) << 8) | // green
325
                        ((blueValue.byteValue() & 0xFF) << 0); // blue
326
                } else if (colorInterpretation.isBGR()) {
327
                    intRGB = ((blueValue.byteValue() & 0xFF) << 16 | // blue
328
                        ((greenValue.byteValue() & 0xFF) << 8) | // green
329
                        ((redValue.byteValue() & 0xFF) << 0)); // red
330

    
331
                }
332
                image.setRGB(j, i, intRGB);
333
            }
334
        }
335
        return image;
336
    }
337

    
338
    private Image drawBuffer(Graphics graphics, Buffer buffer, ColorTable colorTable,
339
        Transparency transparency, FilterList filters) {
340

    
341
        BufferedImage image =
342
            new BufferedImage(buffer.getColumns(), buffer.getRows(), BufferedImage.TYPE_INT_ARGB);
343

    
344
        for (int i = 0; i < buffer.getRows(); i++) {
345
            for (int j = 0; j < buffer.getColumns(); j++) {
346

    
347
                Object value = buffer.getBand(0).get(i, j);
348
                byte[] rgba = colorTable.getRGBA(value);
349

    
350
                if (transparency != null) {
351
                    // Apply defined transparency ranges
352
                    int alpha = rgba[3] & 0xFF;
353
                    int newAlpha =
354
                        transparency.getTransparencyRangeAlpha(rgba[0], rgba[1], rgba[2]);
355
                    alpha = getNewAlpha(alpha, newAlpha);
356

    
357
                    // Apply general transparency
358
                    int transparencyValue = transparency.getAlpha();
359
                    rgba[3] = (byte) getNewAlpha(alpha, transparencyValue);
360
                }
361

    
362
                if (filters != null) {
363
                    // TODO Apply filters
364
                }
365

    
366
                int intARGB = ((rgba[3] & 0xFF) << 24) | // alpha
367
                    ((rgba[0] & 0xFF) << 16) | // red
368
                    ((rgba[1] & 0xFF) << 8) | // green
369
                    ((rgba[2] & 0xFF) << 0); // blue
370

    
371
                image.setRGB(j, i, intARGB);
372
            }
373
        }
374
        return image;
375
    }
376

    
377
    private int getNewAlpha(int alpha, int newAlpha) {
378
        return (int) Math.round(alpha * (newAlpha / 255d));
379
    }
380

    
381
    public ColorTable getColorTable() {
382
        return this.colorTable;
383
    }
384

    
385
    @Override
386
    public void setColorTable(ColorTable colorTable) {
387
        ColorInterpretation colorInterpretation = this.getColorInterpretation();
388

    
389
        if (colorInterpretation != null
390
            && (colorInterpretation.isRGB() || colorInterpretation.isBGR() || colorInterpretation
391
                .isRGBA())) {
392
            throw new IllegalArgumentException(
393
                "Can not set color table when color interpretation is RGB, BGR or RGBA");
394
        }
395

    
396
        this.colorTable = colorTable;
397
    }
398

    
399
    @Override
400
    public ColorInterpretation getColorInterpretation() {
401
        return this.colorInterpretation;
402
    }
403

    
404
    @Override
405
    public void setColorInterpretation(ColorInterpretation colorInterpretation) {
406

    
407
        if (this.colorTable != null
408
            && (colorInterpretation.isRGB() || colorInterpretation.isBGR() || colorInterpretation
409
                .isRGBA())) {
410
            throw new IllegalArgumentException(
411
                "Can not set color interpreation RGB, RGBA or BGR if legend has a color table specifed");
412
        }
413

    
414
        this.colorInterpretation = colorInterpretation;
415
    }
416

    
417
    @Override
418
    public FilterList getFilters() {
419
        return this.filters;
420
    }
421

    
422
    @Override
423
    public void setFilters(FilterList filterList) {
424
        this.filters = filterList;
425
    }
426

    
427
    public static void registerDefinition() {
428
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
429
        DynStruct definition = manager.getDefinition(PERSISTENT_NAME);
430
        if (definition == null) {
431
            definition =
432
                manager.addDefinition(DefaultRasterLegend.class, PERSISTENT_NAME,
433
                    PERSISTENT_DESCRIPTION, null, null);
434
            definition.addDynField(COLOR_TABLE_PERSISTENCE_FIELD).setMandatory(false)
435
                .setClassOfValue(ColorTable.class);
436
            definition.addDynField(COLOR_INTERPRETATION_PERSISTENCE_FIELD).setMandatory(false)
437
                .setClassOfValue(ColorInterpretation.class);
438
            definition.addDynField(FILTERS_PERSISTENCE_FIELD).setMandatory(false)
439
                .setClassOfValue(FilterList.class);
440
        }
441
    }
442

    
443
    @Override
444
    public void saveToState(PersistentState state) throws PersistenceException {
445
        state.set(COLOR_TABLE_PERSISTENCE_FIELD, this.getColorTable());
446
        state.set(COLOR_INTERPRETATION_PERSISTENCE_FIELD, this.getColorInterpretation());
447
        state.set(FILTERS_PERSISTENCE_FIELD, this.filters);
448
    }
449

    
450
    @Override
451
    public void loadFromState(PersistentState state) throws PersistenceException {
452
        this.setColorTable((ColorTable) state.get(COLOR_TABLE_PERSISTENCE_FIELD));
453
        this.setColorInterpretation((ColorInterpretation) state
454
            .get(COLOR_INTERPRETATION_PERSISTENCE_FIELD));
455
        this.setFilters((FilterList) state.get(FILTERS_PERSISTENCE_FIELD));
456
    }
457

    
458
}