Statistics
| Revision:

root / branches / piloto3d / libraries / libFMap / src / com / iver / cit / gvsig / fmap / spatialindex / QuadtreeGt2.java @ 9528

History | View | Annotate | Download (9.75 KB)

1
/*
2
 * Created on 16-may-2006
3
 *
4
 * gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
5
 *
6
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
7
 *
8
 * This program is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU General Public License
10
 * as published by the Free Software Foundation; either version 2
11
 * of the License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
21
 *
22
 * For more information, contact:
23
 *
24
 *  Generalitat Valenciana
25
 *   Conselleria d'Infraestructures i Transport
26
 *   Av. Blasco Ib??ez, 50
27
 *   46010 VALENCIA
28
 *   SPAIN
29
 *
30
 *      +34 963862235
31
 *   gvsig@gva.es
32
 *      www.gvsig.gva.es
33
 *
34
 *    or
35
 *
36
 *   IVER T.I. S.A
37
 *   Salamanca 50
38
 *   46005 Valencia
39
 *   Spain
40
 *
41
 *   +34 963163400
42
 *   dac@iver.es
43
 */
44
/* CVS MESSAGES:
45
*
46
* $Id: QuadtreeGt2.java 9528 2007-01-03 16:58:36Z sbayarri $
47
* $Log$
48
* Revision 1.1.4.2  2007-01-03 16:58:36  sbayarri
49
* Fix wrong files
50
*
51
* Revision 1.1.6.1  2006/11/29 19:22:25  azabala
52
* bug fixed with envelopes that are similar -or greater- to the full extent of a layer
53
*
54
* Revision 1.1  2006/05/24 21:58:04  azabala
55
* *** empty log message ***
56
*
57
*
58
*/
59
package com.iver.cit.gvsig.fmap.spatialindex;
60

    
61
import java.awt.geom.Rectangle2D;
62
import java.io.File;
63
import java.io.IOException;
64
import java.util.ArrayList;
65
import java.util.Collection;
66
import java.util.List;
67
import java.util.Stack;
68

    
69
import org.geotools.data.DataSourceException;
70
import org.geotools.index.TreeException;
71
import org.geotools.index.quadtree.Node;
72
import org.geotools.index.quadtree.QuadTree;
73
import org.geotools.index.quadtree.StoreException;
74
import org.geotools.index.quadtree.fs.FileSystemIndexStore;
75
import org.geotools.index.quadtree.fs.IndexHeader;
76

    
77
import com.vividsolutions.jts.geom.Envelope;
78
/**
79
 * This Quadtree spatial index implementation is based
80
 * in a fork of org.geotools.index.quadtree.Quadtree implementation.
81
 * <br>
82
 * This implementation offers us:
83
 * <ol>
84
 * <li>Persistence of spatial index</li>
85
 * </ol>
86
 * We had to fork geotools quadtree for many reasons:
87
 * <ol>
88
 * <li>It was strongly dependent of SHP format, so it returned not only
89
 * a num of rectangle, it also returned byte offset of this rectangle in shp file</li>
90
 * <li>
91
 * Query artifact wasnt run well at all
92
 * </li>
93
 * </ol>
94
 * @author azabala
95
 *
96
 */
