Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / spatialindex / QuadtreeGt2.java @ 20701

History | View | Annotate | Download (9.79 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 10627 2007-03-06 17:10:21Z caballero $
47
* $Log$
48
* Revision 1.3  2007-03-06 17:08:59  caballero
49
* Exceptions
50
*
51
* Revision 1.2  2006/11/29 19:27:59  azabala
52
* bug fixed (caused when we query for a bbox which is greater or equal to a layer bbox)
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
                                throw new SpatialIndexException();
173
                        }
174

    
175
        }
176

    
177

    
178
        public List query(Rectangle2D rect) {
179
                try {
180
                        return (List) queryQuadTree(toJtsEnvelope(rect));
181
                } catch (IOException e) {
182
                        // TODO Auto-generated catch block
183
                        e.printStackTrace();
184
                } catch (TreeException e) {
185
                        // TODO Auto-generated catch block
186
                        e.printStackTrace();
187
                } catch (StoreException e) {
188
                        // TODO Auto-generated catch block
189
                        e.printStackTrace();
190
                }
191
                return new ArrayList();
192
        }
193

    
194

    
195
        public void insert(Rectangle2D rect, int index) {
196
                try {
197
                        quadtree.insert(index, toJtsEnvelope(rect));
198
                } catch (StoreException e) {
199
                        // TODO Auto-generated catch block
200
                        e.printStackTrace();
201
                }
202
        }
203

    
204
        public Envelope toJtsEnvelope(Rectangle2D rect){
205
                double xmin = rect.getMinX();
206
                double xmax = rect.getMaxX();
207
                double ymin = rect.getMinY();
208
                double ymax = rect.getMaxY();
209
                return new Envelope(xmin, xmax, ymin, ymax);
210
        }
211

    
212

    
213
        public void delete(Rectangle2D rect, int index) {
214
                if(inMemory)
215
                        quadtree.delete(toJtsEnvelope(rect), index);
216
        }
217

    
218
        void openQuadTree() throws StoreException{
219
                if (quadtree == null) {
220
                        File file = new File(quadtreeFile);
221
                        //Intento de cargar todo el quadtree en memoria
222
                        FileSystemIndexStore store = new FileSystemIndexStore(file);
223
                        quadtree = store.load();
224
                }
225
        }
226

    
227
         void openQuadTreeInMemory() throws StoreException {
228
                if (quadtree == null) {
229
                        File file = new File(quadtreeFile);
230
                        //Intento de cargar todo el quadtree en memoria
231
                        FileSystemIndexStore store = new FileSystemIndexStore(file);
232
                        QuadTree filequadtree = store.load();
233
                        quadtree = new QuadTree(filequadtree.getNumShapes(),
234
                                        filequadtree.getMaxDepth(),
235
                                        filequadtree.getRoot().getBounds());
236
                        Stack nodes = new Stack();
237
                        nodes.push(filequadtree.getRoot());
238
                        while(nodes.size() != 0){
239
                                Node node = (Node) nodes.pop();
240
                                Envelope nodeEnv = node.getBounds();
241
                                int[] shapeIds = node.getShapesId();
242
                                for(int i = 0; i < shapeIds.length; i++){
243
                                        quadtree.insert(shapeIds[i], nodeEnv);
244
                                }
245
                                int numSubnodes = node.getNumSubNodes();
246
                                for(int i = 0; i < numSubnodes; i++){
247
                                        nodes.push(node.getSubNode(i));
248
                                }
249
                        }//while
250
                        filequadtree.close();
251
                }
252
        }
253

    
254
        /**
255
         * QuadTree Query
256
         *
257
         * @param bbox
258
         *
259
         * @return
260
         *
261
         * @throws DataSourceException
262
         * @throws IOException
263
         * @throws TreeException
264
         *             DOCUMENT ME!
265
         * @throws StoreException
266
         */
267
        private Collection queryQuadTree(Envelope bbox) throws
268
                        IOException, TreeException, StoreException {
269

    
270
        List solution = null;
271
                if ((quadtree != null)){
272
                                //&& !bbox.contains(quadtree.getRoot().getBounds())) {
273
                        solution = quadtree.query(bbox);
274
//            tmp = quadtree.search(bbox);
275
//            if( tmp==null || !tmp.isEmpty())
276
//                    return tmp;
277

    
278
                }else
279
                        solution = new ArrayList();
280
//                if( quadtree!=null )
281
//                        quadtree.close();
282
//            return null;
283
                return solution;
284
        }
285

    
286
        public void flush() {
287
                byte order = 0;
288
                if ((byteOrder == null) || byteOrder.equalsIgnoreCase("NM")) {
289
                        order = IndexHeader.NEW_MSB_ORDER;
290
                } else if (byteOrder.equalsIgnoreCase("NL")) {
291
                        order = IndexHeader.NEW_LSB_ORDER;
292
                }
293
            File file = new File(quadtreeFile);
294
            FileSystemIndexStore store = new FileSystemIndexStore(file, order);
295
            try {
296
                        store.store(quadtree);
297
                } catch (StoreException e) {
298
                        // TODO Auto-generated catch block
299
                        e.printStackTrace();
300
                }
301
        }
302

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

    
312

    
313

    
314

    
315

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

    
343

    
344

    
345

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

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

360
        int cnt = 0;
361

362
        while (reader.hasNext()) {
363
            record = reader.nextRecord();
364
            data = new Data(keyDef);
365

366
            //Aqu? estamos indexando a partir del n?mero de rectangulo
367
            //luego creo que el segundo valor lo podemos obviar.
368
            data.addValue(new Integer(++cnt));
369
            data.addValue(new Long(record.offset()));
370

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

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

379
        rtree.close();
380

381
        return cnt;
382
    }
383
    */
384