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 @ 463

History | View | Annotate | Download (11.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 Rectangle2D[]  extentList = null;
44
        private int            nRows      = 0;
45
        private int            nCols      = 0;        
46
        private Extent         bbox       = null;
47
        
48
        /**
49
         * Constructor using an array of tiles. It will compute the number
50
         * of rows and columns and the complete bounding box
51
         * @param tileList
52
         */
53
        public MemoryMatrixBuffer(Tile[] tileList) {
54
                bufferList = new Buffer[tileList.length];
55
                extentList = new Rectangle2D[tileList.length];
56
                for (int i = 0; i < extentList.length; i++) {
57
                        bufferList[i] = (Buffer)tileList[i].getData()[0];
58
                        extentList[i] = tileList[i].getExtent();
59
                }
60
                int r = tileList[0].getRow();
61
                int c = tileList[0].getCol();
62
                for (int i = 0; i < tileList.length; i++) {
63
                        if(tileList[i].getRow() == r)
64
                                nRows ++;
65
                        if(tileList[i].getCol() == c)
66
                                nCols ++;
67
                }
68
                bbox = calculateBBox();
69
        }
70
        
71
        /**
72
         * Constructor using an ArrayList of tiles. It will compute the number
73
         * of rows and columns and the complete bounding box
74
         * @param tileList
75
         */
76
        public MemoryMatrixBuffer(ArrayList<Tile> tileList) {
77
                bufferList = new Buffer[tileList.size()];
78
                extentList = new Rectangle2D[tileList.size()];
79
                for (int i = 0; i < extentList.length; i++) {
80
                        bufferList[i] = (Buffer)tileList.get(i).getData()[0];
81
                        extentList[i] = tileList.get(i).getExtent();
82
                }
83
                int r = tileList.get(0).getRow();
84
                int c = tileList.get(0).getCol();
85
                for (int i = 0; i < tileList.size(); i++) {
86
                        if(tileList.get(i).getRow() == r)
87
                                nRows ++;
88
                        if(tileList.get(i).getCol() == c)
89
                                nCols ++;
90
                }
91
                bbox = calculateBBox();
92
        }
93
        
94
        /**
95
         * Builds the complete bounding box of the tile list
96
         * @return
97
         */
98
        private Extent calculateBBox() { 
99
                double minX = Double.MAX_VALUE;
100
                double minY = Double.MAX_VALUE;
101
                double maxX = 0;
102
                double maxY = 0;
103
                for (int i = 0; i < extentList.length; i++) {
104
                        if(extentList[i].getX() < minX)
105
                                minX = extentList[i].getX();
106
                        if((extentList[i].getY() - extentList[i].getHeight()) < minY)
107
                                minY = (extentList[i].getY() - extentList[i].getHeight());
108
                        if((extentList[i].getX() + extentList[i].getWidth()) > maxX)
109
                                maxX = (extentList[i].getX() + extentList[i].getWidth());
110
                        if(extentList[i].getY() > maxY)
111
                                maxY = extentList[i].getY();
112
                }
113
                return new ExtentImpl(minX, minY, maxX, maxY);
114
        }
115
        
116
        /**
117
         * Gets a window from tiles
118
         * @param ext
119
         * @param buf
120
         * @return
121
         */
122
        public Buffer getWindow(Extent ext, Buffer buf) {
123
                //Crea un buffer a escala de la lista de tiles pero q ser? el buffer final
124
                Buffer sourceWithoutResampling = createBufferWithoutResampling(ext, buf.getDataType(), buf.getBandCount());
125
                for (int i = 0; i < bufferList.length; i++) {
126
                        //1-Calcular las coordenadas pixel del tile de entrada
127
                        int[] points = getClipPoints(extentList[i], bufferList[i], ext);
128
                        
129
                        //2-Ajustar peti?n al extent del tile
130
                        Extent adjustedRequestExtent = getAdjustedExtent(extentList[i], ext);
131
                        
132
                        if((points[0] == 0 && points[1] == 0) || (points[2] == 0 && points[3] == 0))
133
                                continue;
134

    
135
                        //3-Calcular coordenada pixel de inicio del buffer
136
                        double wcX1 = Math.abs(adjustedRequestExtent.getMin().getX() - ext.getMin().getX());
137
                        double wcY1 = Math.abs(ext.getMax().getY() - adjustedRequestExtent.getMax().getY());
138
                        int initXPxBuf = (int)Math.ceil((wcX1 * (sourceWithoutResampling.getWidth())) / ext.width());
139
                        int initYPxBuf = (int)Math.ceil((wcY1 * (sourceWithoutResampling.getHeight())) / ext.height());
140

    
141
                        //4-Copiar recorte al buffer
142
                        Rectangle2D rTile = new Rectangle2D.Double(points[0], points[2], (points[1] - points[0]) + 1, (points[3] - points[2]) + 1);
143
                        loadBuffer(sourceWithoutResampling, bufferList[i], rTile, initXPxBuf, initYPxBuf);
144
                }
145
                //Devuelve el buffer pero reescalandolo antes al tama?o en pixeles de la petici?n
146
                try {
147
                        return sourceWithoutResampling.getAdjustedWindow(buf.getWidth(), buf.getHeight(), Buffer.INTERPOLATION_NearestNeighbour);
148
                } catch (ProcessInterruptedException e) {
149
                }
150
                return buf;
151
        }
152
        
153
        /**
154
         * Builds a buffer in the same resolution as the list of tiles. When the operation
155
         * ends this buffer should be resampled.
156
         * @return
157
         */
158
        private Buffer createBufferWithoutResampling(Extent ext, int dataType, int bands) {
159
                int w = 0;
160
                int h = 0;
161
                for (int i = 0; i < bufferList.length; i++) {
162
                        int[] points = getClipPoints(extentList[i], bufferList[i], ext);
163
                        w += (points[1] - points[0]) + 1;
164
                        h += (points[3] - points[2]) + 1;
165
                }
166
                
167
                //Si todos los tiles de la lista no cubren completamente el buffer pedido habr? que calcular cuantos 
168
                //pixeles quedan fuera para a?adirlos al nuevo buffer que estamos construyendo
169
                double mtsPx = extentList[0].getWidth() / bufferList[0].getWidth();
170
                double distanceUp = (ext.getMax().getY() - bbox.getMax().getY()) <= 0 ? 0 : (ext.getMax().getY() - bbox.getMax().getY());
171
                double distanceDown = (bbox.getMin().getY() - ext.getMin().getY()) <= 0 ? 0 : (bbox.getMin().getY() - ext.getMin().getY());
172
                double distanceLeft = (bbox.getMin().getX() - ext.getMin().getX()) <= 0 ? 0 : (bbox.getMin().getX() - ext.getMin().getX());
173
                double distanceRight = (ext.getMax().getX() - bbox.getMax().getX()) <= 0 ? 0 : (ext.getMax().getX() - bbox.getMax().getX());
174
                int distanceUpPx = (int)(distanceUp / mtsPx);
175
                int distanceDownPx = (int)(distanceDown / mtsPx);
176
                int distanceLeftPx = (int)(distanceLeft / mtsPx);
177
                int distanceRightPx = (int)(distanceRight / mtsPx);
178
                return DefaultRasterManager.getInstance().createBuffer(dataType, 
179
                                (int)((w / nCols) + distanceLeftPx + distanceRightPx), 
180
                                (int)((h / nRows) + distanceUpPx + distanceDownPx), 
181
                                bands, 
182
                                true);
183
        }
184
        
185
        /**
186
         * Gets the point list to clip the tile
187
         * @param r Bounding box of the tile
188
         * @param b Buffer of the tile
189
         * @param extentRequest 
190
         * @return
191
         */
192
        private int[] getClipPoints(Rectangle2D r, Buffer b, Extent extentRequest) {
193
                double widthWCTile = r.getWidth();
194
                double widthPXTile = b.getWidth();
195
                double heightWCTile = r.getHeight();
196
                double heightPXTile = b.getHeight();
197
                
198
                //1-Ajustar peti?n al extent del tile
199
                Extent adjustedRequestExtent = getAdjustedExtent(r, extentRequest);
200

    
201
                //2-Obtener el punto inicial y final del recorte del tile en pixeles
202
                double wcX1 = adjustedRequestExtent.getMin().getX() - r.getX();
203
                double wcX2 = adjustedRequestExtent.getMax().getX() - r.getX();
204
                double wcY1 = r.getY() - adjustedRequestExtent.getMax().getY();
205
                double wcY2 = r.getY() - adjustedRequestExtent.getMin().getY();
206
                int initXPxTile = (int)((wcX1 * widthPXTile) / widthWCTile);
207
                int endXPxTile = (int)((wcX2 * widthPXTile) / widthWCTile) - 1;
208
                int initYPxTile = (int)((wcY1 * heightPXTile) / heightWCTile);
209
                int endYPxTile = (int)((wcY2 * heightPXTile) / heightWCTile) - 1;
210
                return new int[]{initXPxTile, 
211
                                endXPxTile >= widthPXTile ? endXPxTile - 1 : endXPxTile, 
212
                                initYPxTile, 
213
                                endYPxTile >= heightPXTile ? endYPxTile - 1 : endYPxTile};
214
        }
215
        
216
        /**
217
         * Adjust the request to the tile bounding box
218
         * @param tileExtent
219
         * @param extentRequest
220
         * @return
221
         */
222
        private Extent getAdjustedExtent(Rectangle2D tileExtent, Extent extentRequest) {
223
                double x1 = Math.max(extentRequest.getMin().getX(), tileExtent.getX());
224
                double y1 = Math.min(extentRequest.getMax().getY(), tileExtent.getY());
225
                double x2 = Math.min(extentRequest.getMax().getX(), (tileExtent.getX() + tileExtent.getWidth()));
226
                double y2 = Math.max(extentRequest.getMin().getY(), (tileExtent.getY() - tileExtent.getHeight()));
227
                return new ExtentImpl(x1, y1, x2, y2); 
228
        }
229
        
230
        /**
231
         * Write data in the source buffer taking into account the view shift
232
         * @param sourceBuf
233
         * @param tileBuf
234
         * @param rTile
235
         * @param initXPxBuf
236
         * @param initYPxBuf
237
         */
238
        private void loadBuffer(Buffer sourceBuf, Buffer tileBuf, Rectangle2D rTile, int initXPxBuf, int initYPxBuf) {
239
                int r = initXPxBuf;
240
                int c = initYPxBuf;
241
                if(tileBuf.getDataType() == Buffer.TYPE_BYTE) {
242
                        for (int band = 0; band < sourceBuf.getBandCount(); band++) {
243
                                r = initYPxBuf;
244
                                for (int row = (int)rTile.getMinY(); row < (int)rTile.getMaxY(); row++) {
245
                                        c = initXPxBuf;
246
                                        for (int col = (int)rTile.getMinX(); col < (int)rTile.getMaxX(); col++) {
247
                                                sourceBuf.setElem(r, c, band, tileBuf.getElemByte(row, col, band));
248
                                                c++;
249
                                        }
250
                                        r++;
251
                                }
252
                        }
253
                }
254
                if(tileBuf.getDataType() == Buffer.TYPE_SHORT) {
255
                        for (int band = 0; band < sourceBuf.getBandCount(); band++) {
256
                                r = initYPxBuf;
257
                                for (int row = (int)rTile.getMinY(); row < (int)rTile.getMaxY(); row++) {
258
                                        c = initXPxBuf;
259
                                        for (int col = (int)rTile.getMinX(); col < (int)rTile.getMaxX(); col++) {
260
                                                sourceBuf.setElem(r, c, band, tileBuf.getElemShort(row, col, band));
261
                                                c++;
262
                                        }
263
                                        r++;
264
                                }
265
                        }
266
                }
267
                if(tileBuf.getDataType() == Buffer.TYPE_INT) {
268
                        for (int band = 0; band < sourceBuf.getBandCount(); band++) {
269
                                r = initYPxBuf;
270
                                for (int row = (int)rTile.getMinY(); row < (int)rTile.getMaxY(); row++) {
271
                                        c = initXPxBuf;
272
                                        for (int col = (int)rTile.getMinX(); col < (int)rTile.getMaxX(); col++) {
273
                                                sourceBuf.setElem(r, c, band, tileBuf.getElemInt(row, col, band));
274
                                                c++;
275
                                        }
276
                                        r++;
277
                                }
278
                        }
279
                }
280
                if(tileBuf.getDataType() == Buffer.TYPE_FLOAT) {
281
                        for (int band = 0; band < sourceBuf.getBandCount(); band++) {
282
                                r = initYPxBuf;
283
                                for (int row = (int)rTile.getMinY(); row < (int)rTile.getMaxY(); row++) {
284
                                        c = initXPxBuf;
285
                                        for (int col = (int)rTile.getMinX(); col < (int)rTile.getMaxX(); col++) {
286
                                                sourceBuf.setElem(r, c, band, tileBuf.getElemFloat(row, col, band));
287
                                                c++;
288
                                        }
289
                                        r++;
290
                                }
291
                        }
292
                }
293
                if(tileBuf.getDataType() == Buffer.TYPE_DOUBLE) {
294
                        for (int band = 0; band < sourceBuf.getBandCount(); band++) {
295
                                r = initYPxBuf;
296
                                for (int row = (int)rTile.getMinY(); row < (int)rTile.getMaxY(); row++) {
297
                                        c = initXPxBuf;
298
                                        for (int col = (int)rTile.getMinX(); col < (int)rTile.getMaxX(); col++) {
299
                                                sourceBuf.setElem(r, c, band, tileBuf.getElemDouble(row, col, band));
300
                                                c++;
301
                                        }
302
                                        r++;
303
                                }
304
                        }
305
                }
306
        }
307
        
308

    
309
        /*private double clip(double value) {
310
                return math.clipDecimals(value, 5);
311
        }
312
        
313
        private double round(double value) {
314
                double a = (value - (int)value);
315
                return (a > 0.95 || a < 0.05) ? Math.round(value) : value;
316
        }*/
317
        
318
}