Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / drivers / featureiterators / SpatialQueryFeatureIterator.java @ 28367

History | View | Annotate | Download (12 KB)

1 11879 azabala
/*
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$
47
 * $Log$
48 13873 azabala
 * 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 12048 azabala
 * refactor of BOUND FACTOR
53
 *
54
 * Revision 1.2  2007/06/06 18:03:03  azabala
55 12037 azabala
 * bug fixed
56
 *
57
 * Revision 1.1  2007/05/29 19:08:11  azabala
58 11879 azabala
 * 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 16395 vcaballero
89 11879 azabala
        /**
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 16395 vcaballero
99 26361 vcaballero
        private boolean isUsedNext=true;
100
        private boolean hasNext=false;
101
102 12048 azabala
        /**
103
         * Proportion of query extent area and layer extent area
104
         * to use boundedshapes capability (reading bounds without
105 16395 vcaballero
         * reading its geometry)
106
         *
107 12048 azabala
         */
108
        public static final double BOUNDED_SHAPES_FACTOR = 4.0d;
109 11879 azabala
110
        /**
111
         * Constructor.
112 16395 vcaballero
         *
113 11879 azabala
         * @param source
114
         *            vectorial data source
115
         * @param sourceProj
116
         *            original projection of the data (it could be null)
117
         * @param targetProj
118
         *            projection of the returned features
119
         * @param fieldNames
120
         * @param spatialQuery
121
         * @throws ReadDriverException
122
         */
123
        public SpatialQueryFeatureIterator(ReadableVectorial source,
124
                        IProjection sourceProj, IProjection targetProj,
125
                        String[] fieldNames, Rectangle2D spatialQuery, boolean fastIteration)
126
                        throws ReadDriverException {
127
                super(source, sourceProj, targetProj, fieldNames);
128
                setRect(spatialQuery);
129
                if(fastIteration)
130
                        spatialChecker = new FastSpatialCheck();
131
                else
132
                        spatialChecker = new PrecisseSpatialCheck();
133
        }
134
135
        public Rectangle2D getRect() {
136
                return rect;
137
        }
138
139
        public void setRect(Rectangle2D rect) {
140
                //by design, rect Rectangle2D must be in the target reprojection
141
                //if targetReprojection != sourceReprojection, we are going to reproject
142
                //rect to the source reprojection (is faster).
143
                //once spatial check is made, result features will be reprojected in the inverse direction
144 16395 vcaballero
                if(this.targetProjection != null &&
145 11879 azabala
                   this.sourceProjection != null &&
146
                   this.targetProjection.getAbrev() != this.sourceProjection.getAbrev()){
147
                        ICoordTrans trans = targetProjection.getCT(sourceProjection);
148 28367 vcaballero
                        try{
149
                                rect = trans.convert(rect);
150
                        }catch (NullPointerException e) {
151
                                // TODO: handle exception
152
                        }
153 11879 azabala
                }
154
                this.rect = rect;
155
        }
156
157
        public boolean hasNext() throws ReadDriverException {
158 26361 vcaballero
                if(!isUsedNext){
159
                        return hasNext;
160
                }
161 11879 azabala
                try {
162
                        while(true){
163
                                if(currentFeature >= source.getShapeCount())
164 26361 vcaballero
                                        return (hasNext=false);
165 11879 azabala
                                if(spatialChecker.intersects(rect, currentFeature)){
166 12037 azabala
                                        //we only update the counter if spatialChecker could read the geometry
167 16395 vcaballero
                                        //if it is boundedshape it doesnt read the geometry, so we need to read
168
                                        //currentFeature again
169 13873 azabala
//                                        if(spatialChecker.returnShapes())
170
//                                                currentFeature++;
171 11879 azabala
                                        break;
172 13873 azabala
                                }
173
                                else
174 11879 azabala
                                        currentFeature++;
175 13873 azabala
                        }//while
176 16395 vcaballero
177
178 11879 azabala
                        //here, currentFeature intersects with the rectangle2d filter
179
                        IGeometry geom = null;
180
                        IFeature feat = null;
181
                        if(spatialChecker.returnShapes()){
182
                                geom = spatialChecker.getLastGeometry();
183
                        }else{
184
                                geom = source.getShape(currentFeature);
185 13873 azabala
//                                currentFeature++;
186 11879 azabala
                                reprojectIfNecessary(geom);
187
                        }
188
                        Value[] regAtt = getValues(currentFeature);
189
                        feat = new DefaultFeature(geom, regAtt, currentFeature + "");
190
                        nextFeature = feat;
191 13873 azabala
                        currentFeature++;
192 26361 vcaballero
                        return (hasNext = true);
193 11879 azabala
                } catch (ExpansionFileReadException e) {
194
                        throw new ReadDriverException(
195
                                        "Error accediendo a datos del driver durante la iteracion",
196
                                        e);
197
                }
198
        }
