Statistics
| Revision:

svn-gvsig-desktop / trunk / extensions / extGeoProcessing / src / com / iver / cit / gvsig / geoprocess / impl / spatialjoin / fmap / SpatialJoinGeoprocess.java @ 10626

History | View | Annotate | Download (15.1 KB)

1
/*
2
 * Created on 28-feb-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: SpatialJoinGeoprocess.java 10626 2007-03-06 16:55:54Z caballero $
47
 * $Log$
48
 * Revision 1.3  2007-03-06 16:47:58  caballero
49
 * Exceptions
50
 *
51
 * Revision 1.2  2006/06/29 07:33:57  fjp
52
 * Cambios ISchemaManager y IFieldManager por terminar
53
 *
54
 * Revision 1.1  2006/06/20 18:20:45  azabala
55
 * first version in cvs
56
 *
57
 * Revision 1.2  2006/06/02 18:21:28  azabala
58
 * *** empty log message ***
59
 *
60
 * Revision 1.1  2006/05/24 21:09:47  azabala
61
 * primera version en cvs despues de refactoring orientado a crear un framework extensible de geoprocessing
62
 *
63
 * Revision 1.10  2006/05/08 15:38:05  azabala
64
 * added nn spatial join with rtree
65
 *
66
 * Revision 1.9  2006/05/02 18:57:33  azabala
67
 * added a new implementation of nearest neighbour finder, based in RTree spatial index
68
 *
69
 * Revision 1.8  2006/05/01 19:09:23  azabala
70
 * Intento de optimizar el spatial join por vecino mas proximo (no funciona)
71
 *
72
 * Revision 1.7  2006/03/21 19:29:36  azabala
73
 * *** empty log message ***
74
 *
75
 * Revision 1.6  2006/03/17 19:53:43  azabala
76
 * *** empty log message ***
77
 *
78
 * Revision 1.5  2006/03/15 18:34:31  azabala
79
 * *** empty log message ***
80
 *
81
 * Revision 1.4  2006/03/14 18:32:46  fjp
82
 * Cambio con LayerDefinition para que sea compatible con la definici?n de tablas tambi?n.
83
 *
84
 * Revision 1.3  2006/03/07 21:01:33  azabala
85
 * *** empty log message ***
86
 *
87
 * Revision 1.2  2006/03/06 19:48:39  azabala
88
 * *** empty log message ***
89
 *
90
 * Revision 1.1  2006/03/05 19:59:32  azabala
91
 * *** empty log message ***
92
 *
93
 *
94
 */
