Statistics
| Revision:

gvsig-raster / org.gvsig.raster / branches / org.gvsig.raster.2.4 / org.gvsig.raster / org.gvsig.raster.lib / org.gvsig.raster.lib.buffer / org.gvsig.raster.lib.buffer.impl / src / main / java / org / gvsig / raster / lib / buffer / impl / AbstractBuffer.java @ 6493

History | View | Annotate | Download (20.6 KB)

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

    
3
import java.awt.geom.AffineTransform;
4
import java.awt.geom.NoninvertibleTransformException;
5
import java.util.ArrayList;
6
import java.util.Iterator;
7
import java.util.List;
8

    
9
import org.cresques.cts.ICoordTrans;
10
import org.cresques.cts.IProjection;
11

    
12
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
13
import org.gvsig.fmap.geom.Geometry.TYPES;
14
import org.gvsig.fmap.geom.GeometryLocator;
15
import org.gvsig.fmap.geom.exception.CreateGeometryException;
16
import org.gvsig.fmap.geom.operation.GeometryOperationException;
17
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
18
import org.gvsig.fmap.geom.primitive.Envelope;
19
import org.gvsig.fmap.geom.primitive.Point;
20
import org.gvsig.raster.lib.buffer.api.Band;
21
import org.gvsig.raster.lib.buffer.api.Band.BandByte;
22
import org.gvsig.raster.lib.buffer.api.Band.BandDouble;
23
import org.gvsig.raster.lib.buffer.api.Band.BandFloat;
24
import org.gvsig.raster.lib.buffer.api.Band.BandInt;
25
import org.gvsig.raster.lib.buffer.api.Band.BandShort;
26
import org.gvsig.raster.lib.buffer.api.BandNotification;
27
import org.gvsig.raster.lib.buffer.api.Buffer;
28
import org.gvsig.raster.lib.buffer.api.BufferLocator;
29
import org.gvsig.raster.lib.buffer.api.BufferManager;
30
import org.gvsig.raster.lib.buffer.api.BufferNotification;
31
import org.gvsig.raster.lib.buffer.api.FilterList;
32
import org.gvsig.raster.lib.buffer.api.NoData;
33
import org.gvsig.raster.lib.buffer.api.exceptions.BandException;
34
import org.gvsig.raster.lib.buffer.api.exceptions.BufferException;
35
import org.gvsig.raster.lib.buffer.api.statistics.Statistics;
36
import org.gvsig.raster.lib.buffer.impl.statistics.DefaultStatistics;
37
import org.gvsig.tools.ToolsLocator;
38
import org.gvsig.tools.exception.BaseException;
39
import org.gvsig.tools.locator.LocatorException;
40
import org.gvsig.tools.observer.Notification;
41
import org.gvsig.tools.observer.Observable;
42
import org.gvsig.tools.observer.impl.BaseWeakReferencingObservable;
43
import org.gvsig.tools.task.SimpleTaskStatus;
44

    
45
import org.slf4j.Logger;
46
import org.slf4j.LoggerFactory;
47

    
48

    
49
/**
50
 * @author fdiaz
51
 *
52
 */
