Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / libraries / libFMap_dalindex / src / org / gvsig / fmap / dal / index / spatial / gt2 / GT2Quadtree.java @ 40370

History | View | Annotate | Download (12 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 com.vividsolutions.jts.geom.Envelope;
67

    
68
import org.geotools.index.quadtree.Node;
69
import org.geotools.index.quadtree.QuadTree;
70
import org.geotools.index.quadtree.StoreException;
71
import org.geotools.index.quadtree.fs.FileSystemIndexStore;
72
import org.geotools.index.quadtree.fs.IndexHeader;
73

    
74
import org.gvsig.fmap.dal.exception.DataException;
75
import org.gvsig.fmap.dal.exception.InitializeException;
76
import org.gvsig.fmap.dal.feature.FeatureStore;
77
import org.gvsig.fmap.dal.feature.exception.FeatureIndexException;
78
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
79
import org.gvsig.fmap.dal.feature.spi.index.AbstractFeatureIndexProvider;
80
import org.gvsig.fmap.dal.feature.spi.index.FeatureIndexProvider;
81
import org.gvsig.fmap.geom.Geometry;
82
import org.gvsig.fmap.geom.primitive.Point;
83
import org.gvsig.tools.exception.BaseException;
84

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

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

    
131
    boolean inMemory = false;
132

    
133
    public GT2Quadtree() {
134

    
135
    }
136

    
137
    public void initialize() throws InitializeException {
138
        try {
139
            File file =
140
                File.createTempFile(getFeatureStore().getName(), ".qix");
141
            this.fileName = file.getAbsolutePath();
142
            this.byteOrder = "NM";
143
            this.quadtree = createQuadTree();
144
            if (exists()) {
145
                load();
146
            }
147
        } catch (IOException e) {
148
            throw new InitializeException(e);
149
        } catch (BaseException e) {
150
            throw new InitializeException(e);
151
        }
152
    }
153

    
154
    /**
155
     * @return
156
     * @throws DataException
157
     */
158
    private QuadTree createQuadTree() throws DataException {
159
        org.gvsig.fmap.geom.primitive.Envelope env =
160
            getFeatureStore().getEnvelope();
161
        int featureCount = (int) getFeatureStore().getFeatureCount();
162
        return new QuadTree(featureCount, toJtsEnvelope(env));
163
    }
164

    
165
    /**
166
     * If the spatial index file exists and has content
167
     */
168
    public boolean exists() {
169
        return (new File(fileName).length() != 0);
170
    }
171

    
172
    public void load() throws FeatureIndexException {
173
        if (quadtree == null) {
174
            load(new File(fileName));
175
        }
176
    }
177

    
178
    public void load(File f) throws FeatureIndexException {
179
        try {
180
            FileSystemIndexStore store = new FileSystemIndexStore(f);
181
            quadtree = store.load();
182
            this.fileName = f.getAbsolutePath();
183
        } catch (StoreException e) {
184
            throw new FeatureIndexException(e);
185
        }
186
    }
187

    
188
    /**
189
     * Inserts an object in the index
190
     */
191
    public void insert(org.gvsig.fmap.geom.primitive.Envelope env, int index) {
192
        if (env == null) {
193
            throw new IllegalArgumentException("Envelope cannot be null");
194
        }
195
        Envelope e = toJtsEnvelope(env);
196
        if (e == null) {
197
            throw new IllegalStateException(
198
                "JTS Envelope conversion returns null");
199
        }
200
        System.out.println("recno=" + index);
201
        if (quadtree == null) {
202
            throw new IllegalStateException("quadtree is null");
203
        }
204
        try {
205
            quadtree.insert(index, toJtsEnvelope(env));
206
        } catch (StoreException se) {
207
            // TODO Auto-generated catch block
208
            se.printStackTrace();
209
        }
210
    }
211

    
212
    public void delete(org.gvsig.fmap.geom.primitive.Envelope env, int index) {
213
        if (inMemory) {
214
            quadtree.delete(toJtsEnvelope(env), index);
215
        }
216
    }
217

    
218
    public Envelope toJtsEnvelope(org.gvsig.fmap.geom.primitive.Envelope env) {
219
        if (env == null) {
220
            return null;
221
        }
222
        Point min = env.getLowerCorner();
223
        Point max = env.getUpperCorner();
224

    
225
        return new Envelope(min.getX(), max.getX(), min.getY(), max.getY());
226
    }
227

    
228
    /**
229
     * 
230
     * @throws StoreException
231
     * @deprecated
232
     */
233
    void openQuadTree() throws StoreException {
234
        if (quadtree == null) {
235
            File file = new File(this.fileName);
236
            // Intento de cargar todo el quadtree en memoria
237
            FileSystemIndexStore store = new FileSystemIndexStore(file);
238
            quadtree = store.load();
239
        }
240
    }
241

    
242
    void openQuadTreeInMemory() throws StoreException {
243
        if (quadtree == null) {
244
            File file = new File(fileName);
245
            // Intento de cargar todo el quadtree en memoria
246
            FileSystemIndexStore store = new FileSystemIndexStore(file);
247
            QuadTree filequadtree = store.load();
248
            quadtree =
249
                new QuadTree(filequadtree.getNumShapes(),
250
                    filequadtree.getMaxDepth(), filequadtree.getRoot()
251
                        .getBounds());
252
            Stack nodes = new Stack();
253
            nodes.push(filequadtree.getRoot());
254
            while (nodes.size() != 0) {
255
                Node node = (Node) nodes.pop();
256
                Envelope nodeEnv = node.getBounds();
257
                int[] shapeIds = node.getShapesId();
258
                for (int i = 0; i < shapeIds.length; i++) {
259
                    quadtree.insert(shapeIds[i], nodeEnv);
260
                }
261
                int numSubnodes = node.getNumSubNodes();
262
                for (int i = 0; i < numSubnodes; i++) {
263
                    nodes.push(node.getSubNode(i));
264
                }
265
            }// while
266
            filequadtree.close();
267
        }
268
    }
269

    
270
    public void flush() throws FeatureIndexException {
271
        flush(new File(fileName));
272
    }
273

    
274
    public void flush(File f) throws FeatureIndexException {
275
        byte order = 0;
276
        if ((byteOrder == null) || byteOrder.equalsIgnoreCase("NM")) {
277
            order = IndexHeader.NEW_MSB_ORDER;
278
        } else
279
            if (byteOrder.equalsIgnoreCase("NL")) {
280
                order = IndexHeader.NEW_LSB_ORDER;
281
            }
282
        FileSystemIndexStore store = new FileSystemIndexStore(f, order);
283
        try {
284
            store.store(quadtree);
285
            this.fileName = f.getAbsolutePath();
286
        } catch (StoreException e) {
287
            throw new FeatureIndexException(e);
288
        }
289
    }
290

    
291
    public File getFile() {
292
        return new File(this.fileName);
293
    }
294

    
295
    private FeatureStore getFeatureStore() {
296
        return getFeatureIndexProviderServices()
297
            .getFeatureStoreProviderServices().getFeatureStore();
298
    }
299

    
300
    public void delete(Object value, FeatureReferenceProviderServices fref) {
301

    
302
        if (!isCompatibleOID(fref.getOID())) {
303
            throw new IllegalArgumentException(
304
                "OID not compatible. Must be an instance of Number within the Integer range.");
305
        }
306

    
307
        delete(((org.gvsig.fmap.geom.Geometry) value).getEnvelope(),
308
            ((Number) fref.getOID()).intValue());
309
    }
310

    
311
    public void insert(Object value, FeatureReferenceProviderServices fref) {
312

    
313
        if (!isCompatibleOID(fref.getOID())) {
314
            throw new IllegalArgumentException(
315
                "OID not compatible. Must be an instance of Number within the Integer range.");
316
        }
317

    
318
        insert(((org.gvsig.fmap.geom.Geometry) value).getEnvelope(),
319
            ((Number) fref.getOID()).intValue());
320
    }
321

    
322
    public List match(Object value) throws FeatureIndexException {
323
        if (quadtree == null) {
324
            throw new IllegalStateException("This quadtree is null.");
325
        }
326
        if (value == null) {
327
            throw new IllegalArgumentException("Envelope cannot be null.");
328
        }
329
        if (!(value instanceof org.gvsig.fmap.geom.primitive.Envelope)) {
330
            throw new IllegalArgumentException("Not an envelope.");
331
        }
332
        org.gvsig.fmap.geom.primitive.Envelope env = null;
333
        if (value instanceof org.gvsig.fmap.geom.primitive.Envelope) {
334
            env = (org.gvsig.fmap.geom.primitive.Envelope) value;
335
        } else
336
            if (value instanceof Geometry) {
337
                env = ((Geometry) value).getEnvelope();
338
            }
339
        return new LongList(quadtree.query(toJtsEnvelope(env)));
340
    }
341

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

    
346
    public boolean isMatchSupported() {
347
        return true;
348
    }
349

    
350
    public boolean isNearestSupported() {
351
        return false;
352
    }
353

    
354
    public boolean isNearestToleranceSupported() {
355
        return false;
356
    }
357

    
358
    public boolean isRangeSupported() {
359
        return false;
360
    }
361

    
362
    public List nearest(int count, Object value, Object tolerance)
363
        throws FeatureIndexException {
364
        throw new UnsupportedOperationException();
365
    }
366

    
367
    public List range(Object value1, Object value2)
368
        throws FeatureIndexException {
369
        throw new UnsupportedOperationException();
370
    }
371

    
372
    /**
373
     * Indicates whether the given OID's type is compatible
374
     * with this provider
375
     * 
376
     * @param oid
377
     * 
378
     * @return
379
     *         true if this index provider supports the given oid type
380
     */
381
    private boolean isCompatibleOID(Object oid) {
382
        if (!(oid instanceof Number)) {
383
            return false;
384
        }
385

    
386
        long num = ((Number) oid).longValue();
387

    
388
        if ((num > Integer.MAX_VALUE) || (num < Integer.MIN_VALUE)) {
389
            return false;
390
        }
391

    
392
        return true;
393
    }
394

    
395
    public void clear() throws DataException {
396
        this.quadtree = createQuadTree();
397
    }
398

    
399
}