Statistics
| Revision:

root / branches / v2_0_0_prep / libraries / libFMap_dalindex / src / org / gvsig / fmap / dal / index / spatial / gt2 / GT2Quadtree.java @ 29326

History | View | Annotate | Download (10.2 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 org.gvsig.fmap.dal.index.spatial.gt2;
60

    
61
import java.io.File;
62
import java.io.IOException;
63
import java.util.List;
64
import java.util.Stack;
65

    
66
import org.geotools.index.quadtree.Node;
67
import org.geotools.index.quadtree.QuadTree;
68
import org.geotools.index.quadtree.StoreException;
69
import org.geotools.index.quadtree.fs.FileSystemIndexStore;
70
import org.geotools.index.quadtree.fs.IndexHeader;
71
import org.gvsig.fmap.dal.exception.InitializeException;
72
import org.gvsig.fmap.dal.feature.FeatureStore;
73
import org.gvsig.fmap.dal.feature.exception.FeatureIndexException;
74
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
75
import org.gvsig.fmap.dal.feature.spi.index.AbstractFeatureIndexProvider;
76
import org.gvsig.fmap.dal.feature.spi.index.FeatureIndexProvider;
77
import org.gvsig.fmap.geom.Geometry;
78
import org.gvsig.fmap.geom.primitive.Point;
79
import org.gvsig.tools.exception.BaseException;
80

    
81
import com.vividsolutions.jts.geom.Envelope;
82

    
83
/**
84
 * This Quadtree spatial index implementation is based in a fork of
85
 * org.geotools.index.quadtree.Quadtree implementation. <br>
86
 * This implementation offers us:
87
 * <ol>
88
 * <li>Persistence of spatial index</li>
89
 * </ol>
90
 * We had to fork geotools quadtree for many reasons:
91
 * <ol>
92
 * <li>It was strongly dependent of SHP format, so it returned not only a num
93
 * of rectangle, it also returned byte offset of this rectangle in shp file</li>
94
 * <li> Query artifact wasnt run well at all </li>
95
 * </ol>
96
 *
97
 * @author azabala
98
 *
99
 */
100
public class GT2Quadtree extends AbstractFeatureIndexProvider implements FeatureIndexProvider {
101

    
102
        public static final String NAME = GT2Quadtree.class.getSimpleName();
103
        /**
104
         * Geotools quadtree implementation
105
         */
106
        QuadTree quadtree;
107
        /**
108
         * Persistent storage
109
         */
110
        String fileName;
111
        /**
112
         * Spatial index file extension
113
         */
114
        final String qExt = ".qix";
115
        /**
116
         * qix format has many versions, and allows different byte orders.
117
         */
118
        String byteOrder;
119
        /**
120
         * Bounds of the layer to index
121
         */
122
        //Envelope bounds;
123
        /**
124
         * Number of records of the layer to index
125
         */
126
        //int numRecs = 0;
127

    
128
        boolean inMemory = false;
129

    
130
        public GT2Quadtree() {
131

    
132
        }
133

    
134
        public void initialize() throws InitializeException {
135
                try {
136
                        File file = File.createTempFile(getFeatureStore().getName(), ".qix");
137
                        this.fileName = file.getAbsolutePath();
138
                        org.gvsig.fmap.geom.primitive.Envelope env = getFeatureStore()
139
                                        .getEnvelope();
140
                        int featureCount = (int) getFeatureStore().getFeatureSet().getSize();
141
                        this.byteOrder = "NM";
142
                        quadtree = new QuadTree(featureCount, toJtsEnvelope(env));
143
                        if (exists()) {
144
                                load();
145
                        }
146
                } catch (IOException e) {
147
                        throw new InitializeException(e);
148
                } catch (BaseException e) {
149
                        throw new InitializeException(e);
150
                }
151
        }
152

    
153
        /**
154
         * If the spatial index file exists and has content
155
         */
156
        public boolean exists() {
157
                return (new File(fileName).length() != 0);
158
        }
159

    
160
        public void load() throws FeatureIndexException {
161
                if (quadtree == null) {
162
                        load(new File(fileName));
163
                }
164
        }
165

    
166
        public void load(File f) throws FeatureIndexException {
167
                try {
168
                        FileSystemIndexStore store = new FileSystemIndexStore(f);
169
                        quadtree = store.load();
170
                        this.fileName = f.getAbsolutePath();
171
                } catch (StoreException e) {
172
                        throw new FeatureIndexException(e);
173
                }
174
        }
175

    
176
        /**
177
         * Inserts an object in the index
178
         */
179
        public void insert(org.gvsig.fmap.geom.primitive.Envelope env, int index) {
180
                if (env == null) {
181
                        throw new IllegalArgumentException("Envelope cannot be null");
182
                }
183
                Envelope e = toJtsEnvelope(env);
184
                if (e == null) {
185
                        throw new IllegalStateException(
186
                                        "JTS Envelope conversion returns null");
187
                }
188
                System.out.println("recno=" + index);
189
                if (quadtree == null) {
190
                        throw new IllegalStateException("quadtree is null");
191
                }
192
                try {
193
                        quadtree.insert(index, toJtsEnvelope(env));
194
                } catch (StoreException se) {
195
                        // TODO Auto-generated catch block
196
                        se.printStackTrace();
197
                }
198
        }
199

    
200
        public void delete(org.gvsig.fmap.geom.primitive.Envelope env, int index) {
201
                if (inMemory) {
202
                        quadtree.delete(toJtsEnvelope(env), index);
203
                }
204
        }
205

    
206
        public Envelope toJtsEnvelope(org.gvsig.fmap.geom.primitive.Envelope env) {
207
                if (env == null) {
208
                        return null;
209
                }
210
                Point min = env.getLowerCorner();
211
                Point max = env.getUpperCorner();
212

    
213
                return new Envelope(min.getX(), max.getX(), min.getY(), max.getY());
214
        }
215

    
216
        /**
217
         *
218
         * @throws StoreException
219
         * @deprecated
220
         */
221
        void openQuadTree() throws StoreException {
222
                if (quadtree == null) {
223
                        File file = new File(this.fileName);
224
                        // Intento de cargar todo el quadtree en memoria
225
                        FileSystemIndexStore store = new FileSystemIndexStore(file);
226
                        quadtree = store.load();
227
                }
228
        }
229

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

    
256
        public void flush() throws FeatureIndexException {
257
                flush(new File(fileName));
258
        }
259

    
260
        public void flush(File f) throws FeatureIndexException {
261
                byte order = 0;
262
                if ((byteOrder == null) || byteOrder.equalsIgnoreCase("NM")) {
263
                        order = IndexHeader.NEW_MSB_ORDER;
264
                } else if (byteOrder.equalsIgnoreCase("NL")) {
265
                        order = IndexHeader.NEW_LSB_ORDER;
266
                }
267
                FileSystemIndexStore store = new FileSystemIndexStore(f, order);
268
                try {
269
                        store.store(quadtree);
270
                        this.fileName = f.getAbsolutePath();
271
                } catch (StoreException e) {
272
                        throw new FeatureIndexException(e);
273
                }
274
        }
275

    
276
        public File getFile() {
277
                return new File(this.fileName);
278
        }
279

    
280
        private FeatureStore getFeatureStore() {
281
                return getFeatureIndexProviderServices()
282
                                .getFeatureStoreProviderServices().getFeatureStore();
283
        }
284

    
285
        public void delete(Object value, FeatureReferenceProviderServices fref) {
286

    
287
                if (!isCompatibleOID(fref.getOID())) {
288
                        throw new IllegalArgumentException("OID not compatible. Must be an instance of Number within the Integer range.");
289
                }
290

    
291
                delete(((org.gvsig.fmap.geom.Geometry) value).getEnvelope(), ((Number) fref.getOID()).intValue());
292
        }
293

    
294
        public void insert(Object value, FeatureReferenceProviderServices fref) {
295

    
296
                if (!isCompatibleOID(fref.getOID())) {
297
                        throw new IllegalArgumentException("OID not compatible. Must be an instance of Number within the Integer range.");
298
                }
299

    
300
                insert(((org.gvsig.fmap.geom.Geometry) value).getEnvelope(), ((Number) fref.getOID()).intValue());
301
        }
302

    
303
        public List match(Object value) throws FeatureIndexException {
304
                if (quadtree == null) {
305
                        throw new IllegalStateException("This quadtree is null.");
306
                }
307
                if (value == null) {
308
                        throw new IllegalArgumentException("Envelope cannot be null.");
309
                }
310
                if (!(value instanceof org.gvsig.fmap.geom.primitive.Envelope)) {
311
                        throw new IllegalArgumentException("Not an envelope.");
312
                }
313
                org.gvsig.fmap.geom.primitive.Envelope env = null;
314
                if (value instanceof org.gvsig.fmap.geom.primitive.Envelope) {
315
                        env = (org.gvsig.fmap.geom.primitive.Envelope) value;
316
                } else if (value instanceof Geometry) {
317
                        env = ((Geometry) value).getEnvelope();
318
                }
319
                return new LongList(quadtree.query(toJtsEnvelope(env)));
320
        }
321

    
322
        public List nearest(int count, Object value) throws FeatureIndexException {
323
                throw new UnsupportedOperationException();
324
        }
325

    
326
        public boolean isMatchSupported() {
327
                return true;
328
        }
329

    
330
        public boolean isNearestSupported() {
331
                return false;
332
        }
333

    
334
        public boolean isNearestToleranceSupported() {
335
                return false;
336
        }
337

    
338
        public boolean isRangeSupported() {
339
                return false;
340
        }
341

    
342
        public List nearest(int count, Object value, Object tolerance)
343
                        throws FeatureIndexException {
344
                throw new UnsupportedOperationException();
345
        }
346

    
347
        public List range(Object value1, Object value2) throws FeatureIndexException {
348
                throw new UnsupportedOperationException();
349
        }
350

    
351
        /**
352
         * Indicates whether the given OID's type is compatible
353
         * with this provider
354
         *
355
         * @param oid
356
         *
357
         * @return
358
         *                 true if this index provider supports the given oid type
359
         */
360
        private boolean isCompatibleOID(Object oid) {
361
                if (!(oid instanceof Number)) {
362
                        return false;
363
                }
364

    
365
                long num = ((Number) oid).longValue();
366

    
367
                if (num > Integer.MAX_VALUE || num < Integer.MIN_VALUE) {
368
                        return false;
369
                }
370

    
371
                return true;
372
        }
373

    
374
}