53
public abstract class AbstractBuffer extends BaseWeakReferencingObservable implements Buffer {
54

    
55
    protected static final Logger logger = LoggerFactory.getLogger(AbstractBuffer.class);
56

    
57
    protected List<Band> bands;
58
    protected int rows;
59
    protected int columns;
60
    protected FilterList filters;
61
    protected Envelope envelope;
62
    protected IProjection projection;
63
    protected Statistics statistics;
64
    private Double pixelSizeX = null;
65
    private Double pixelSizeY = null;
66

    
67
//    // to make disposable
68
//    private final Object lock = new Object();
69
//    private boolean disposed = false;
70

    
71
//    public AbstractBuffer() {
72
//        if(ToolsLocator.getDisposableManager() != null) {
73
//            ToolsLocator.getDisposableManager().bind(this);
74
//        } else {
75
//            logger.warn("Can't retrieve the disposable manager,");
76
//        }
77
//    }
78

    
79
    @Override
80
    public Statistics getStatistics(SimpleTaskStatus status) {
81
        if (statistics == null) {
82
            statistics = new DefaultStatistics(bands);
83
            // this.addObserver(statistics);
84
        }
85
        if (!statistics.isCalculated()) {
86
            statistics.calculate(status); // scale ???
87
        }
88
        return statistics;
89
    }
90

    
91
    @Override
92
    public Iterator<Band> iterator() {
93
        return bands.iterator();
94
    }
95

    
96
    @Override
97
    public void update(Observable observable, Object notification) {
98
        if (notification instanceof BandNotification && observable instanceof Band) {
99
            Notification bandNotification = (Notification) notification;
100
            if (bandNotification.getType().equals(BandNotification.COPY_FROM)
101
                || bandNotification.getType().equals(BandNotification.FILL)
102
                || bandNotification.getType().equals(BandNotification.PUT_ROW)
103
                || bandNotification.getType().equals(BandNotification.SET)) {
104
                this.statistics = null;
105
                this.notifyObservers(new DefaultBufferNotification(BufferNotification.CHANGE_BAND,
106
                    new Object[] { observable }));
107
            }
108
        }
109
    }
110

    
111
    @Override
112
    public void filter(FilterList filterList) {
113
        this.filters = filterList;
114
    }
115

    
116
    @Override
117
    public int getBandCount() {
118
        return bands.size();
119
    }
120

    
121
    @Override
122
    public Band[] getBands() {
123
        Band[] arrayBands = new Band[bands.size()];
124
        return bands.toArray(arrayBands);
125
    }
126

    
127
    @Override
128
    public int getColumns() {
129
        return this.columns;
130
    }
131

    
132
    @Override
133
    public int getRows() {
134
        return this.rows;
135
    }
136

    
137
    @Override
138
    public Envelope getEnvelope() {
139
        return this.envelope;
140
    }
141

    
142
    @Override
143
    public IProjection getProjection() {
144
        return this.projection;
145
    }
146

    
147
    @Override
148
    public boolean isInside(int cellX, int cellY) {
149
        return (cellX >= 0 && cellX < this.columns && cellY >= 0 && cellY < this.rows);
150
    }
151

    
152
    @Override
153
    public boolean isInside(Point point) {
154

    
155
        if (getEnvelope() == null) {
156
            return false;
157
        }
158

    
159
        try {
160
            return getEnvelope().getGeometry().contains(point);
161
        } catch (GeometryOperationNotSupportedException | GeometryOperationException e) {
162
            logger.warn("It could not determine if the point is on the envelope", e);
163
            return false;
164
        }
165
    }
166

    
167
    @Override
168
    public void addBand(Band band) {
169

    
170
        if (band.getColumns() != this.getColumns() || band.getRows() != this.getRows()) {
171
            throw new IllegalArgumentException(
172
                "Can not add band to buffer. Band must have the same rows and columns as buffer.");
173
        }
174

    
175
        this.bands.add(band);
176
        band.addObserver(this);
177
        this.statistics = null;
178
        this.notifyObservers(new DefaultBufferNotification(BufferNotification.ADD_BAND, new Object[] { band }));
179
    }
180

    
181
    @Override
182
    public void setBand(int pos, Band band) throws BandException {
183
        this.bands.get(pos).copyFrom(band);
184
        this.statistics = null;
185
        this.notifyObservers(new DefaultBufferNotification(BufferNotification.SET_BAND, new Object[] { pos, band }));
186
    }
187

    
188
    @Override
189
    public void removeBand(int pos) {
190
        Band band = this.bands.get(pos);
191
        band.deleteObserver(this);
192
        this.bands.remove(pos);
193
        this.statistics = null;
194
        this.notifyObservers(new DefaultBufferNotification(BufferNotification.REMOVE_BAND, new Object[] { pos }));
195
    }
196

    
197
    @Override
198
    public Band getBand(int pos) {
199
        return this.bands.get(pos);
200
    }
201

    
202
    @Override
203
    public BandByte getBandByte(int pos) {
204
        if (this.bands.get(pos).getDataType() != BufferManager.TYPE_BYTE) {
205
            throw new IllegalArgumentException(String.format("Band in position %1s is type of %2s", pos, this.bands
206
                .get(pos).getDataType()));
207
        }
208
        return (BandByte) this.bands.get(pos);
209
    }
210

    
211
    @Override
212
    public BandShort getBandShort(int pos) {
213
        if (this.bands.get(pos).getDataType() != BufferManager.TYPE_SHORT) {
214
            throw new IllegalArgumentException(String.format("Band in position %1s is type of %2s", pos, this.bands
215
                .get(pos).getDataType()));
216
        }
217
        return (BandShort) this.bands.get(pos);
218
    }
219

    
220
    @Override
221
    public BandInt getBandInt(int pos) {
222
        if (this.bands.get(pos).getDataType() != BufferManager.TYPE_INT) {
223
            throw new IllegalArgumentException(String.format("Band in position %1s is type of %2s", pos, this.bands
224
                .get(pos).getDataType()));
225
        }
226
        return (BandInt) this.bands.get(pos);
227

    
228
    }
229

    
230
    @Override
231
    public BandFloat getBandFloat(int pos) {
232
        if (this.bands.get(pos).getDataType() != BufferManager.TYPE_FLOAT) {
233
            throw new IllegalArgumentException(String.format("Band in position %1s is type of %2s", pos, this.bands
234
                .get(pos).getDataType()));
235
        }
236
        return (BandFloat) this.bands.get(pos);
237

    
238
    }
239

    
240
    @Override
241
    public BandDouble getBandDouble(int pos) {
242
        if (this.bands.get(pos).getDataType() != BufferManager.TYPE_DOUBLE) {
243
            throw new IllegalArgumentException(String.format("Band in position %1s is type of %2s", pos, this.bands
244
                .get(pos).getDataType()));
245
        }
246
        return (BandDouble) this.bands.get(pos);
247

    
248
    }
249

    
250
    @Override
251
    public void switchBands(int[] positions) {
252
        List<Integer> visited = new ArrayList<Integer>();
253
        if (positions.length != this.getBandCount()) {
254
            throw new IllegalArgumentException("Position array length has to be the same as band count");
255
        }
256
        for (int i = 0; i < positions.length; i++) {
257
            Integer position = new Integer(positions[i]);
258
            if (visited.contains(position)) {
259
                throw new IllegalArgumentException(String.format(
260
                    "Position array can not have duplicated bands. Duplicated value: %1s", position));
261
            }
262
            visited.add(position);
263
        }
264

    
265
        List<Band> auxBands = new ArrayList<Band>(bands.size());
266
        for (int i = 0; i < visited.size(); i++) {
267
            auxBands.add(bands.get(visited.get(i)));
268
        }
269
        bands = auxBands;
270
        this.statistics = null;
271
        this.notifyObservers(new DefaultBufferNotification(BufferNotification.SWITCH_BAND, new Object[] { positions }));
272
    }
273

    
274
    @Override
275
    public void switchBands(int pos1, int pos2) {
276
        Band auxBand = bands.get(pos1);
277
        bands.set(pos1, bands.get(pos2));
278
        bands.set(pos2, auxBand);
279
        this.statistics = null;
280
        this.notifyObservers(new DefaultBufferNotification(BufferNotification.SWITCH_BAND, new Object[] { pos1, pos2 }));
281
    }
282

    
283
    @Override
284
    public Buffer createInterpolated(int rows, int columns, int interpolationMode, SimpleTaskStatus status)
285
        throws BufferException {
286
        if(rows==0 || columns==0){
287
            return null;
288
        }
289

    
290
        try {
291
            if (rows == getRows() && columns == getColumns()) {
292
                return (Buffer) this.clone();
293
            }
294

    
295
            Buffer target =
296
                BufferLocator.getBufferManager().createBuffer(rows, columns, this.getBandTypes(),
297
                    this.getBandNoData(), this.getProjection(), this.getEnvelope(), null);
298
            BufferInterpolation interp = new BufferInterpolation();
299
            switch (interpolationMode) {
300
            case Buffer.INTERPOLATION_NearestNeighbour:
301
                interp.nearestNeighbourInterpolation(this, target, status);
302
                break;
303
            case Buffer.INTERPOLATION_Bilinear:
304
                interp.bilinearInterpolation(this, target, status);
305
                break;
306
            case Buffer.INTERPOLATION_InverseDistance:
307
                interp.inverseDistanceInterpolation(this, target, status);
308
                break;
309
            case Buffer.INTERPOLATION_BicubicSpline:
310
                interp.bicubicSplineInterpolation(this, target, status);
311
                break;
312
            case Buffer.INTERPOLATION_BSpline:
313
                interp.bSplineInterpolation(this, target, status);
314
                break;
315
            }
316
            return target;
317
        } catch (CloneNotSupportedException | LocatorException e) {
318
            throw new BufferException(e);
319
        }
320
    }
321

    
322
    @Override
323
    public Buffer convert(ICoordTrans ct, SimpleTaskStatus status) throws BufferException {
324

    
325
        if (this.getEnvelope() == null) {
326
            throw new IllegalStateException("Buffer envelope is null. A buffer allways has to have envelope");
327
        }
328

    
329
        boolean isMyStatus = false;
330
        if (status == null) {
331
            status =
332
                ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus(
333
                    String.format("Projecting buffer from %1s to %2s", ct.getPOrig().getAbrev(), ct.getPDest()
334
                        .getAbrev()));
335
            status.add();
336
            isMyStatus = true;
337
        } else {
338
            status.push();
339
        }
340

    
341
        Envelope projectedBufferEnvelope = this.getEnvelope().convert(ct);
342
        // Get size of new buffer
343
        double[] newsize = getSize(this.getEnvelope(), projectedBufferEnvelope, this.getColumns(), this.getRows());
344
        int projectedBufferColumns = (int) newsize[0];
345
        int projectedBufferRows = (int) newsize[1];
346

    
347
        int[] bandDataTypes = this.getBandTypes();
348
        NoData[] bandNoData = this.getBandNoData();
349

    
350
        status.message("Creating projected buffer");
351
        Buffer projectedBuffer =
352
            BufferLocator.getBufferManager().createBuffer(projectedBufferRows, projectedBufferColumns, bandDataTypes,
353
                bandNoData, ct.getPDest(), projectedBufferEnvelope);
354

    
355
        // This affine transform allow us to convert pixel to coordinate and inverse
356
        AffineTransform bufferAf = calculateAffineTransform(this.getEnvelope(), this.getRows(), this.getColumns());
357
        AffineTransform projectedBufferAf =
358
            calculateAffineTransform(projectedBufferEnvelope, projectedBufferRows, projectedBufferColumns);
359

    
360
        ICoordTrans invertedCt = ct.getInverted();
361
        AffineTransform inverseBufferAf;
362
        try {
363
            inverseBufferAf = bufferAf.createInverse();
364
        } catch (NoninvertibleTransformException e1) {
365
            status.abort();
366
            logger.error("Can not create inverse transformation of {}", bufferAf);
367
            throw new BufferException(e1);
368
        }
369

    
370
        status.setRangeOfValues(0,
371
            projectedBuffer.getRows() * projectedBuffer.getColumns() * projectedBuffer.getBandCount());
372
        status.message("Projecting buffer");
373

    
374
        Point point;
375
        try {
376
            point = (Point) GeometryLocator.getGeometryManager().create(TYPES.POINT, SUBTYPES.GEOM2D);
377
        } catch (CreateGeometryException | LocatorException e1) {
378
            status.abort();
379
            logger.error("Can not create point geometry to project buffer");
380
           throw new BufferException(e1);
381
        }
382
        for (int row = 0; row < projectedBuffer.getRows(); row++) {
383

    
384
            if (status.isCancellationRequested()) {
385
                status.cancel();
386
                return projectedBuffer;
387
            }
388

    
389
            for (int col = 0; col < projectedBuffer.getColumns(); col++) {
390
                point.setX(col);
391
                point.setY(row);
392

    
393
                point.transform(projectedBufferAf); // projected buffer
394
                                                    // pixel to world point
395
                                                    // (target projection)
396
                point.reProject(invertedCt); // projected world point
397
                                             // to world point (source
398
                                             // projection)
399
                point.transform(inverseBufferAf); // world point to
400
                                                  // pixel source
401
                                                  // buffer
402

    
403
                double floorPointX = Math.floor(point.getX());
404
                double floorPointY = Math.floor(point.getY());
405
                boolean isValidPoint =
406
                    point.getX() >= 0 && floorPointX < this.getColumns() && point.getY() >= 0
407
                        && floorPointY < this.getRows();
408

    
409
                for (int k = 0; k < this.getBandCount(); k++) {
410

    
411
                    status.setCurValue(row * col * k);
412
                    Band band = this.bands.get(k);
413
                    Number value = null;
414
                    if (isValidPoint) {
415
                        value = (Number) band.get((int) floorPointY, (int) floorPointX);
416
                    } else if (band.getNoData().isDefined()) {
417
                        value = band.getNoData().getValue();
418
                    } else {
419
                        continue;
420
                    }
421

    
422
                    Band projectedBand = projectedBuffer.getBand(k);
423
                    int dataType = projectedBand.getDataType();
424
                    switch (dataType) {
425
                    case BufferManager.TYPE_BYTE:
426
                        projectedBand.set(row, col, value.byteValue());
427
                        break;
428
                    case BufferManager.TYPE_SHORT:
429
                        projectedBand.set(row, col, value.shortValue());
430
                        break;
431
                    case BufferManager.TYPE_INT:
432
                        projectedBand.set(row, col, value.intValue());
433
                        break;
434
                    case BufferManager.TYPE_FLOAT:
435
                        projectedBand.set(row, col, value.floatValue());
436
                        break;
437
                    case BufferManager.TYPE_DOUBLE:
438
                        projectedBand.set(row, col, value.doubleValue());
439
                        break;
440
                    default:
441
                        break;
442
                    }
443
                }
444

    
445
            }
446
        }
447

    
448
        if (isMyStatus) {
449
            status.terminate();
450
        } else {
451
            status.pop();
452
        }
453
        return projectedBuffer;
454
    }
455

    
456
    private double[] getSize(Envelope envelope, Envelope projectedEnvelope, int p1x, int p1y) {
457
        double sumSideOldBBox = envelope.getLength(0) + envelope.getLength(1);
458
        double sumSideNewBBox = projectedEnvelope.getLength(0) + projectedEnvelope.getLength(1);
459
        double d1x = (envelope.getLength(0) * 100) / sumSideOldBBox;
460
        double d1y = (envelope.getLength(1) * 100) / sumSideOldBBox;
461
        double d2x = (projectedEnvelope.getLength(0) * 100) / sumSideNewBBox;
462
        double d2y = (projectedEnvelope.getLength(1) * 100) / sumSideNewBBox;
463
        double p2y = (p1y * d2y) / d1y;
464
        double p2x = (p1x * d2x) / d1x;
465
        double newCellSizeX = projectedEnvelope.getLength(0) / p2x;
466
        double newCellSizeY= projectedEnvelope.getLength(1) / p2y;
467
        return new double[] { Math.round(p2x), Math.round(p2y), newCellSizeX, newCellSizeY };
468
    }
469

    
470
    private AffineTransform calculateAffineTransform(Envelope projectedBufferEnvelope, int projectedBufferRows,
471
        int projectedBufferColumns) {
472

    
473
        double cellSizeX = projectedBufferEnvelope.getLength(0) / projectedBufferColumns;
474
        double cellSizeY = projectedBufferEnvelope.getLength(1) / projectedBufferRows;
475

    
476
        return new AffineTransform(cellSizeX, 0d, 0d, -cellSizeY, projectedBufferEnvelope.getMinimum(0),
477
            projectedBufferEnvelope.getMaximum(1));
478
    }
479

    
480

    
481
    public int[] getBandTypes() {
482
        int[] bandDataTypes = new int[this.getBandCount()];
483
        for (int i = 0; i < this.bands.size(); i++) {
484
            bandDataTypes[i] = this.bands.get(i).getDataType();
485
        }
486
        return bandDataTypes;
487
    }
488

    
489
    public NoData[] getBandNoData() {
490
        NoData[] bandNoData = new NoData[this.getBandCount()];
491
        for (int i = 0; i < this.bands.size(); i++) {
492
            bandNoData[i] = this.bands.get(i).getNoData();
493
        }
494
        return bandNoData;
495
    }
496

    
497
    @Override
498
    public Buffer clip(Envelope envelope) throws BufferException {
499
        if(!this.envelope.intersects(envelope)){
500
            return null;
501
        }
502
        try {
503
            return BufferLocator.getBufferManager().createClippedBuffer(this, envelope);
504
        } catch (LocatorException | BufferException e) {
505
            throw new BufferException(e);
506
        }
507
    }
508

    
509
    public double getPixelSizeX(){
510
        if(pixelSizeX == null){
511
            pixelSizeX = this.getEnvelope().getLength(0)/this.getColumns();
512
        }
513
        return pixelSizeX.doubleValue();
514
    }
515

    
516
    public double getPixelSizeY(){
517
        if(pixelSizeY == null){
518
            pixelSizeY = this.getEnvelope().getLength(1)/this.getRows();
519
        }
520
        return pixelSizeY.doubleValue();
521
    }
522

    
523
//    public final void dispose() {
524
//        synchronized (lock) {
525
//            // Check if we have already been disposed, and don't do it again
526
//            if (!disposed) {
527
//                if ( ToolsLocator.getDisposableManager().release(this) ) {
528
//                    try {
529
//                        doDispose();
530
//                    } catch (BaseException ex) {
531
//                        LOG.error("Error performing dispose", ex);
532
//                    }
533
//                    disposed = true;
534
//                }
535
//            }
536
//        }
537
//    }
538
//
539
//    @Override
540
//    public void doDispose() {
541
//        for (Iterator iterator = bands.iterator(); iterator.hasNext();) {
542
//            Band band = (Band) iterator.next();
543
//            band.dispose();
544
//        }
545
//        envelope = null;
546
//        projection = null;
547
//        //TODO: ?FilterList Disposable?
548
//        filters = null;
549
//        //TODO: ?Statistics Disposable?
550
//        statistics = null;
551
//
552
//        pixelSizeX = null;
553
//        pixelSizeY = null;
554
//    }
555

    
556
    @Override
557
    protected void finalize() throws Throwable {
558
        super.finalize();
559
        logger.info("AbstractBuffer with rows = "+rows+" columns = "+columns+" CLEANED");
560

    
561
    }
562
}