199
200
        public IFeature next() throws ReadDriverException {
201 26361 vcaballero
                isUsedNext=true;
202 11879 azabala
                return nextFeature;
203
        }
204
205
        /**
206
         * Classes that chekcs if a specified feature intersects with a given Rectangle2D must
207
         * implement this interface.
208 16395 vcaballero
         *
209 11879 azabala
         * This interface is necessary because there are many approach to do that
210
         * (an exact intersection, an intersection based in bounds2d, etc)
211 16395 vcaballero
         *
212
         *
213 11879 azabala
         * @author azabala
214
         *
215
         */
216
        interface ISpatialCheck {
217
                public boolean intersects(Rectangle2D extent, int featureIndex)
218
                                throws ExpansionFileReadException, ReadDriverException;
219 16395 vcaballero
220 11879 azabala
                /**
221
                 * Tells if this spatialcheck could return the geometry of the features
222
                 * (or if it is boundedshapes based, needs another driver access operation)
223
                 * @return
224
                 */
225
                public boolean returnShapes();
226
                /**
227
                 * Returns the last readed geometry (if the spatialcheck do that)
228
                 * @return
229
                 */
230
                public IGeometry getLastGeometry();
231 16395 vcaballero
232 11879 azabala
                /**
233
                 * Return the index of the last readed geometry
234
                 * @return
235
                 */
236
                public int getIndexOfLast();
237
238 16395 vcaballero
239 11879 azabala
        }
240
241 16395 vcaballero
242
243
244 11879 azabala
        /**
245
         * All classes that return the bounds Rectangle2D of a feature must
246
         * implement this interface.
247 16395 vcaballero
         *
248 11879 azabala
         * @author azabala
249 16395 vcaballero
         *
250 11879 azabala
         */
251
        interface BoundsProvider {
252
                /**
253
                 * Returns the bound of the specified feature index
254 16395 vcaballero
                 *
255 11879 azabala
                 * @param featureIndex
256
                 * @return
257
                 * @throws ExpansionFileReadException
258
                 * @throws ReadDriverException
259
                 */
260
                public Rectangle2D getBounds(int featureIndex)
261
                                throws ExpansionFileReadException, ReadDriverException;
262
263
                /**
264
                 * Tells if this boundsProvider could returns shapes
265 16395 vcaballero
                 *
266 11879 azabala
                 * @return
267
                 */
268
                public boolean returnShapes();
269
270
                /**
271
                 * Returns the last geometry readed, if the boundsProvider could do that
272 16395 vcaballero
                 *
273 11879 azabala
                 * @return
274
                 */
275
                public IGeometry getLastGeometry();
276
        }
277
278 16395 vcaballero
279
280
281 11879 azabala
        /**
282
         * BoundsProvider that uses a BoundedShapes (faster than others)
283 16395 vcaballero
         *
284 11879 azabala
         * @author azabala
285 16395 vcaballero
         *
286 11879 azabala
         */
287
        class BoundedShapesProvider implements BoundsProvider {
288
                BoundedShapes boundedShapes;
289
290
                BoundedShapesProvider(BoundedShapes boundedShapes) {
291
                        this.boundedShapes = boundedShapes;
292
                }
293
294
                public Rectangle2D getBounds(int featureIndex)
295
                                throws ExpansionFileReadException, ReadDriverException {
296
                        return boundedShapes.getShapeBounds(featureIndex);
297
                }
298
299
                public boolean returnShapes() {
300
                        return false;
301
                }
302
303
                public IGeometry getLastGeometry() {
304
                        return null;
305
                }
306
307
        }
308
309 16395 vcaballero
310
311
312 11879 azabala
        /**
313
         * BoundsProvider that returns feature bounds from the feature geometry
314 16395 vcaballero
         *
315 11879 azabala
         * @author azabala
316 16395 vcaballero
         *
317 11879 azabala
         */
318
        class IGeometryBoundProvider implements BoundsProvider {
319
                /**
320
                 * Adapter of a given driver from which we read the features bounds.
321
                 */
322
                ReadableVectorial source;
323
324
                IGeometry lastGeometry;
325
326
                IGeometryBoundProvider(ReadableVectorial sourceOfFeatures) {
327
                        this.source = sourceOfFeatures;
328
                }
329
330
                public Rectangle2D getBounds(int featureIndex)
331
                                throws ExpansionFileReadException, ReadDriverException {
332
                        lastGeometry = source.getShape(featureIndex);
333 16395 vcaballero
                        if (lastGeometry ==null)
334
                                return new Rectangle2D.Double(0,0,0,0);
335 18424 vcaballero
//                        reprojectIfNecessary(this.lastGeometry);
336 11879 azabala
                        //bounds2D is in the original projection
337
                        Rectangle2D solution = lastGeometry.getBounds2D();
338
                        //the readed geometry in the specified projection
339 17204 vcaballero
//                        reprojectIfNecessary(this.lastGeometry);
340 11879 azabala
                        return solution;
341
                }
342
343
                public IGeometry getLastGeometry() {
344 18424 vcaballero
                        reprojectIfNecessary(this.lastGeometry);
345 11879 azabala
                        return lastGeometry;
346
                }
347
348
                public boolean returnShapes() {
349
                        return true;
350
                }
351
352
        }
