Revision 5417

View differences:

trunk/libraries/libFMap/src/com/iver/cit/gvsig/fmap/spatialindex/QuadtreeGt2.java
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$
47
* $Log$
48
* Revision 1.1  2006-05-24 21:58:04  azabala
49
* *** empty log message ***
50
*
51
*
52
*/
53
package com.iver.cit.gvsig.fmap.spatialindex;
54

  
55
import java.awt.geom.Rectangle2D;
56
import java.io.File;
57
import java.io.IOException;
58
import java.util.ArrayList;
59
import java.util.Collection;
60
import java.util.List;
61
import java.util.Stack;
62

  
63
import org.geotools.data.DataSourceException;
64
import org.geotools.index.TreeException;
65
import org.geotools.index.quadtree.Node;
66
import org.geotools.index.quadtree.QuadTree;
67
import org.geotools.index.quadtree.StoreException;
68
import org.geotools.index.quadtree.fs.FileSystemIndexStore;
69
import org.geotools.index.quadtree.fs.IndexHeader;
70

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

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

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

  
295
	public void close() {
296
		try {
297
			quadtree.close();
298
		} catch (StoreException e) {
299
			// TODO Auto-generated catch block
300
			e.printStackTrace();
301
		}
302
	}
303

  
304
	
305

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

  
335

  
336

  
337

  
338
	/**
339
    private int buildRTree(ShapefileReader reader, File rtreeFile,
340
        boolean verbose)
341
        throws TreeException, LockTimeoutException, IOException {
342
        DataDefinition keyDef = new DataDefinition("US-ASCII");
343
        keyDef.addField(Integer.class);
344
        keyDef.addField(Long.class);
345

  
346
        FileSystemPageStore fps = new FileSystemPageStore(rtreeFile, keyDef,
347
                this.max, this.min, this.split);
348
        org.geotools.index.rtree.RTree rtree = new org.geotools.index.rtree.RTree(fps);
349
        Record record = null;
350
        Data data = null;
351

  
352
        int cnt = 0;
353

  
354
        while (reader.hasNext()) {
355
            record = reader.nextRecord();
356
            data = new Data(keyDef);
357
            
358
            //Aqu? estamos indexando a partir del n?mero de rectangulo
359
            //luego creo que el segundo valor lo podemos obviar.
360
            data.addValue(new Integer(++cnt));
361
            data.addValue(new Long(record.offset()));
362

  
363
            rtree.insert(new Envelope(record.minX, record.maxX, record.minY,
364
                    record.maxY), data);
365

  
366
            if (verbose && ((cnt % 500) == 0)) {
367
                System.out.print('.');
368
            }
369
        }
370

  
371
        rtree.close();
372

  
373
        return cnt;
374
    }
375
    */
376

  
0 377

  
trunk/libraries/libFMap/src/com/iver/cit/gvsig/fmap/spatialindex/RTreeJsi.java
1
/*
2
 * Created on 15-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$
47
* $Log$
48
* Revision 1.1  2006-05-24 21:58:04  azabala
49
* *** empty log message ***
50
*
51
*
52
*/
53
package com.iver.cit.gvsig.fmap.spatialindex;
54

  
55
import java.awt.Point;
56
import java.awt.geom.Rectangle2D;
57
import java.util.ArrayList;
58
import java.util.List;
59
import java.util.Properties;
60

  
61
import org.geotools.index.quadtree.QuadTree;
62
import org.geotools.index.quadtree.StoreException;
63

  
64
import com.infomatiq.jsi.*;
65
import com.infomatiq.jsi.rtree.*;
66
import com.vividsolutions.jts.geom.Envelope;
67

  
68
/**
69
 * RTree spatial index implementation based in library
70
 * JSI (java spatial index).
71
 * 
72
 * http://jsi.sourceforge.net/
73
 * 
74
 * This RTree has better performance that Spatial Index Library
75
 * RTree, and that JTS'RTree, because
76
 * it uses the GNU's Trove Collections API.
77
 * 
78
 * We are doing some probes with it, because it offers
79
 * a Nearest Neighbour algorithm implementation 
80
 * (useful for Spatial Join geoprocess, for example).
81
 * 
82
 * It isnt persistent, and We've found some problems
83
 * with delete operations.
84
 * 
85
 * 
86
 * 
87
 * 
88
 * @author azabala
89
 *
90
 */