95
package com.iver.cit.gvsig.geoprocess.impl.spatialjoin.fmap;
96

    
97
import java.util.Map;
98

    
99
import com.hardcode.gdbms.driver.exceptions.ReadDriverException;
100
import com.hardcode.gdbms.driver.exceptions.SchemaEditionException;
101
import com.iver.andami.PluginServices;
102
import com.iver.cit.gvsig.exceptions.expansionfile.ExpansionFileReadException;
103
import com.iver.cit.gvsig.exceptions.visitors.ProcessVisitorException;
104
import com.iver.cit.gvsig.exceptions.visitors.VisitorException;
105
import com.iver.cit.gvsig.fmap.core.IGeometry;
106
import com.iver.cit.gvsig.fmap.drivers.ILayerDefinition;
107
import com.iver.cit.gvsig.fmap.layers.FBitSet;
108
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
109
import com.iver.cit.gvsig.fmap.layers.ReadableVectorial;
110
import com.iver.cit.gvsig.fmap.operations.strategies.Strategy;
111
import com.iver.cit.gvsig.fmap.operations.strategies.StrategyManager;
112
import com.iver.cit.gvsig.fmap.spatialindex.INearestNeighbourFinder;
113
import com.iver.cit.gvsig.fmap.spatialindex.ISpatialIndex;
114
import com.iver.cit.gvsig.fmap.spatialindex.RTreeJsi;
115
import com.iver.cit.gvsig.geoprocess.core.fmap.AbstractGeoprocess;
116
import com.iver.cit.gvsig.geoprocess.core.fmap.FeaturePersisterProcessor2;
117
import com.iver.cit.gvsig.geoprocess.core.fmap.GeoprocessException;
118
import com.iver.cit.gvsig.geoprocess.core.fmap.ITwoLayersGeoprocess;
119
import com.iver.cit.gvsig.geoprocess.core.fmap.XTypes;
120
import com.iver.utiles.swing.threads.CancellableMonitorable;
121
import com.iver.utiles.swing.threads.DefaultCancellableMonitorable;
122
import com.iver.utiles.swing.threads.IMonitorableTask;
123
/**
124
 * This geoprocess implements Spatial Join operation.
125
 * A spatial join is a join where the criteria to link
126
 * a feature of layer A to one (or many) features of layer B
127
 * is a spatial critera.<br>
128
 * We can do two types of spatial join:
129
 * <ul>
130
 * <li><b>Intersect spatial join (1->N).</b> Given a feature, looks for
131
 * all intersecting features, and apply a sumarization function
132
 * to all of them. The result is a feature where all numeric features
133
 * of layer B have been grouped by one or many sumarization functions.
134
 * </li>
135
 * <li><b>Nearest spatial join (1->N)</b>Given a feature, looks
136
 * for the nearest feature of layer B, and tooks its fields.
137
 * </li>
138
 * </ul>
139
 * @author azabala
140
 *
141
 */