353
354 16395 vcaballero
355
356
357 11879 azabala
        /**
358
         * Checks if the specified features intersects with rectangle2D instances in
359
         * a rough but fast manner.
360 16395 vcaballero
         *
361 11879 azabala
         */
362
        class FastSpatialCheck implements ISpatialCheck {
363
                BoundsProvider boundProvider;
364
                int lastIndex;
365 16395 vcaballero
366
367 26361 vcaballero
                public FastSpatialCheck() {
368 12037 azabala
                        try {
369 16395 vcaballero
                                if(isBoundedShapesNecessary()){
370 12037 azabala
                                        if (source instanceof BoundedShapes){
371
                                                boundProvider = new BoundedShapesProvider(
372
                                                                (BoundedShapes) source);
373
                                        }else if (source.getDriver() instanceof BoundedShapes){
374
                                                boundProvider = new BoundedShapesProvider(
375
                                                                (BoundedShapes) source.getDriver());
376 16792 vcaballero
                                    }else{
377
                                            boundProvider = new IGeometryBoundProvider(source);
378 12037 azabala
                                    }
379
                                }else{
380
                                                boundProvider = new IGeometryBoundProvider(source);
381
                                }
382
                        } catch (ExpansionFileReadException e) {
383
                                // TODO Auto-generated catch block
384
                                e.printStackTrace();
385 11879 azabala
                                boundProvider = new IGeometryBoundProvider(source);
386 12037 azabala
                        } catch (ReadDriverException e) {
387
                                // TODO Auto-generated catch block
388
                                e.printStackTrace();
389
                                boundProvider = new IGeometryBoundProvider(source);
390
                        }
391 11879 azabala
                }
392 16395 vcaballero
393
394 12037 azabala
                protected boolean isBoundedShapesNecessary() throws ReadDriverException, ExpansionFileReadException {
395
                        Rectangle2D driverExtent = source.getFullExtent();
396
                        double areaExtent = rect.getWidth() * rect.getHeight();
397
                        double areaFullExtent = driverExtent.getWidth() *
398
                                                         driverExtent.getHeight();
399
                        return areaExtent < (areaFullExtent / BOUNDED_SHAPES_FACTOR);
400 11879 azabala
401 12037 azabala
                }
402
403 11879 azabala
                public boolean intersects(Rectangle2D extent, int featureIndex)
404
                                throws ExpansionFileReadException, ReadDriverException {
405
                        this.lastIndex = featureIndex;
406
                        Rectangle2D featureBounds = boundProvider.getBounds(featureIndex);
407
                        return XRectangle2D.intersectInclusive(extent, featureBounds);
408
                }
409
410
                public BoundsProvider getBoundsProvider() {
411
                        return boundProvider;
412
                }
413
414
                public boolean returnShapes() {
415
                        return boundProvider.returnShapes();
416
                }
417
418
                public IGeometry getLastGeometry() {
419
                        return boundProvider.getLastGeometry();
420
                }
421
422
                public int getIndexOfLast() {
423
                        return lastIndex;
424
                }
425
426
        }// FastSpatialCheck
427
428 16395 vcaballero
429 11879 azabala
        /**
430
         * Checks if the specified features intersect with rectangle2D instances in
431
         * a precisse manner
432 16395 vcaballero
         *
433 11879 azabala
         * @author azabala
434 16395 vcaballero
         *
435 11879 azabala
         */
436
437
        class PrecisseSpatialCheck implements ISpatialCheck {
438
                IGeometry lastGeometry;
439
                int lastIndex;
440
441 26361 vcaballero
                public PrecisseSpatialCheck() {
442 11879 azabala
                }
443
444
                public boolean intersects(Rectangle2D extent, int featureIndex)
445
                                throws ExpansionFileReadException, ReadDriverException {
446
                        this.lastIndex = featureIndex;
447
                        this.lastGeometry = source.getShape(lastIndex);
448
                        //the spatial check is made in the original projection
449
                        boolean solution = lastGeometry.fastIntersects(rect.getMinX(),
450
                                        rect.getMinY(), rect.getWidth(), rect.getHeight());
451
                        //but the solution is returned in the new projection (if applies)
452
                        reprojectIfNecessary(lastGeometry);
453
                        return solution;
454
                }
455
456
                public boolean returnShapes() {
457
                        return true;
458
                }
459
460
                public IGeometry getLastGeometry() {
461
                        return lastGeometry;
462
                }
463
464
                public int getIndexOfLast() {
465
                        return lastIndex;
466
                }
467
        }
468
}