97
public class QuadtreeGt2 implements IPersistentSpatialIndex {
98
        /**
99
         * Geotools quadtree implementation
100
         */
101
        QuadTree quadtree;
102
        /**
103
         * Persistent storage
104
         */
105
        String quadtreeFile;
106
        /**
107
         * Spatial index file extension
108
         */
109
        final String qExt = ".qix";
110
        /**
111
         * qix format has many versions, and allows
112
         * different byte orders.
113
         */
114
        String byteOrder;
115
        /**
116
         * Bounds of the layer to index
117
         */
118
        Envelope bounds;
119
        /**
120
         * Number of records of the layer to index
121
         */
122
        int numRecs = 0;
123
        
124
        boolean inMemory = false;
125
        /**
126
         * Constructor.
127
         * You must say a qix file path, and if you want to overwrite this file
128
         * if exists. Also, you must specify how many geometries are going to index,
129
         * and the bounding box of all the geometries.
130
         * 
131
         * 
132
         * @param quadtreeFile qix file path
133
         * @param byteOrder byte order (bigendian, etc)
134
         * @param bounds Rectangle2D of all the geometries to index
135
         * @param numRecords num of geometries to index
136
         * @param overwrite if we want to overwrite a possible existing qix file
137
         * @throws SpatialIndexException
138
         */
139
        public QuadtreeGt2(String quadtreeFile, 
140
                        String byteOrder, 
141
                        Rectangle2D bounds, 
142
                        int numRecords, 
143
                        boolean overwrite) throws SpatialIndexException{
144
                
145
                this.quadtreeFile = quadtreeFile +  qExt;
146
                this.byteOrder = byteOrder;
147
                this.bounds = toJtsEnvelope(bounds);
148
                this.numRecs = numRecords;
149
                
150
                if(exists()){
151
                        if(!overwrite){
152
                                load();
153
                                return;
154
                        }
155
                }
156
                quadtree = new QuadTree(numRecs, this.bounds);
157
        }
158
        
159
        /**
160
         * If the spatial index file exists and has content
161
         */
162
        public boolean exists(){
163
                return (new File(quadtreeFile).length() != 0);
164
        }
165
        
166
        public void load() throws SpatialIndexException{
167
                        try {
168
//                                openQuadTreeInMemory();
169
                                openQuadTree();
170
                        } catch (StoreException e) {
171
                                throw new SpatialIndexException("Error al cargar el fichero qix", e);
172
                        }
173
                
174
        }
175
        
176
        
177
        public List query(Rectangle2D rect) {
178
                try {
179
                        return (List) queryQuadTree(toJtsEnvelope(rect));
180
                } catch (IOException e) {
181
                        // TODO Auto-generated catch block
182
                        e.printStackTrace();
183
                } catch (TreeException e) {
184
                        // TODO Auto-generated catch block
185
                        e.printStackTrace();
186
                } catch (StoreException e) {
187
                        // TODO Auto-generated catch block
188
                        e.printStackTrace();
189
                }
190
                return new ArrayList();
191
        }
192
        
193

    
194
        public void insert(Rectangle2D rect, int index) {
195
                try {
196
                        quadtree.insert(index, toJtsEnvelope(rect));
197
                } catch (StoreException e) {
198
                        // TODO Auto-generated catch block
199
                        e.printStackTrace();
200
                }
201
        }
202
        
203
        public Envelope toJtsEnvelope(Rectangle2D rect){
204
                double xmin = rect.getMinX();
205
                double xmax = rect.getMaxX();
206
                double ymin = rect.getMinY();
207
                double ymax = rect.getMaxY();
208
                return new Envelope(xmin, xmax, ymin, ymax);
209
        }
210
        
211

    
212
        public void delete(Rectangle2D rect, int index) {
213
                if(inMemory)
214
                        quadtree.delete(toJtsEnvelope(rect), index);
215
        }
216
        
217
        void openQuadTree() throws StoreException{
218
                if (quadtree == null) {
219
                        File file = new File(quadtreeFile);
220
                        //Intento de cargar todo el quadtree en memoria
221
                        FileSystemIndexStore store = new FileSystemIndexStore(file);
222
                        quadtree = store.load();
223
                }
224
        }
225
        
226
         void openQuadTreeInMemory() throws StoreException {
227
                if (quadtree == null) {
228
                        File file = new File(quadtreeFile);
229
                        //Intento de cargar todo el quadtree en memoria
230
                        FileSystemIndexStore store = new FileSystemIndexStore(file);
231
                        QuadTree filequadtree = store.load();
232
                        quadtree = new QuadTree(filequadtree.getNumShapes(), 
233
                                        filequadtree.getMaxDepth(), 
234
                                        filequadtree.getRoot().getBounds());
235
                        Stack nodes = new Stack();
236
                        nodes.push(filequadtree.getRoot());
237
                        while(nodes.size() != 0){
238
                                Node node = (Node) nodes.pop();
239
                                Envelope nodeEnv = node.getBounds();
240
                                int[] shapeIds = node.getShapesId();
241
                                for(int i = 0; i < shapeIds.length; i++){
242
                                        quadtree.insert(shapeIds[i], nodeEnv);
243
                                }
244
                                int numSubnodes = node.getNumSubNodes();
245
                                for(int i = 0; i < numSubnodes; i++){
246
                                        nodes.push(node.getSubNode(i));
247
                                }
248
                        }//while
249
                        filequadtree.close();
250
                }
251
        }
252
        
253
        /**
254
         * QuadTree Query
255
         *
256
         * @param bbox
257
         *
258
         * @return
259
         *
260
         * @throws DataSourceException
261
         * @throws IOException
262
         * @throws TreeException
263
         *             DOCUMENT ME!
264
         * @throws StoreException 
265
         */
266
        private Collection queryQuadTree(Envelope bbox) throws 
267
                        IOException, TreeException, StoreException {
268
                
269
        List solution = null;
270
                if ((quadtree != null) ) {
271
                        solution = quadtree.query(bbox);
272
//            tmp = quadtree.search(bbox);
273
//            if( tmp==null || !tmp.isEmpty())
274
//                    return tmp;
275
                
276
                }else
277
                        solution = new ArrayList();
278
//                if( quadtree!=null )
279
//                        quadtree.close();
280
//            return null;
281
                return solution;
282
        }
283
        
284
        public void flush() {
285
                byte order = 0;
286
                if ((byteOrder == null) || byteOrder.equalsIgnoreCase("NM")) {
287
                        order = IndexHeader.NEW_MSB_ORDER;
288
                } else if (byteOrder.equalsIgnoreCase("NL")) {
289
                        order = IndexHeader.NEW_LSB_ORDER;
290
                } 
291
            File file = new File(quadtreeFile);
292
            FileSystemIndexStore store = new FileSystemIndexStore(file, order);
293
            try {
294
                        store.store(quadtree);
295
                } catch (StoreException e) {
296
                        // TODO Auto-generated catch block
297
                        e.printStackTrace();
298
                }
299
        }
300

    
301
        public void close() {
302
                try {
303
                        quadtree.close();
304
                } catch (StoreException e) {
305
                        // TODO Auto-generated catch block
306
                        e.printStackTrace();
307
                }
308
        }
309

    
310
        
311

    
312
        
313
        
314
//        private void buildQuadTree() throws TreeException {
315
//                        ShapeFileIndexer indexer = new ShapeFileIndexer();
316
//                        indexer.setIdxType(ShapeFileIndexer.QUADTREE);
317
//                        indexer.setShapeFileName(shpURL.getPath());
318
//
319
//                        try {
320
//                                indexer.index(false, readWriteLock);
321
//                        } catch (MalformedURLException e) {
322
//                                throw new TreeException(e);
323
//                        } catch (LockTimeoutException e) {
324
//                                throw new TreeException(e);
325
//                        } catch (Exception e) {
326
//                                File f = new File(treeURL.getPath());
327
//
328
//                                if (f.exists()) {
329
//                                        f.delete();
330
//                                }
331
//
332
//                                if (e instanceof TreeException) {
333
//                                        throw (TreeException) e;
334
//                                } else {
335
//                                        throw new TreeException(e);
336
//                                }
337
//                        }
338
//                }
339
}
340

    
341

    
342

    
343

    
344
        /**
345
    private int buildRTree(ShapefileReader reader, File rtreeFile,
346
        boolean verbose)
347
        throws TreeException, LockTimeoutException, IOException {
348
        DataDefinition keyDef = new DataDefinition("US-ASCII");
349
        keyDef.addField(Integer.class);
350
        keyDef.addField(Long.class);
351

352
        FileSystemPageStore fps = new FileSystemPageStore(rtreeFile, keyDef,
353
                this.max, this.min, this.split);
354
        org.geotools.index.rtree.RTree rtree = new org.geotools.index.rtree.RTree(fps);
355
        Record record = null;
356
        Data data = null;
357

358
        int cnt = 0;
359

360
        while (reader.hasNext()) {
361
            record = reader.nextRecord();
362
            data = new Data(keyDef);
363
            
364
            //Aqu? estamos indexando a partir del n?mero de rectangulo
365
            //luego creo que el segundo valor lo podemos obviar.
366
            data.addValue(new Integer(++cnt));
367
            data.addValue(new Long(record.offset()));
368

369
            rtree.insert(new Envelope(record.minX, record.maxX, record.minY,
370
                    record.maxY), data);
371

372
            if (verbose && ((cnt % 500) == 0)) {
373
                System.out.print('.');
374
            }
375
        }
376

377
        rtree.close();
378

379
        return cnt;
380
    }
381
    */
382