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
/*
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 28367 2009-05-04 15:30:10Z vcaballero $
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
        private boolean isUsedNext=true;
100
        private boolean hasNext=false;
101

    
102
        /**
103
         * Proportion of query extent area and layer extent area
104
         * to use boundedshapes capability (reading bounds without
105
         * reading its geometry)
106
         *
107
         */
108
        public static final double BOUNDED_SHAPES_FACTOR = 4.0d;
109

    
110
        /**
111
         * Constructor.
112
         *
113
         * @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
                if(this.targetProjection != null &&
145
                   this.sourceProjection != null &&
146
                   this.targetProjection.getAbrev() != this.sourceProjection.getAbrev()){
147
                        ICoordTrans trans = targetProjection.getCT(sourceProjection);
148
                        try{
149
                                rect = trans.convert(rect);
150
                        }catch (NullPointerException e) {
151
                                // TODO: handle exception
152
                        }
153
                }
154
                this.rect = rect;
155
        }
156

    
157
        public boolean hasNext() throws ReadDriverException {
158
                if(!isUsedNext){
159
                        return hasNext;
160
                }
161
                try {
162
                        while(true){
163
                                if(currentFeature >= source.getShapeCount())
164
                                        return (hasNext=false);
165
                                if(spatialChecker.intersects(rect, currentFeature)){
166
                                        //we only update the counter if spatialChecker could read the geometry
167
                                        //if it is boundedshape it doesnt read the geometry, so we need to read
168
                                        //currentFeature again
169
//                                        if(spatialChecker.returnShapes())
170
//                                                currentFeature++;
171
                                        break;
172
                                }
173
                                else
174
                                        currentFeature++;
175
                        }//while
176

    
177

    
178
                        //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
//                                currentFeature++;
186
                                reprojectIfNecessary(geom);
187
                        }
188
                        Value[] regAtt = getValues(currentFeature);
189
                        feat = new DefaultFeature(geom, regAtt, currentFeature + "");
190
                        nextFeature = feat;
191
                        currentFeature++;
192
                        return (hasNext = true);
193
                } 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
                isUsedNext=true;
202
                return nextFeature;
203
        }
204

    
205
        /**
206
         * Classes that chekcs if a specified feature intersects with a given Rectangle2D must
207
         * implement this interface.
208
         *
209
         * This interface is necessary because there are many approach to do that
210
         * (an exact intersection, an intersection based in bounds2d, etc)
211
         *
212
         *
213
         * @author azabala
214
         *
215
         */
216
        interface ISpatialCheck {
217
                public boolean intersects(Rectangle2D extent, int featureIndex)
218
                                throws ExpansionFileReadException, ReadDriverException;
219

    
220
                /**
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

    
232
                /**
233
                 * Return the index of the last readed geometry
234
                 * @return
235
                 */
236
                public int getIndexOfLast();
237

    
238

    
239
        }
240

    
241

    
242

    
243

    
244
        /**
245
         * All classes that return the bounds Rectangle2D of a feature must
246
         * implement this interface.
247
         *
248
         * @author azabala
249
         *
250
         */
251
        interface BoundsProvider {
252
                /**
253
                 * Returns the bound of the specified feature index
254
                 *
255
                 * @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
                 *
266
                 * @return
267
                 */
268
                public boolean returnShapes();
269

    
270
                /**
271
                 * Returns the last geometry readed, if the boundsProvider could do that
272
                 *
273
                 * @return
274
                 */
275
                public IGeometry getLastGeometry();
276
        }
277

    
278

    
279

    
280

    
281
        /**
282
         * BoundsProvider that uses a BoundedShapes (faster than others)
283
         *
284
         * @author azabala
285
         *
286
         */
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

    
310

    
311

    
312
        /**
313
         * BoundsProvider that returns feature bounds from the feature geometry
314
         *
315
         * @author azabala
316
         *
317
         */
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
                        if (lastGeometry ==null)
334
                                return new Rectangle2D.Double(0,0,0,0);
335
//                        reprojectIfNecessary(this.lastGeometry);
336
                        //bounds2D is in the original projection
337
                        Rectangle2D solution = lastGeometry.getBounds2D();
338
                        //the readed geometry in the specified projection
339
//                        reprojectIfNecessary(this.lastGeometry);
340
                        return solution;
341
                }
342

    
343
                public IGeometry getLastGeometry() {
344
                        reprojectIfNecessary(this.lastGeometry);
345
                        return lastGeometry;
346
                }
347

    
348
                public boolean returnShapes() {
349
                        return true;
350
                }
351

    
352
        }
353

    
354

    
355

    
356

    
357
        /**
358
         * Checks if the specified features intersects with rectangle2D instances in
359
         * a rough but fast manner.
360
         *
361
         */
362
        class FastSpatialCheck implements ISpatialCheck {
363
                BoundsProvider boundProvider;
364
                int lastIndex;
365

    
366

    
367
                public FastSpatialCheck() {
368
                        try {
369
                                if(isBoundedShapesNecessary()){
370
                                        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
                                    }else{
377
                                            boundProvider = new IGeometryBoundProvider(source);
378
                                    }
379
                                }else{
380
                                                boundProvider = new IGeometryBoundProvider(source);
381
                                }
382
                        } catch (ExpansionFileReadException e) {
383
                                // TODO Auto-generated catch block
384
                                e.printStackTrace();
385
                                boundProvider = new IGeometryBoundProvider(source);
386
                        } catch (ReadDriverException e) {
387
                                // TODO Auto-generated catch block
388
                                e.printStackTrace();
389
                                boundProvider = new IGeometryBoundProvider(source);
390
                        }
391
                }
392

    
393

    
394
                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

    
401
                }
402

    
403
                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

    
429
        /**
430
         * Checks if the specified features intersect with rectangle2D instances in
431
         * a precisse manner
432
         *
433
         * @author azabala
434
         *
435
         */
436

    
437
        class PrecisseSpatialCheck implements ISpatialCheck {
438
                IGeometry lastGeometry;
439
                int lastIndex;
440

    
441
                public PrecisseSpatialCheck() {
442
                }
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
}