142
public class SpatialJoinGeoprocess extends AbstractGeoprocess
143
                                                                implements ITwoLayersGeoprocess {
144
        /**
145
         * overlay layer
146
         */
147
        private FLyrVect secondLayer;
148
        /**
149
         * Relates each numeric field of target layer with
150
         * many sumarization functions
151
         */
152
        private Map fields_sumFunctions;
153

    
154
        /**
155
         * flag to only clip selection of input layer
156
         */
157
        private boolean onlyFirstLayerSelection = false;
158

    
159
        /**
160
         * flag to only clip with selection of clipping layer
161
         */
162
        private boolean onlySecondLayerSelection = false;
163

    
164
        /**
165
         * flag to apply a nearest spatial join (1 to 1 join) or a intersect spatial
166
         * join (1 to m join)
167
         */
168
        private boolean nearestSpatialJoin = true;
169

    
170
        /**
171
         * Visitor that will do the process
172
         */
173
        private SpatialJoinVisitor visitor = null;
174
        /**
175
         * It will process results of joined features
176
         */
177
        private FeaturePersisterProcessor2 processor;
178

    
179

    
180
        public SpatialJoinGeoprocess(FLyrVect inputLayer) {
181
                setFirstOperand(inputLayer);
182
        }
183

    
184
        public void setSecondOperand(FLyrVect overlayLayer) {
185
                this.secondLayer = overlayLayer;
186

    
187
        }
188

    
189
        public void setFirstOperand(FLyrVect firstLayer) {
190
                this.firstLayer = firstLayer;
191

    
192
        }
193

    
194
        /**
195
         * PRECONDITION: We must setResultLayerProperties before
196
         * to call setParameters.
197
         * FIXME
198
         */
199
        public void setParameters(Map params) throws GeoprocessException {
200
                Boolean firstLayerSelection = (Boolean) params
201
                                .get("firstlayerselection");
202
                if (firstLayerSelection != null)
203
                        this.onlyFirstLayerSelection = firstLayerSelection.booleanValue();
204

    
205
                Boolean secondLayerSelection = (Boolean) params
206
                                .get("secondlayerselection");
207
                if (secondLayerSelection != null)
208
                        this.onlySecondLayerSelection = secondLayerSelection.booleanValue();
209

    
210
                if(writer == null)
211
                        throw new GeoprocessException("Hay que hacer setResultLayerProperties antes de hacer setParameters en el spatial join");
212
                processor =
213
                        new FeaturePersisterProcessor2(writer);
214

    
215
                processor = new FeaturePersisterProcessor2(writer);
216

    
217
                Boolean nearest = (Boolean) params
218
                                .get("nearest");
219
                if (nearest != null)
220
                        this.nearestSpatialJoin = nearest.booleanValue();
221
                if(nearestSpatialJoin){
222
                        try {
223
//                                ISpatialIndex spatialIndex = secondLayer.getISpatialIndex();
224
//                                if(spatialIndex != null &&
225
//                                                (spatialIndex instanceof INearestNeighbourFinder))
226
//                                {
227
                                        visitor = new SpatiallyIndexedSpatialJoinVisitor(this.firstLayer,
228
                                                        this.secondLayer,
229
                                                        processor);
230
//                                }else{
231
//
232
//                                        visitor = new NearestSpatialJoinVisitor(this.firstLayer,
233
//                                                        this.secondLayer,
234
//                                                        processor);
235
//                                }
236
                        } catch (ReadDriverException e) {
237
                                throw new GeoprocessException("Error preparando el procesado de las capas a enlazar");
238
                        }
239

    
240
                }else{
241
                        try {
242
                                visitor = new IntersectSpatialJoinVisitor(this.firstLayer,
243
                                                                                                this.secondLayer,
244
                                                                this.fields_sumFunctions,
245
                                                                processor);
246
                        } catch (ReadDriverException e) {
247
                                throw new GeoprocessException("Error preparando el procesado de las capas a enlazar");
248
                        }
249
                }
250
                visitor.setFeatureProcessor(processor);
251

    
252
        }
253

    
254
        public void checkPreconditions() throws GeoprocessException {
255
                if (firstLayer == null)
256
                        throw new GeoprocessException(
257
                                        "Spatial Join: capa de entrada a null");
258
                if (secondLayer == null)
259
                        throw new GeoprocessException("Spatial Join: 2? capa a null");
260
                if (this.writer == null || this.schemaManager == null) {
261
                        throw new GeoprocessException(
262
                                        "Operacion spatial join sin especificar capa de resultados");
263
                }
264
                try {
265
                        int firstLayerType = firstLayer.getShapeType();
266
                        int secondLayerType = secondLayer.getShapeType();
267
                        if(firstLayerType == XTypes.POINT
268
                                        && secondLayerType == XTypes.POINT
269
                                        && (!nearestSpatialJoin)){
270
                                throw new GeoprocessException(
271
                                "No est? permitido el spatial join M:N entre puntos");
272
                        }
273
                } catch (ReadDriverException e) {
274
                        throw new GeoprocessException(
275
                                        "Error al tratar de chequear la geometria de las capas a enlazar espacialmente");
276
                }
277
        }
278

    
279
        public void process() throws GeoprocessException {
280
                Strategy strategy =
281
                        StrategyManager.getStrategy(firstLayer);
282

    
283
                Strategy secondLyrStrategy =
284
                        StrategyManager.getStrategy(secondLayer);
285
                visitor.setCancelableStrategy(secondLyrStrategy);
286
                visitor.setOnlySecondLyrSelection(onlySecondLayerSelection);
287
                try {
288
                        if(this.onlyFirstLayerSelection){
289
                                strategy.process(visitor,
290
                                                firstLayer.getRecordset().
291
                                                getSelection());
292

    
293
                        }else{
294
                                strategy.process(visitor);
295
                        }
296

    
297
                } catch (ReadDriverException e) {
298
                        throw new GeoprocessException("Error al acceder a los datos durante un spatial join");
299
                } catch (ProcessVisitorException e) {
300
                        throw new GeoprocessException("Error al procesar los datos durante un spatial join");
301
                } catch (ExpansionFileReadException e) {
302
                        throw new GeoprocessException("Error al procesar los datos durante un spatial join");
303
                } catch (VisitorException e) {
304
                        throw new GeoprocessException("Error al procesar los datos durante un spatial join");
305
                }
306

    
307
        }
308

    
309
        //FIXME to throw an edition exception in
310
        //schema manager
311
        public void cancel() {
312
                try {
313
                        this.schemaManager.removeSchema("");
314
                } catch (SchemaEditionException e) {
315
                        // TODO Auto-generated catch block
316
                        e.printStackTrace();
317
                }
318
        }
319

    
320
        /**
321
         * FIXME Lanzar una excepcion si esto se llama antes
322
         * que el setParameters (esto me lo aseguro obligando a meter
323
         * los datos en el constructor)
324
         *
325
         * FIXME A?adir, en las relaciones 1-N, el n?mero de features
326
         * que participan en la relaci?n de la parte de N
327
         */
328
        public ILayerDefinition createLayerDefinition() {
329
                ILayerDefinition solution = null;
330
                try {
331
                        solution =  visitor.getResultLayerDefinition();
332
                } catch (GeoprocessException e) {
333
                        // TODO Auto-generated catch block
334
                        e.printStackTrace();
335
                }
336
                return solution;
337
        }
338

    
339
        public Map getFields_sumFunctions() {
340
                return fields_sumFunctions;
341
        }
342

    
343
        public void setFields_sumFunctions(Map fields_sumFunctions) {
344
                this.fields_sumFunctions = fields_sumFunctions;
345
        }
346

    
347
        public IMonitorableTask createTask() {
348
                try {
349
                        return new SpatialJoinMonitorableTask();
350
                } catch (Exception e) {
351
                        return null;
352
                }
353
        }
354

    
355
        class SpatialJoinMonitorableTask implements IMonitorableTask {
356
                private CancellableMonitorable cancelMonitor = null;
357
                String SPJOIN_MESSAGE = PluginServices.getText(this, "Mensaje_enlace_espacial");
358
                String SPJOIN_NOTE = PluginServices.getText(this, "Mensaje_procesando_enlace_espacial");
359
                String OF =  PluginServices.getText(this, "De");
360

    
361
                private boolean finished = false;
362

    
363
                SpatialJoinMonitorableTask() throws ReadDriverException  {
364
                        initialize();
365
                }
366
                void initialize() throws ReadDriverException  {
367
                        cancelMonitor = createCancelMonitor();
368
                }
369

    
370
                private CancellableMonitorable createCancelMonitor() throws ReadDriverException {
371
                        DefaultCancellableMonitorable monitor = new
372
                                                        DefaultCancellableMonitorable();
373
                        monitor.setInitialStep(0);
374
                        monitor.setDeterminatedProcess(true);
375
                        int numSteps = 0;
376
                        if (onlyFirstLayerSelection) {
377
                                FBitSet selection = firstLayer.getRecordset().getSelection();
378
                                numSteps += (2 * selection.cardinality());
379
                        } else {
380
                                numSteps += 2 * firstLayer.getSource().getShapeCount();
381
                        }
382
                        monitor.setFinalStep(numSteps);
383
                        return monitor;
384
                }
385

    
386
                public int getInitialStep() {
387
                        return cancelMonitor.getInitialStep();
388
                }
389

    
390
                public int getFinishStep() {
391
                        return cancelMonitor.getFinalStep();
392
                }
393

    
394
                public int getCurrentStep() {
395
                        return cancelMonitor.getCurrentStep();
396
                }
397

    
398
                public String getStatusMessage() {
399
                        return SPJOIN_MESSAGE;
400
                }
401

    
402
                public String getNote() {
403
                        return SPJOIN_NOTE + " " +
404
                        getCurrentStep() + " "+
405
                        OF + " " + getFinishStep();
406
                }
407

    
408
                public void cancel() {
409
                        ((DefaultCancellableMonitorable) cancelMonitor).setCanceled(true);
410
                        SpatialJoinGeoprocess.this.cancel();
411
                }
412

    
413
                public void run() throws GeoprocessException {
414
                        ISpatialIndex oldSptIdx = null;
415
                        if(nearestSpatialJoin){
416
                                //TODO Para spatial join m-n lo estoy haciendo
417
                                //en el GeoprocessController, mientras que para el 1-n
418
                                //aqu?: unificar criterios
419
                                oldSptIdx = secondLayer.getISpatialIndex();
420
                                if(oldSptIdx == null || ! (oldSptIdx instanceof INearestNeighbourFinder)){
421
                                        RTreeJsi newSptIdx = new RTreeJsi();
422
                                        newSptIdx.create();
423
                                        ReadableVectorial source = secondLayer.getSource();
424
                                        try {
425
                                                int numFeatures = source.getShapeCount();
426
                                                for(int i = 0; i < numFeatures; i++){
427
                                                        IGeometry geometry = source.getShape(i);
428
                                                        if(geometry != null)
429
                                                                newSptIdx.insert(geometry.getBounds2D(), i);
430
                                                }
431
                                        } catch (ReadDriverException e) {
432
                                                throw new GeoprocessException("Error intentando indexar para busqueda por mas proximo");
433
                                        } catch (ExpansionFileReadException e) {
434
                                                throw new GeoprocessException("Error intentando indexar para busqueda por mas proximo");
435
                                        }
436
                                        secondLayer.setISpatialIndex(newSptIdx);
437
                                }//if oldSptIdx
438
                        }//if nearest
439

    
440
                        if(visitor instanceof SpatiallyIndexedSpatialJoinVisitor)
441
                        {
442
                                //here checks for Nearest Neighbour capabilitie
443
                                ((SpatiallyIndexedSpatialJoinVisitor)visitor).initialize();
444
                        }
445

    
446
                        Strategy strategy =
447
                                StrategyManager.getStrategy(firstLayer);
448
                        Strategy secondLyrStrategy =
449
                                StrategyManager.getStrategy(secondLayer);
450
                        visitor.setCancelableStrategy(secondLyrStrategy);
451
                        visitor.setOnlySecondLyrSelection(onlySecondLayerSelection);
452
                        try {
453
                                if(onlyFirstLayerSelection){
454
                                        strategy.process(visitor,
455
                                                        firstLayer.getRecordset().
456
                                                        getSelection(),
457
                                                        cancelMonitor);
458

    
459
                                }else{
460
                                        strategy.process(visitor, cancelMonitor);
461
                                }
462

    
463
//                                If we changed spatial index to allow Nearest Neighbour queries,
464
                                //recover the old spatial index
465
                                if(oldSptIdx != null)
466
                                        secondLayer.setISpatialIndex(oldSptIdx);
467

    
468
                        } catch (ReadDriverException e) {
469
                                throw new GeoprocessException("Error al acceder a los datos durante un spatial join");
470
                        } catch (ProcessVisitorException e) {
471
                                throw new GeoprocessException("Error al procesar los datos durante un spatial join");
472
                        } catch (ExpansionFileReadException e) {
473
                                throw new GeoprocessException("Error al procesar los datos durante un spatial join");
474
                        } catch (VisitorException e) {
475
                                throw new GeoprocessException("Error al procesar los datos durante un spatial join");
476
                        }
477
                        finally{
478
                                finished = true;
479
                        }
480
                }
481

    
482
                public boolean isDefined() {
483
                        return cancelMonitor.isDeterminatedProcess();
484
                }
485

    
486
                public boolean isCanceled() {
487
                        return cancelMonitor.isCanceled();
488
                }
489

    
490
                public boolean isFinished() {
491
                        return finished;
492
                }
493
        }
494

    
495

    
496
}