91
public class RTreeJsi implements ISpatialIndex, INearestNeighbourFinder {
92
	private RTree rtree;
93
	
94
	public RTreeJsi(){
95
		rtree = new RTree();
96
	}
97
	
98
	public void create(){
99
		Properties props = new Properties();
100
//		props.setProperty("MaxNodeEntries", "500");
101
//		props.setProperty("MinNodeEntries", "200");
102
		rtree.init(props);
103
	}
104
	
105
	class ListIntProcedure implements IntProcedure{
106
		ArrayList solution = new ArrayList();
107
		
108
		public boolean execute(int arg0) {
109
			solution.add(new Integer(arg0));
110
			return true;
111
		}
112
		
113
		public List getSolution(){
114
			return solution;
115
		}
116
	}
117
	
118
	
119
	public List query(Rectangle2D rect) {
120
		ListIntProcedure solution = new ListIntProcedure();
121
		rtree.intersects(toJsiRect(rect), solution);
122
		return solution.getSolution();
123
	}
124
	
125
	private Rectangle toJsiRect(Rectangle2D rect){
126
		Rectangle jsiRect = new Rectangle((float)rect.getMinX(),
127
				(float)rect.getMinY(),
128
				(float)rect.getMaxX(),
129
				(float)rect.getMaxY());
130
		return jsiRect;
131
	}
132

  
133
	public void insert(Rectangle2D rect, int index) {
134
		rtree.add(toJsiRect(rect), index);
135
	}
136

  
137
	public void delete(Rectangle2D rect, int index) {
138
		rtree.delete(toJsiRect(rect), index);
139
	}
140

  
141
	public List findNNearest(int numberOfNearest, Point point) {
142
		ListIntProcedure solution = new ListIntProcedure();
143
		com.infomatiq.jsi.Point jsiPoint =
144
			new com.infomatiq.jsi.Point(point.x, point.y);
145
		//FIXME REVISAR
146
		rtree.nearest(jsiPoint, solution, Float.POSITIVE_INFINITY);
147
		return solution.getSolution();
148
	}
149

  
150
	public List findNNearest(int numberOfNearest, Rectangle2D rect) {
151
		throw new IllegalArgumentException("Metodo no implementado");
152
	}
153
	
154
	public static void main(String[] args){
155
		RTreeJsi q = new RTreeJsi();
156
		q.create();
157
		
158
			for(int i = 1; i <= 99; i++){
159
				q.insert(new Rectangle2D.Double(100+i, 200+i, 200+i, 500+i),i);
160
			}
161
		
162
			for(int i = 1; i <= 99; i++){
163
				q.delete(new Rectangle2D.Double(100+i, 200+i, 200+i, 500+i),i);
164
				System.out.println("Rect="+i);
165
			}
166
	}
167

  
168
}
169

  
0 170

  
trunk/libraries/libFMap/.classpath
16 16
	<classpathentry kind="lib" path="lib/jts-1.7.jar"/>
17 17
	<classpathentry kind="lib" path="lib/jtsio-1.7.jar"/>
18 18
	<classpathentry kind="lib" path="/_fwAndami/lib/castor-0.9.5.3-xml.jar"/>
19
	<classpathentry sourcepath="/libIverUtiles" kind="lib" path="/_fwAndami/lib/iver-utiles.jar"/>
20 19
	<classpathentry kind="lib" path="/_fwAndami/lib/log4j-1.2.8.jar"/>
21 20
	<classpathentry kind="lib" path="lib/driver-manager-1.1.jar"/>
22 21
	<classpathentry kind="lib" path="lib/spatialindex.jar"/>
22
	<classpathentry kind="lib" path="lib/trove-0.1.8.jar"/>
23
	<classpathentry kind="lib" path="lib/gt2sidx.jar"/>
24
	<classpathentry sourcepath="/Utiles/src" kind="lib" path="/_fwAndami/lib/iver-utiles.jar"/>
23 25
	<classpathentry kind="output" path="bin"/>
24 26
</classpath>

Also available in: Unified diff