Statistics
| Revision:

root / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / drivers / featureiterators / SpatialQueryFeatureIterator.java @ 13873

History | View | Annotate | Download (11.5 KB)

1
/*
2
 * Created on 12-abr-2007
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: SpatialQueryFeatureIterator.java 13873 2007-09-19 16:02:29Z azabala $
47
 * $Log$
48
 * Revision 1.4  2007-09-19 16:02:29  azabala
49
 * bug solved (feature returned by iterator has the attributes of the next record)
50
 *
51
 * Revision 1.3  2007/06/07 09:30:09  azabala
52
 * refactor of BOUND FACTOR
53
 *
54
 * Revision 1.2  2007/06/06 18:03:03  azabala
55
 * bug fixed
56
 *
57
 * Revision 1.1  2007/05/29 19:08:11  azabala
58
 * first version in cvs
59
 *
60
 * Revision 1.1  2007/04/19 17:27:58  azabala
61
 * first version in cvs
62
 *
63
 *
64
 */
65
package com.iver.cit.gvsig.fmap.drivers.featureiterators;
66

    
67
import java.awt.geom.Rectangle2D;
68

    
69
import org.cresques.cts.ICoordTrans;
70
import org.cresques.cts.IProjection;
71
import org.geotools.resources.geometry.XRectangle2D;
72

    
73
import com.hardcode.gdbms.driver.exceptions.ReadDriverException;
74
import com.hardcode.gdbms.engine.values.Value;
75
import com.iver.cit.gvsig.exceptions.expansionfile.ExpansionFileReadException;
76
import com.iver.cit.gvsig.fmap.core.DefaultFeature;
77
import com.iver.cit.gvsig.fmap.core.IFeature;
78
import com.iver.cit.gvsig.fmap.core.IGeometry;
79
import com.iver.cit.gvsig.fmap.drivers.BoundedShapes;
80
import com.iver.cit.gvsig.fmap.layers.ReadableVectorial;
81

    
82
public class SpatialQueryFeatureIterator extends DefaultFeatureIterator {
83

    
84
        /**
85
         * region for which features we are iterating
86
         */
87
        protected Rectangle2D rect;
88
        
89
        /**
90
         * Checks feature geometries to see if intersects the given extent filter
91
         */
92
        protected ISpatialCheck spatialChecker;
93

    
94
        /**
95
         * Feature which will be returned the next time
96
         */
97
        IFeature nextFeature = null;
98
        
99
        /**
100
         * Proportion of query extent area and layer extent area
101
         * to use boundedshapes capability (reading bounds without
102
         * reading its geometry) 
103
         * 
104
         */
105
        public static final double BOUNDED_SHAPES_FACTOR = 4.0d;
106

    
107
        /**
108
         * Constructor.
109
         * 
110
         * @param source
111
         *            vectorial data source
112
         * @param sourceProj
113
         *            original projection of the data (it could be null)
114
         * @param targetProj
115
         *            projection of the returned features
116
         * @param fieldNames
117
         * @param spatialQuery
118
         * @throws ReadDriverException
119
         */
120
        public SpatialQueryFeatureIterator(ReadableVectorial source,
121
                        IProjection sourceProj, IProjection targetProj,
122
                        String[] fieldNames, Rectangle2D spatialQuery, boolean fastIteration)
123
                        throws ReadDriverException {
124
                super(source, sourceProj, targetProj, fieldNames);
125
                setRect(spatialQuery);
126
                if(fastIteration)
127
                        spatialChecker = new FastSpatialCheck();
128
                else
129
                        spatialChecker = new PrecisseSpatialCheck();
130
        }
131

    
132
        public Rectangle2D getRect() {
133
                return rect;
134
        }
135

    
136
        public void setRect(Rectangle2D rect) {
137
                //by design, rect Rectangle2D must be in the target reprojection
138
                //if targetReprojection != sourceReprojection, we are going to reproject
139
                //rect to the source reprojection (is faster).
140
                //once spatial check is made, result features will be reprojected in the inverse direction
141
                if(this.targetProjection != null && 
142
                   this.sourceProjection != null &&
143
                   this.targetProjection.getAbrev() != this.sourceProjection.getAbrev()){
144
                        ICoordTrans trans = targetProjection.getCT(sourceProjection);
145
                        rect = trans.convert(rect);
146
                }
147
                this.rect = rect;
148
        }
149

    
150
        public boolean hasNext() throws ReadDriverException {
151
                try {
152
                        while(true){
153
                                if(currentFeature >= source.getShapeCount())
154
                                        return false;
155
                                if(spatialChecker.intersects(rect, currentFeature)){
156
                                        //we only update the counter if spatialChecker could read the geometry
157
                                        //if it is boundedshape it doesnt read the geometry, so we need to read 
158
                                        //currentFeature again 
159
//                                        if(spatialChecker.returnShapes())
160
//                                                currentFeature++;
161
                                        break;
162
                                }
163
                                else
164
                                        currentFeature++;
165
                        }//while
166
                        
167
                        
168
                        //here, currentFeature intersects with the rectangle2d filter
169
                        IGeometry geom = null;
170
                        IFeature feat = null;
171
                        if(spatialChecker.returnShapes()){
172
                                geom = spatialChecker.getLastGeometry();
173
                        }else{
174
                                geom = source.getShape(currentFeature);
175
//                                currentFeature++;
176
                                reprojectIfNecessary(geom);
177
                        }
178
                        Value[] regAtt = getValues(currentFeature);
179
                        feat = new DefaultFeature(geom, regAtt, currentFeature + "");
180
                        nextFeature = feat;
181
                        currentFeature++;
182
                        return true;
183
                } catch (ExpansionFileReadException e) {
184
                        throw new ReadDriverException(
185
                                        "Error accediendo a datos del driver durante la iteracion",
186
                                        e);
187
                }
188
        }
189

    
190
        public IFeature next() throws ReadDriverException {
191
                return nextFeature;
192
        }
193

    
194
        /**
195
         * Classes that chekcs if a specified feature intersects with a given Rectangle2D must
196
         * implement this interface.
197
         * 
198
         * This interface is necessary because there are many approach to do that
199
         * (an exact intersection, an intersection based in bounds2d, etc)
200
         * 
201
         * 
202
         * @author azabala
203
         *
204
         */
205
        interface ISpatialCheck {
206
                public boolean intersects(Rectangle2D extent, int featureIndex)
207
                                throws ExpansionFileReadException, ReadDriverException;
208
                
209
                /**
210
                 * Tells if this spatialcheck could return the geometry of the features
211
                 * (or if it is boundedshapes based, needs another driver access operation)
212
                 * @return
213
                 */
214
                public boolean returnShapes();
215
                /**
216
                 * Returns the last readed geometry (if the spatialcheck do that)
217
                 * @return
218
                 */
219
                public IGeometry getLastGeometry();
220
                
221
                /**
222
                 * Return the index of the last readed geometry
223
                 * @return
224
                 */
225
                public int getIndexOfLast();
226

    
227
                
228
        }
229
        
230
        
231
        
232

    
233
        /**
234
         * All classes that return the bounds Rectangle2D of a feature must
235
         * implement this interface.
236
         * 
237
         * @author azabala
238
         * 
239
         */
240
        interface BoundsProvider {
241
                /**
242
                 * Returns the bound of the specified feature index
243
                 * 
244
                 * @param featureIndex
245
                 * @return
246
                 * @throws ExpansionFileReadException
247
                 * @throws ReadDriverException
248
                 */
249
                public Rectangle2D getBounds(int featureIndex)
250
                                throws ExpansionFileReadException, ReadDriverException;
251

    
252
                /**
253
                 * Tells if this boundsProvider could returns shapes
254
                 * 
255
                 * @return
256
                 */
257
                public boolean returnShapes();
258

    
259
                /**
260
                 * Returns the last geometry readed, if the boundsProvider could do that
261
                 * 
262
                 * @return
263
                 */
264
                public IGeometry getLastGeometry();
265
        }
266

    
267
        
268
        
269
        
270
        /**
271
         * BoundsProvider that uses a BoundedShapes (faster than others)
272
         * 
273
         * @author azabala
274
         * 
275
         */
276
        class BoundedShapesProvider implements BoundsProvider {
277
                BoundedShapes boundedShapes;
278

    
279
                BoundedShapesProvider(BoundedShapes boundedShapes) {
280
                        this.boundedShapes = boundedShapes;
281
                }
282

    
283
                public Rectangle2D getBounds(int featureIndex)
284
                                throws ExpansionFileReadException, ReadDriverException {
285
                        return boundedShapes.getShapeBounds(featureIndex);
286
                }
287

    
288
                public boolean returnShapes() {
289
                        return false;
290
                }
291

    
292
                public IGeometry getLastGeometry() {
293
                        return null;
294
                }
295

    
296
        }
297

    
298
        
299
        
300
        
301
        /**
302
         * BoundsProvider that returns feature bounds from the feature geometry
303
         * 
304
         * @author azabala
305
         * 
306
         */
307
        class IGeometryBoundProvider implements BoundsProvider {
308
                /**
309
                 * Adapter of a given driver from which we read the features bounds.
310
                 */
311
                ReadableVectorial source;
312

    
313
                IGeometry lastGeometry;
314

    
315
                IGeometryBoundProvider(ReadableVectorial sourceOfFeatures) {
316
                        this.source = sourceOfFeatures;
317
                }
318

    
319
                public Rectangle2D getBounds(int featureIndex)
320
                                throws ExpansionFileReadException, ReadDriverException {
321
                        lastGeometry = source.getShape(featureIndex);
322
                        //bounds2D is in the original projection
323
                        Rectangle2D solution = lastGeometry.getBounds2D();
324
                        //the readed geometry in the specified projection
325
                        reprojectIfNecessary(this.lastGeometry);
326
                        return solution;
327
                }
328

    
329
                public IGeometry getLastGeometry() {
330
                        return lastGeometry;
331
                }
332

    
333
                public boolean returnShapes() {
334
                        return true;
335
                }
336

    
337
        }
338

    
339
        
340
        
341
        
342
        /**
343
         * Checks if the specified features intersects with rectangle2D instances in
344
         * a rough but fast manner.
345
         * 
346
         */
347
        class FastSpatialCheck implements ISpatialCheck {
348
                BoundsProvider boundProvider;
349
                int lastIndex;
350
                
351
                
352
                FastSpatialCheck() {
353
                        try {
354
                                if(isBoundedShapesNecessary()){        
355
                                        if (source instanceof BoundedShapes){
356
                                                boundProvider = new BoundedShapesProvider(
357
                                                                (BoundedShapes) source);
358
                                        }else if (source.getDriver() instanceof BoundedShapes){
359
                                                boundProvider = new BoundedShapesProvider(
360
                                                                (BoundedShapes) source.getDriver());
361
                                    }
362
                                }else{
363
                                                boundProvider = new IGeometryBoundProvider(source);
364
                                }
365
                        } catch (ExpansionFileReadException e) {
366
                                // TODO Auto-generated catch block
367
                                e.printStackTrace();
368
                                boundProvider = new IGeometryBoundProvider(source);
369
                        } catch (ReadDriverException e) {
370
                                // TODO Auto-generated catch block
371
                                e.printStackTrace();
372
                                boundProvider = new IGeometryBoundProvider(source);
373
                        }
374
                }
375
                
376
                
377
                protected boolean isBoundedShapesNecessary() throws ReadDriverException, ExpansionFileReadException {
378
                        Rectangle2D driverExtent = source.getFullExtent();
379
                        double areaExtent = rect.getWidth() * rect.getHeight();
380
                        double areaFullExtent = driverExtent.getWidth() *
381
                                                         driverExtent.getHeight();
382
                        return areaExtent < (areaFullExtent / BOUNDED_SHAPES_FACTOR);
383

    
384
                }
385

    
386
                public boolean intersects(Rectangle2D extent, int featureIndex)
387
                                throws ExpansionFileReadException, ReadDriverException {
388
                        this.lastIndex = featureIndex;
389
                        Rectangle2D featureBounds = boundProvider.getBounds(featureIndex);
390
                        return XRectangle2D.intersectInclusive(extent, featureBounds);
391
                }
392

    
393
                public BoundsProvider getBoundsProvider() {
394
                        return boundProvider;
395
                }
396

    
397
                public boolean returnShapes() {
398
                        return boundProvider.returnShapes();
399
                }
400

    
401
                public IGeometry getLastGeometry() {
402
                        return boundProvider.getLastGeometry();
403
                }
404

    
405
                public int getIndexOfLast() {
406
                        return lastIndex;
407
                }
408

    
409
        }// FastSpatialCheck
410

    
411
        
412
        /**
413
         * Checks if the specified features intersect with rectangle2D instances in
414
         * a precisse manner
415
         * 
416
         * @author azabala
417
         * 
418
         */
419

    
420
        class PrecisseSpatialCheck implements ISpatialCheck {
421
                IGeometry lastGeometry;
422
                int lastIndex;
423

    
424
                PrecisseSpatialCheck() {
425
                }
426

    
427
                public boolean intersects(Rectangle2D extent, int featureIndex)
428
                                throws ExpansionFileReadException, ReadDriverException {
429
                        this.lastIndex = featureIndex;
430
                        this.lastGeometry = source.getShape(lastIndex);
431
                        //the spatial check is made in the original projection
432
                        boolean solution = lastGeometry.fastIntersects(rect.getMinX(),
433
                                        rect.getMinY(), rect.getWidth(), rect.getHeight());
434
                        //but the solution is returned in the new projection (if applies)
435
                        reprojectIfNecessary(lastGeometry);
436
                        return solution;
437
                }
438

    
439
                public boolean returnShapes() {
440
                        return true;
441
                }
442

    
443
                public IGeometry getLastGeometry() {
444
                        return lastGeometry;
445
                }
446

    
447
                public int getIndexOfLast() {
448
                        return lastIndex;
449
                }
450
        }
451
}