Statistics
| Revision:

gvsig-raster / org.gvsig.raster / trunk / org.gvsig.raster / org.gvsig.raster.lib / org.gvsig.raster.lib.impl / src / main / java / org / gvsig / raster / impl / provider / MemoryMatrixBuffer.java @ 746

History | View | Annotate | Download (16.6 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 */
22
package org.gvsig.raster.impl.provider;
23

    
24
import java.awt.geom.Rectangle2D;
25
import java.util.ArrayList;
26

    
27
import org.gvsig.fmap.dal.coverage.dataset.Buffer;
28
import org.gvsig.fmap.dal.coverage.datastruct.Extent;
29
import org.gvsig.fmap.dal.coverage.exception.ProcessInterruptedException;
30
import org.gvsig.raster.cache.tile.Tile;
31
import org.gvsig.raster.impl.DefaultRasterManager;
32
import org.gvsig.raster.impl.datastruct.ExtentImpl;
33

    
34
/** 
35
 * Buffer composed by a list of tiles and its extents. 
36
 * It will expose a method getWindow to read a window of data from the tile list.
37
 * The list of tiles have to make a square.
38
 * 
39
 * @author Nacho Brodin (nachobrodin@gmail.com)
40
 */
41
public class MemoryMatrixBuffer {
42
        private Buffer[]         bufferList  = null;
43
        private Buffer[]         transpList  = null;
44
        private int              nRows       = 0;
45
        private int              nCols       = 0;        
46
        private Extent           bbox        = null;
47
        private ArrayList<Tile>  tileList    = null;
48
        
49
        /**
50
         * Constructor using an array of tiles. It will compute the number
51
         * of rows and columns and the complete bounding box
52
         * @param tileList
53
         */
54
        public MemoryMatrixBuffer(Tile[] tileList) {
55
                this.tileList = new ArrayList<Tile>();
56
                bufferList = new Buffer[tileList.length];
57
                if(tileList[0].getData().length > 1 && tileList[0].getData()[1] instanceof Buffer)
58
                        transpList = new Buffer[tileList.length];
59
                for (int i = 0; i < tileList.length; i++) {
60
                        this.tileList.add(tileList[i]);
61
                        bufferList[i] = (Buffer)tileList[i].getData()[0];
62
                        if(tileList[i].getData().length > 1 && tileList[i].getData()[1] instanceof Buffer)
63
                                transpList[i] = (Buffer)tileList[i].getData()[1];
64
                        //extentList[i] = tileList[i].getExtent();
65
                        //pxLayerList[i] = tileList[i].getCoordsPx();
66
                }
67
                int minRow = Integer.MAX_VALUE;
68
                int maxRow = Integer.MIN_VALUE;
69
                int minCol = Integer.MAX_VALUE;
70
                int maxCol = Integer.MIN_VALUE;
71
                for (int i = 0; i < tileList.length; i++) {
72
                        if(tileList[i].getRow() > maxRow)
73
                                maxRow = tileList[i].getRow();
74
                        if(tileList[i].getCol() > maxCol)
75
                                maxCol = tileList[i].getCol();
76
                        if(tileList[i].getRow() < minRow)
77
                                minRow = tileList[i].getRow();
78
                        if(tileList[i].getCol() < minCol)
79
                                minCol = tileList[i].getCol();
80
                }
81
                nRows = maxRow - minRow + 1;
82
                nCols = maxCol - minCol + 1;
83
                bbox = calculateBBox();
84
        }
85
        
86
        /**
87
         * Constructor using an ArrayList of tiles. It will compute the number
88
         * of rows and columns and the complete bounding box
89
         * @param tileList
90
         */
91
        public MemoryMatrixBuffer(ArrayList<Tile> tileList) {
92
                this.tileList = tileList;
93
                bufferList = new Buffer[tileList.size()];
94
                if(tileList.get(0).getData().length > 1 && tileList.get(0).getData()[1] instanceof Buffer)
95
                        transpList = new Buffer[tileList.size()];
96
                for (int i = 0; i < tileList.size(); i++) {
97
                        bufferList[i] = (Buffer)tileList.get(i).getData()[0];
98
                        if(tileList.get(i).getData().length > 1 && tileList.get(i).getData()[1] instanceof Buffer)
99
                                transpList[i] = (Buffer)tileList.get(i).getData()[1];
100
                }
101
                int minRow = Integer.MAX_VALUE;
102
                int maxRow = Integer.MIN_VALUE;
103
                int minCol = Integer.MAX_VALUE;
104
                int maxCol = Integer.MIN_VALUE;
105
                for (int i = 0; i < tileList.size(); i++) {
106
                        if(tileList.get(i).getRow() > maxRow)
107
                                maxRow = tileList.get(i).getRow();
108
                        if(tileList.get(i).getCol() > maxCol)
109
                                maxCol = tileList.get(i).getCol();
110
                        if(tileList.get(i).getRow() < minRow)
111
                                minRow = tileList.get(i).getRow();
112
                        if(tileList.get(i).getCol() < minCol)
113
                                minCol = tileList.get(i).getCol();
114
                }
115
                nRows = maxRow - minRow + 1;
116
                nCols = maxCol - minCol + 1;
117
                bbox = calculateBBox();
118
        }
119
        
120
        /**
121
         * Builds the complete bounding box of the tile list
122
         * @return
123
         */
124
        private Extent calculateBBox() { 
125
                double minX = Double.MAX_VALUE;
126
                double minY = Double.MAX_VALUE;
127
                double maxX = 0;
128
                double maxY = 0;
129
                for (int i = 0; i < tileList.size(); i++) {
130
                        Rectangle2D e = tileList.get(i).getExtent();
131
                        if(e.getX() < minX)
132
                                minX = e.getX();
133
                        if((e.getY() - e.getHeight()) < minY)
134
                                minY = (e.getY() - e.getHeight());
135
                        if((e.getX() + e.getWidth()) > maxX)
136
                                maxX = (e.getX() + e.getWidth());
137
                        if(e.getY() > maxY)
138
                                maxY = e.getY();
139
                }
140
                return new ExtentImpl(minX, minY, maxX, maxY);
141
        }
142
        
143
        /**
144
         * Gets a window from tiles
145
         * @param ext
146
         * @param buf
147
         * @return
148
         */
149
        public Buffer getWindow(Rectangle2D r, Buffer buf) {
150
                int shiftRow = 0;
151
                int shiftCol = 0;
152
                int posRow = 0;
153
                int posCol = 0;
154
                Rectangle2D[] rTileShiftList = new Rectangle2D[bufferList.length];
155
                Rectangle2D[] rBufferShiftList = new Rectangle2D[bufferList.length];
156
                int[] colsWidth = new int[nCols];
157
                int[] rowsHeight = new int[nRows];
158
                for (int i = 0; i < bufferList.length; i++) {
159
                        Rectangle2D pxLayer = tileList.get(i).getCoordsPx();
160
                        int initPxTileX = (int)Math.max(pxLayer.getMinX(), r.getMinX()) - (tileList.get(i).getCol() * tileList.get(i).getWidthPx()); 
161
                        int initPxTileY = (int)Math.max(pxLayer.getMinY(), r.getMinY()) - (tileList.get(i).getRow() * tileList.get(i).getHeightPx());
162
                        int widthPxTile = (int)Math.min(pxLayer.getMaxX(), r.getMaxX()) - (tileList.get(i).getCol() * tileList.get(i).getWidthPx()) - initPxTileX;
163
                        int heightPxTile = (int)Math.min(pxLayer.getMaxY(), r.getMaxY()) - (tileList.get(i).getRow() * tileList.get(i).getHeightPx()) - initPxTileY;
164
                        rTileShiftList[i] = new Rectangle2D.Double(initPxTileX, initPxTileY, widthPxTile, heightPxTile);
165
                        if(i == 0) {
166
                                shiftCol = tileList.get(i).getCol();
167
                                shiftRow = tileList.get(i).getRow();
168
                        }
169
                        posCol = tileList.get(i).getCol() - shiftCol;
170
                        posRow = tileList.get(i).getRow() - shiftRow;
171
                        if(posCol == 0)
172
                                colsWidth[posCol] = widthPxTile;
173
                        else
174
                                colsWidth[posCol] = widthPxTile + colsWidth[posCol - 1];
175
                        
176
                        if(posRow == 0)
177
                                rowsHeight[posRow] = heightPxTile;
178
                        else
179
                                rowsHeight[posRow] = heightPxTile + rowsHeight[posRow - 1];
180
                        
181
                        
182
                        //shiftX = initPxTileX < shiftX ? initPxTileX : shiftX;
183
                        //shiftY = initPxTileY < shiftY ? initPxTileY : shiftY;
184
                }
185
                
186
                int initPxBufferX = 0; 
187
                int initPxBufferY = 0;
188
                int widthPxBuffer = 0;
189
                int heightPxBuffer = 0;
190
                
191
                for (int i = 0; i < bufferList.length; i++) {
192
                        posCol = tileList.get(i).getCol() - shiftCol;
193
                        posRow = tileList.get(i).getRow() - shiftRow;
194
                        if(posCol == 0) {
195
                                initPxBufferX = 0;
196
                                widthPxBuffer = colsWidth[0];
197
                        } else {
198
                                initPxBufferX = colsWidth[posCol - 1];
199
                                widthPxBuffer = colsWidth[posCol] - initPxBufferX;
200
                        }
201
                        if(posRow == 0) {
202
                                initPxBufferY = 0;
203
                                heightPxBuffer = rowsHeight[0];
204
                        } else {
205
                                initPxBufferY = rowsHeight[posRow - 1];
206
                                heightPxBuffer = rowsHeight[posRow] - initPxBufferY;
207
                        }
208
                        rBufferShiftList[i] = new Rectangle2D.Double(initPxBufferX, initPxBufferY, widthPxBuffer, heightPxBuffer);
209
                }                        
210
                
211
                for (int i = 0; i < bufferList.length; i++) {
212
                        loadBuffer(buf, 
213
                                        bufferList[i],
214
                                        rTileShiftList[i], 
215
                                        (int)rBufferShiftList[i].getX(), 
216
                                        (int)rBufferShiftList[i].getY(), 
217
                                        false);
218
                }
219
                return buf;
220
        }
221
        
222
        /**
223
         * Gets a window from tiles
224
         * @param ext
225
         * @param buf
226
         * @return
227
         */
228
        public Buffer getWindow(Extent ext, Buffer buf) {
229
                return getWindow(ext, buf, false);
230
        }
231
        
232
        /**
233
         * Gets a window from tiles
234
         * @param ext
235
         * @param buf
236
         * @return
237
         */
238
        public Buffer getWindow(Extent ext, Buffer buf, boolean alpha) {
239
                //Crea un buffer a escala de la lista de tiles pero q ser? el buffer final
240
                /*int bands = buf.getBandCount();
241
                if(transpList != null && !alpha)
242
                        bands ++;*/
243
                Buffer sourceWithoutResampling = createBufferWithoutResampling(ext, buf.getDataType(), buf.getBandCount());
244
                for (int i = 0; i < bufferList.length; i++) {
245
                        //1-Calcular las coordenadas pixel del tile de entrada
246
                        int[] points = getClipPoints(tileList.get(i).getExtent(), bufferList[i], ext);
247
                        
248
                        //2-Ajustar peti?n al extent del tile
249
                        Extent adjustedRequestExtent = getAdjustedExtent(tileList.get(i).getExtent(), ext);
250
                        
251
                        if((points[0] == 0 && points[1] == 0) || (points[2] == 0 && points[3] == 0))
252
                                continue;
253

    
254
                        //3-Calcular coordenada pixel de inicio del buffer
255
                        double wcX1 = Math.abs(adjustedRequestExtent.getMin().getX() - ext.getMin().getX());
256
                        double wcY1 = Math.abs(ext.getMax().getY() - adjustedRequestExtent.getMax().getY());
257
                        int initXPxBuf = (int)Math.ceil((wcX1 * (sourceWithoutResampling.getWidth())) / ext.width());
258
                        int initYPxBuf = (int)Math.ceil((wcY1 * (sourceWithoutResampling.getHeight())) / ext.height());
259

    
260
                        //4-Copiar recorte al buffer
261
                        Rectangle2D rTile = new Rectangle2D.Double(points[0], points[2], (points[1] - points[0]) + 1, (points[3] - points[2]) + 1);
262
                        if(alpha)
263
                                loadBuffer(sourceWithoutResampling, transpList[i], rTile, initXPxBuf, initYPxBuf, true);
264
                        else
265
                                loadBuffer(sourceWithoutResampling, bufferList[i], rTile, initXPxBuf, initYPxBuf, false);
266
                }
267
                //Devuelve el buffer pero reescalandolo antes al tama?o en pixeles de la petici?n
268
                try {
269
                        return sourceWithoutResampling.getAdjustedWindow(buf.getWidth(), buf.getHeight(), Buffer.INTERPOLATION_NearestNeighbour);
270
                } catch (ProcessInterruptedException e) {
271
                }
272
                return buf;
273
        }
274
        
275
        /**
276
         * Builds a buffer in the same resolution as the list of tiles. When the operation
277
         * ends this buffer should be resampled.
278
         * @return
279
         */
280
        private Buffer createBufferWithoutResampling(Extent ext, int dataType, int bands) {
281
                int w = 0;
282
                int h = 0;
283
                for (int i = 0; i < bufferList.length; i++) {
284
                        int[] points = getClipPoints(tileList.get(i).getExtent(), bufferList[i], ext);
285
                        w += (points[1] - points[0]) + 1;
286
                        h += (points[3] - points[2]) + 1;
287
                }
288
                
289
                //Si todos los tiles de la lista no cubren completamente el buffer pedido habr? que calcular cuantos 
290
                //pixeles quedan fuera para a?adirlos al nuevo buffer que estamos construyendo
291
                double mtsPx = tileList.get(0).getExtent().getWidth() / bufferList[0].getWidth();
292
                double distanceUp = (ext.getMax().getY() - bbox.getMax().getY()) <= 0 ? 0 : (ext.getMax().getY() - bbox.getMax().getY());
293
                double distanceDown = (bbox.getMin().getY() - ext.getMin().getY()) <= 0 ? 0 : (bbox.getMin().getY() - ext.getMin().getY());
294
                double distanceLeft = (bbox.getMin().getX() - ext.getMin().getX()) <= 0 ? 0 : (bbox.getMin().getX() - ext.getMin().getX());
295
                double distanceRight = (ext.getMax().getX() - bbox.getMax().getX()) <= 0 ? 0 : (ext.getMax().getX() - bbox.getMax().getX());
296
                int distanceUpPx = (int)(distanceUp / mtsPx);
297
                int distanceDownPx = (int)(distanceDown / mtsPx);
298
                int distanceLeftPx = (int)(distanceLeft / mtsPx);
299
                int distanceRightPx = (int)(distanceRight / mtsPx);
300
                return DefaultRasterManager.getInstance().createBuffer(dataType, 
301
                                (int)((w / nCols) + distanceLeftPx + distanceRightPx), 
302
                                (int)((h / nRows) + distanceUpPx + distanceDownPx), 
303
                                bands, 
304
                                true);
305
        }
306
        
307
        /**
308
         * Gets the point list to clip the tile
309
         * @param r Bounding box of the tile
310
         * @param b Buffer of the tile
311
         * @param extentRequest 
312
         * @return
313
         */
314
        private int[] getClipPoints(Rectangle2D r, Buffer b, Extent extentRequest) {
315
                double widthWCTile = r.getWidth();
316
                double widthPXTile = b.getWidth();
317
                double heightWCTile = r.getHeight();
318
                double heightPXTile = b.getHeight();
319
                
320
                //1-Ajustar peti?n al extent del tile
321
                Extent adjustedRequestExtent = getAdjustedExtent(r, extentRequest);
322

    
323
                //2-Obtener el punto inicial y final del recorte del tile en pixeles
324
                double wcX1 = adjustedRequestExtent.getMin().getX() - r.getX();
325
                double wcX2 = adjustedRequestExtent.getMax().getX() - r.getX();
326
                double wcY1 = r.getY() - adjustedRequestExtent.getMax().getY();
327
                double wcY2 = r.getY() - adjustedRequestExtent.getMin().getY();
328
                int initXPxTile = (int)((wcX1 * widthPXTile) / widthWCTile);
329
                int endXPxTile = (int)((wcX2 * widthPXTile) / widthWCTile) - 1;
330
                int initYPxTile = (int)((wcY1 * heightPXTile) / heightWCTile);
331
                int endYPxTile = (int)((wcY2 * heightPXTile) / heightWCTile) - 1;
332
                return new int[]{initXPxTile, 
333
                                endXPxTile >= widthPXTile ? endXPxTile - 1 : endXPxTile, 
334
                                initYPxTile, 
335
                                endYPxTile >= heightPXTile ? endYPxTile - 1 : endYPxTile};
336
        }
337
        
338
        /**
339
         * Adjust the request to the tile bounding box
340
         * @param tileExtent
341
         * @param extentRequest
342
         * @return
343
         */
344
        private Extent getAdjustedExtent(Rectangle2D tileExtent, Extent extentRequest) {
345
                double x1 = Math.max(extentRequest.getMin().getX(), tileExtent.getX());
346
                double y1 = Math.min(extentRequest.getMax().getY(), tileExtent.getY());
347
                double x2 = Math.min(extentRequest.getMax().getX(), (tileExtent.getX() + tileExtent.getWidth()));
348
                double y2 = Math.max(extentRequest.getMin().getY(), (tileExtent.getY() - tileExtent.getHeight()));
349
                return new ExtentImpl(x1, y1, x2, y2); 
350
        }
351
        
352
        /**
353
         * Write data in the source buffer taking into account the view shift
354
         * @param sourceBuf
355
         * @param tileBuf
356
         * @param rTile
357
         * @param initXPxBuf
358
         * @param initYPxBuf
359
         */
360
        private void loadBuffer(Buffer sourceBuf, Buffer tileBuf, Rectangle2D rTile, int initXPxBuf, int initYPxBuf, boolean alpha) {
361
                int r = initXPxBuf;
362
                int c = initYPxBuf;
363
                //if(!alpha) {
364
                        if(tileBuf.getDataType() == Buffer.TYPE_BYTE) {
365
                                for (int band = 0; band < tileBuf.getBandCount(); band++) {
366
                                        r = initYPxBuf;
367
                                        for (int row = (int)rTile.getMinY(); (row < (int)rTile.getMaxY() && r < sourceBuf.getHeight()); row++) {
368
                                                c = initXPxBuf;
369
                                                for (int col = (int)rTile.getMinX(); (col < (int)rTile.getMaxX() && c < sourceBuf.getWidth()); col++) {
370
                                                        sourceBuf.setElem(r, c, band, tileBuf.getElemByte(row, col, band));
371
                                                        c++;
372
                                                }
373
                                                r++;
374
                                        }
375
                                }
376
                        }
377
                /*} else {
378
                        if(tileBuf.getDataType() == Buffer.TYPE_BYTE) {
379
                                r = initYPxBuf;
380
                                for (int row = (int)rTile.getMinY(); row < (int)rTile.getMaxY(); row++) {
381
                                        c = initXPxBuf;
382
                                        for (int col = (int)rTile.getMinX(); col < (int)rTile.getMaxX(); col++) {
383
                                                sourceBuf.setElem(r, c, 0, tileBuf.getElemByte(row, col, 0));
384
                                                c++;
385
                                        }
386
                                        r++;
387
                                }
388
                        }
389
                }*/
390
                if(tileBuf.getDataType() == Buffer.TYPE_SHORT) {
391
                        for (int band = 0; band < tileBuf.getBandCount(); band++) {
392
                                r = initYPxBuf;
393
                                for (int row = (int)rTile.getMinY(); (row < (int)rTile.getMaxY() && r < sourceBuf.getHeight()); row++) {
394
                                        c = initXPxBuf;
395
                                        for (int col = (int)rTile.getMinX(); (col < (int)rTile.getMaxX() && c < sourceBuf.getWidth()); col++) {
396
                                                sourceBuf.setElem(r, c, band, tileBuf.getElemShort(row, col, band));
397
                                                c++;
398
                                        }
399
                                        r++;
400
                                }
401
                        }
402
                }
403
                if(tileBuf.getDataType() == Buffer.TYPE_INT) {
404
                        for (int band = 0; band < tileBuf.getBandCount(); band++) {
405
                                r = initYPxBuf;
406
                                for (int row = (int)rTile.getMinY(); (row < (int)rTile.getMaxY() && r < sourceBuf.getHeight()); row++) {
407
                                        c = initXPxBuf;
408
                                        for (int col = (int)rTile.getMinX(); (col < (int)rTile.getMaxX() && c < sourceBuf.getWidth()); col++) {
409
                                                sourceBuf.setElem(r, c, band, tileBuf.getElemInt(row, col, band));
410
                                                c++;
411
                                        }
412
                                        r++;
413
                                }
414
                        }
415
                }
416
                if(tileBuf.getDataType() == Buffer.TYPE_FLOAT) {
417
                        for (int band = 0; band < tileBuf.getBandCount(); band++) {
418
                                r = initYPxBuf;
419
                                for (int row = (int)rTile.getMinY(); (row < (int)rTile.getMaxY() && r < sourceBuf.getHeight()); row++) {
420
                                        c = initXPxBuf;
421
                                        for (int col = (int)rTile.getMinX(); (col < (int)rTile.getMaxX() && c < sourceBuf.getWidth()); col++) {
422
                                                sourceBuf.setElem(r, c, band, tileBuf.getElemFloat(row, col, band));
423
                                                c++;
424
                                        }
425
                                        r++;
426
                                }
427
                        }
428
                }
429
                if(tileBuf.getDataType() == Buffer.TYPE_DOUBLE) {
430
                        for (int band = 0; band < tileBuf.getBandCount(); band++) {
431
                                r = initYPxBuf;
432
                                for (int row = (int)rTile.getMinY(); (row < (int)rTile.getMaxY() && r < sourceBuf.getHeight()); row++) {
433
                                        c = initXPxBuf;
434
                                        for (int col = (int)rTile.getMinX(); (col < (int)rTile.getMaxX() && c < sourceBuf.getWidth()); col++) {
435
                                                sourceBuf.setElem(r, c, band, tileBuf.getElemDouble(row, col, band));
436
                                                c++;
437
                                        }
438
                                        r++;
439
                                }
440
                        }
441
                }
442
        }
443
        
444

    
445
        /*private double clip(double value) {
446
                return math.clipDecimals(value, 5);
447
        }
448
        
449
        private double round(double value) {
450
                double a = (value - (int)value);
451
                return (a > 0.95 || a < 0.05) ? Math.round(value) : value;
452
        }*/
453
        
454
}