Statistics
| Revision:

root / trunk / extensions / extGeoProcessing / src / com / iver / cit / gvsig / geoprocess / spatialjoin / fmap / SpatialJoinGeoprocess.java @ 5412

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

    
85
import java.util.Map;
86

    
87
import com.iver.andami.PluginServices;
88
import com.iver.cit.gvsig.fmap.DriverException;
89
import com.iver.cit.gvsig.fmap.drivers.DriverIOException;
90
import com.iver.cit.gvsig.fmap.drivers.ILayerDefinition;
91
import com.iver.cit.gvsig.fmap.edition.EditionException;
92
import com.iver.cit.gvsig.fmap.layers.FBitSet;
93
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
94
import com.iver.cit.gvsig.fmap.operations.strategies.Strategy;
95
import com.iver.cit.gvsig.fmap.operations.strategies.StrategyManager;
96
import com.iver.cit.gvsig.fmap.operations.strategies.VisitException;
97
import com.iver.cit.gvsig.fmap.spatialindex.INearestNeighbourFinder;
98
import com.iver.cit.gvsig.fmap.spatialindex.ISpatialIndex;
99
import com.iver.cit.gvsig.geoprocess.core.fmap.AbstractGeoprocess;
100
import com.iver.cit.gvsig.geoprocess.core.fmap.FeaturePersisterProcessor2;
101
import com.iver.cit.gvsig.geoprocess.core.fmap.GeoprocessException;
102
import com.iver.cit.gvsig.geoprocess.core.fmap.ITwoLayersGeoprocess;
103
import com.iver.cit.gvsig.geoprocess.core.fmap.XTypes;
104
import com.iver.utiles.swing.threads.CancellableMonitorable;
105
import com.iver.utiles.swing.threads.DefaultCancellableMonitorable;
106
import com.iver.utiles.swing.threads.IMonitorableTask;
107
/**
108
 * This geoprocess implements Spatial Join operation.
109
 * A spatial join is a join where the criteria to link
110
 * a feature of layer A to one (or many) features of layer B
111
 * is a spatial critera.<br>
112
 * We can do two types of spatial join:
113
 * <ul>
114
 * <li><b>Intersect spatial join (1->N).</b> Given a feature, looks for
115
 * all intersecting features, and apply a sumarization function
116
 * to all of them. The result is a feature where all numeric features
117
 * of layer B have been grouped by one or many sumarization functions.
118
 * </li>
119
 * <li><b>Nearest spatial join (1->N)</b>Given a feature, looks
120
 * for the nearest feature of layer B, and tooks its fields.
121
 * </li>
122
 * </ul>
123
 * @author azabala
124
 *
125
 */
126
public class SpatialJoinGeoprocess extends AbstractGeoprocess
127
                                                                implements ITwoLayersGeoprocess {
128
        /**
129
         * overlay layer
130
         */
131
        private FLyrVect secondLayer;
132
        /**
133
         * Relates each numeric field of target layer with
134
         * many sumarization functions
135
         */
136
        private Map fields_sumFunctions;
137

    
138
        /**
139
         * flag to only clip selection of input layer
140
         */
141
        private boolean onlyFirstLayerSelection = false;
142

    
143
        /**
144
         * flag to only clip with selection of clipping layer
145
         */
146
        private boolean onlySecondLayerSelection = false;
147

    
148
        /**
149
         * flag to apply a nearest spatial join (1 to 1 join) or a intersect spatial
150
         * join (1 to m join)
151
         */
152
        private boolean nearestSpatialJoin = true;
153
        
154
        /**
155
         * Visitor that will do the process
156
         */
157
        private SpatialJoinVisitor visitor = null;
158
        /**
159
         * It will process results of joined features
160
         */
161
        private FeaturePersisterProcessor2 processor;
162
        
163

    
164
        public SpatialJoinGeoprocess(FLyrVect inputLayer) {
165
                setFirstOperand(inputLayer);
166
        }
167

    
168
        public void setSecondOperand(FLyrVect overlayLayer) {
169
                this.secondLayer = overlayLayer;
170

    
171
        }
172

    
173
        public void setFirstOperand(FLyrVect firstLayer) {
174
                this.firstLayer = firstLayer;
175
                
176
        }
177

    
178
        /**
179
         * PRECONDITION: We must setResultLayerProperties before
180
         * to call setParameters.
181
         * FIXME
182
         */
183
        public void setParameters(Map params) throws GeoprocessException {
184
                Boolean firstLayerSelection = (Boolean) params
185
                                .get("firstlayerselection");
186
                if (firstLayerSelection != null)
187
                        this.onlyFirstLayerSelection = firstLayerSelection.booleanValue();
188

    
189
                Boolean secondLayerSelection = (Boolean) params
190
                                .get("secondlayerselection");
191
                if (secondLayerSelection != null)
192
                        this.onlySecondLayerSelection = secondLayerSelection.booleanValue();
193

    
194
                if(writer == null)
195
                        throw new GeoprocessException("Hay que hacer setResultLayerProperties antes de hacer setParameters en el spatial join");
196
                processor =
197
                        new FeaturePersisterProcessor2(writer);
198
                
199
                processor = new FeaturePersisterProcessor2(writer);
200
                
201
                Boolean nearest = (Boolean) params
202
                                .get("nearest");
203
                if (nearest != null)
204
                        this.nearestSpatialJoin = nearest.booleanValue();
205
                if(nearestSpatialJoin){
206
                        try {
207
                                ISpatialIndex spatialIndex = secondLayer.getISpatialIndex();
208
                                if(spatialIndex != null && 
209
                                                (spatialIndex instanceof INearestNeighbourFinder))
210
                                {
211
                                        visitor = new SpatiallyIndexedSpatialJoinVisitor(this.firstLayer, 
212
                                                        this.secondLayer,
213
                                                        processor);
214
                                }else{
215
                                        
216
                                        visitor = new NearestSpatialJoinVisitor(this.firstLayer, 
217
                                                        this.secondLayer,
218
                                                        processor);
219
                                }
220
                        } catch (DriverException e) {
221
                                throw new GeoprocessException("Error preparando el procesado de las capas a enlazar");
222
                        }
223
                        
224
                }else{
225
                        try {
226
                                visitor = new IntersectSpatialJoinVisitor(this.firstLayer,
227
                                                                                                this.secondLayer,
228
                                                                this.fields_sumFunctions, 
229
                                                                processor);
230
                        } catch (DriverException e) {
231
                                throw new GeoprocessException("Error preparando el procesado de las capas a enlazar");
232
                        }
233
                }
234
                visitor.setFeatureProcessor(processor);
235

    
236
        }
237

    
238
        public void checkPreconditions() throws GeoprocessException {
239
                if (firstLayer == null)
240
                        throw new GeoprocessException(
241
                                        "Spatial Join: capa de entrada a null");
242
                if (secondLayer == null)
243
                        throw new GeoprocessException("Spatial Join: 2? capa a null");
244
                if (this.writer == null || this.schemaManager == null) {
245
                        throw new GeoprocessException(
246
                                        "Operacion spatial join sin especificar capa de resultados");
247
                }
248
                try {
249
                        int firstLayerType = firstLayer.getShapeType();
250
                        int secondLayerType = secondLayer.getShapeType();
251
                        if(firstLayerType == XTypes.POINT 
252
                                        && secondLayerType == XTypes.POINT 
253
                                        && (!nearestSpatialJoin)){
254
                                throw new GeoprocessException(
255
                                "No est? permitido el spatial join M:N entre puntos");
256
                        }
257
                } catch (com.iver.cit.gvsig.fmap.DriverException e) {
258
                        throw new GeoprocessException(
259
                                        "Error al tratar de chequear la geometria de las capas a enlazar espacialmente");
260
                }
261
        }
262

    
263
        public void process() throws GeoprocessException {
264
                //Comentado: esto se le debe preguntar al usuario
265
//                if(!secondLayer.isSpatiallyIndexed()){
266
//                        //Revisar. Si el driver es ISpatialDB no es 
267
//                        //necesario construir indice
268
//                        secondLayer.createSpatialIndex();
269
//                }
270
                Strategy strategy =
271
                        StrategyManager.getStrategy(firstLayer);
272
                
273
                Strategy secondLyrStrategy =
274
                        StrategyManager.getStrategy(secondLayer);
275
                visitor.setCancelableStrategy(secondLyrStrategy);
276
                visitor.setOnlySecondLyrSelection(onlySecondLayerSelection);
277
                try {
278
                        if(this.onlyFirstLayerSelection){
279
                                strategy.process(visitor, 
280
                                                firstLayer.getRecordset().
281
                                                getSelection());
282
                                
283
                        }else{
284
                                strategy.process(visitor);
285
                        }
286
                        
287
                } catch (DriverException e) {
288
                        throw new GeoprocessException("Error al acceder a los datos durante un spatial join");
289
                } catch (VisitException e) {
290
                        throw new GeoprocessException("Error al procesar los datos durante un spatial join");
291
                }
292

    
293
        }
294

    
295
        //FIXME to throw an edition exception in 
296
        //schema manager
297
        public void cancel() {
298
                try {
299
                        this.schemaManager.drop();
300
                } catch (EditionException e) {
301
                        e.printStackTrace();
302
                }
303
        }
304

    
305
        /**
306
         * FIXME Lanzar una excepcion si esto se llama antes
307
         * que el setParameters (esto me lo aseguro obligando a meter
308
         * los datos en el constructor)
309
         * 
310
         * FIXME A?adir, en las relaciones 1-N, el n?mero de features
311
         * que participan en la relaci?n de la parte de N
312
         */
313
        public ILayerDefinition createLayerDefinition() {
314
                ILayerDefinition solution = null;
315
                try {
316
                        solution =  visitor.getResultLayerDefinition();
317
                } catch (GeoprocessException e) {
318
                        // TODO Auto-generated catch block
319
                        e.printStackTrace();
320
                }
321
                return solution;
322
        }
323

    
324
        public Map getFields_sumFunctions() {
325
                return fields_sumFunctions;
326
        }
327

    
328
        public void setFields_sumFunctions(Map fields_sumFunctions) {
329
                this.fields_sumFunctions = fields_sumFunctions;
330
        }
331

    
332
        public IMonitorableTask createTask() {
333
                try {
334
                        return new SpatialJoinMonitorableTask();
335
                } catch (Exception e) {
336
                        return null;
337
                }
338
        }
339
        
340
        class SpatialJoinMonitorableTask implements IMonitorableTask {
341
                private CancellableMonitorable cancelMonitor = null;
342
                String SPJOIN_MESSAGE = PluginServices.getText(this, "Mensaje_enlace_espacial");
343
                String SPJOIN_NOTE = PluginServices.getText(this, "Mensaje_procesando_enlace_espacial");
344
                String OF =  PluginServices.getText(this, "De");
345
                
346
                private boolean finished = false;
347

    
348
                SpatialJoinMonitorableTask() throws DriverIOException, DriverException {
349
                        initialize();
350
                }
351
                void initialize() throws DriverIOException, DriverException {
352
                        cancelMonitor = createCancelMonitor();
353
                }
354

    
355
                private CancellableMonitorable createCancelMonitor()
356
                                throws DriverIOException, DriverException {
357
                        DefaultCancellableMonitorable monitor = new 
358
                                                        DefaultCancellableMonitorable();
359
                        monitor.setInitialStep(0);
360
                        monitor.setDeterminatedProcess(true);
361
                        int numSteps = 0;
362
                        if (onlyFirstLayerSelection) {
363
                                FBitSet selection = firstLayer.getRecordset().getSelection();
364
                                numSteps += (2 * selection.cardinality());
365
                        } else {
366
                                numSteps += 2 * firstLayer.getSource().getShapeCount();
367
                        }
368
                        monitor.setFinalStep(numSteps);
369
                        return monitor;
370
                }
371

    
372
                public int getInitialStep() {
373
                        return cancelMonitor.getInitialStep();
374
                }
375

    
376
                public int getFinishStep() {
377
                        return cancelMonitor.getFinalStep();
378
                }
379

    
380
                public int getCurrentStep() {
381
                        return cancelMonitor.getCurrentStep();
382
                }
383

    
384
                public String getStatusMessage() {
385
                        return SPJOIN_MESSAGE;
386
                }
387

    
388
                public String getNote() {
389
                        return SPJOIN_NOTE + " " +
390
                        getCurrentStep() + " "+
391
                        OF + " " + getFinishStep();
392
                }
393

    
394
                public void cancel() {
395
                        ((DefaultCancellableMonitorable) cancelMonitor).setCanceled(true);
396
                        SpatialJoinGeoprocess.this.cancel();
397
                }
398

    
399
                public void run() throws GeoprocessException {
400
                        if(!secondLayer.isSpatiallyIndexed()){
401
                                //Revisar. Si el driver es ISpatialDB no es 
402
                                //necesario construir indice
403
                                secondLayer.createSpatialIndex();
404
                        }
405
                        Strategy strategy =
406
                                StrategyManager.getStrategy(firstLayer);
407
                        Strategy secondLyrStrategy =
408
                                StrategyManager.getStrategy(secondLayer);
409
                        visitor.setCancelableStrategy(secondLyrStrategy);
410
                        visitor.setOnlySecondLyrSelection(onlySecondLayerSelection);
411
                        try {
412
                                if(onlyFirstLayerSelection){
413
                                        strategy.process(visitor, 
414
                                                        firstLayer.getRecordset().
415
                                                        getSelection(),
416
                                                        cancelMonitor);
417
                                        
418
                                }else{
419
                                        strategy.process(visitor, cancelMonitor);
420
                                }
421
                                
422
                        } catch (DriverException e) {
423
                                throw new GeoprocessException("Error al acceder a los datos durante un spatial join");
424
                        } catch (VisitException e) {
425
                                throw new GeoprocessException("Error al procesar los datos durante un spatial join");
426
                        }
427
                        finally{
428
                                finished = true;
429
                        }
430
                }
431

    
432
                public boolean isDefined() {
433
                        return cancelMonitor.isDeterminatedProcess();
434
                }
435

    
436
                public boolean isCanceled() {
437
                        return cancelMonitor.isCanceled();
438
                }
439

    
440
                public boolean isFinished() {
441
                        return finished;
442
                }
443
        }
444
        
445

    
446
}