Statistics
| Revision:

svn-gvsig-desktop / tags / v1_1_Build_1010 / extensions / extGeoProcessing / src / com / iver / cit / gvsig / geoprocess / impl / dissolve / fmap / DissolveVisitor.java @ 12804

History | View | Annotate | Download (21.2 KB)

1
/*
2
 * Created on 24-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: DissolveVisitor.java 12804 2007-07-26 12:18:11Z  $
47
 * $Log$
48
 * Revision 1.2.2.1  2007-07-12 09:28:45  azabala
49
 * optimizations in dissolution of buffered features (we dont use strategies to avoid reading of geometries already processed)
50
 *
51
 * Revision 1.2  2006/07/27 17:21:06  azabala
52
 * *** empty log message ***
53
 *
54
 * Revision 1.1  2006/06/20 18:20:45  azabala
55
 * first version in cvs
56
 *
57
 * Revision 1.3  2006/06/08 18:24:43  azabala
58
 * modificaciones para admitir capas de shapeType MULTI
59
 *
60
 * Revision 1.2  2006/06/02 18:21:28  azabala
61
 * *** empty log message ***
62
 *
63
 * Revision 1.1  2006/05/24 21:11:14  azabala
64
 * primera version en cvs despues de refactoring orientado a crear un framework extensible de geoprocessing
65
 *
66
 * Revision 1.5  2006/05/08 15:37:26  azabala
67
 * added alphanumeric dissolve
68
 *
69
 * Revision 1.4  2006/05/01 19:14:30  azabala
70
 * comentario
71
 *
72
 * Revision 1.3  2006/03/15 18:33:24  azabala
73
 * *** empty log message ***
74
 *
75
 * Revision 1.2  2006/03/07 21:01:33  azabala
76
 * *** empty log message ***
77
 *
78
 * Revision 1.1  2006/03/06 19:48:39  azabala
79
 * *** empty log message ***
80
 *
81
 * Revision 1.2  2006/03/05 19:58:30  azabala
82
 * *** empty log message ***
83
 *
84
 * Revision 1.1  2006/02/26 20:54:04  azabala
85
 * *** empty log message ***
86
 *
87
 *
88
 */
89
package com.iver.cit.gvsig.geoprocess.impl.dissolve.fmap;
90

    
91
import java.awt.geom.Rectangle2D;
92
import java.util.ArrayList;
93
import java.util.Iterator;
94
import java.util.List;
95
import java.util.Map;
96
import java.util.Stack;
97

    
98
import com.hardcode.gdbms.engine.data.driver.DriverException;
99
import com.hardcode.gdbms.engine.values.NumericValue;
100
import com.hardcode.gdbms.engine.values.Value;
101
import com.hardcode.gdbms.engine.values.ValueFactory;
102
import com.iver.cit.gvsig.fmap.core.DefaultFeature;
103
import com.iver.cit.gvsig.fmap.core.IGeometry;
104
import com.iver.cit.gvsig.fmap.core.v02.FConverter;
105
import com.iver.cit.gvsig.fmap.edition.EditionException;
106
import com.iver.cit.gvsig.fmap.layers.FBitSet;
107
import com.iver.cit.gvsig.fmap.layers.FLayer;
108
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
109
import com.iver.cit.gvsig.fmap.layers.SelectableDataSource;
110
import com.iver.cit.gvsig.fmap.layers.layerOperations.AlphanumericData;
111
import com.iver.cit.gvsig.fmap.layers.layerOperations.VectorialData;
112
import com.iver.cit.gvsig.fmap.operations.strategies.FeatureVisitor;
113
import com.iver.cit.gvsig.fmap.operations.strategies.Strategy;
114
import com.iver.cit.gvsig.fmap.operations.strategies.VisitException;
115
import com.iver.cit.gvsig.geoprocess.core.fmap.FeatureProcessor;
116
import com.iver.cit.gvsig.geoprocess.core.fmap.SummarizationFunction;
117
import com.iver.cit.gvsig.geoprocess.core.fmap.XTypes;
118
import com.vividsolutions.jts.geom.Geometry;
119
import com.vividsolutions.jts.geom.GeometryFactory;
120

    
121
/**
122
 * <p>
123
 * This FeatureVisitor processes each geometry of a polygon layer, looks for
124
 * adjacent polygons and verify values of a dissolve field. If these values are
125
 * coincident, it creates a new polygon by unioning original polygons. Also
126
 * applies a sumarization function to numeric fields of original features.
127
 * </p>
128
 * 
129
 * @author azabala
130
 * 
131
 */
132
public class DissolveVisitor implements FeatureVisitor {
133

    
134
        /**
135
         * Allows to get attributes of disolved layer features
136
         */
137
        protected SelectableDataSource recordset;
138

    
139
        /**
140
         * Is used to do spatial querys (looking for adjacent polygons to visited
141
         * feature geometry
142
         */
143
        protected FLyrVect dissolvedLayer;
144

    
145
        /**
146
         * Field which adjacent features must have the same value to dissolve them
147
         */
148
        protected String dissolveField;
149

    
150
        /**
151
         * It marks all features that have already been dissolved (to avoid process
152
         * them in subsecuent steps)
153
         * 
154
         */
155
        protected FBitSet dissolvedGeometries;
156

    
157
        /**
158
         * Relates a numerical field name with its sumarization functions
159
         */
160
        protected Map numericField_sumarizeFunction;
161

    
162
        /**
163
         * Processes results of dissolve operations (save them in a file, or cache
164
         * them in memory, etc)
165
         */
166
        protected FeatureProcessor featureProcessor;
167

    
168
        /**
169
         * Strategy of the layer we want to dissolve
170
         */
171
        protected Strategy strategy;
172
        /**
173
         * Index of the result
174
         */
175
        protected int fid = 0;
176

    
177
        /**
178
         * Constructor
179
         * @param dissolveField
180
         * @param processor
181
         */
182
        public DissolveVisitor(String dissolveField, FeatureProcessor processor) {
183
                this.dissolveField = dissolveField;
184
                this.featureProcessor = processor;
185
                dissolvedGeometries = new FBitSet();
186
        }
187

    
188
        public int getNumProcessedGeometries() {
189
                return dissolvedGeometries.cardinality();
190
        }
191
        
192
        public FBitSet getDissolvedGeometries(){
193
                return dissolvedGeometries;
194
        }
195

    
196
        public void setDissolvedAttributesInfo(Map numericField_sumFunction) {
197
                this.numericField_sumarizeFunction = numericField_sumFunction;
198
        }
199

    
200
        /*
201
         * Algorithm to compute dissolve is strongly based in depth first algorithm
202
         * to traverse graphs.
203
         * 
204
         * It puts features to dissolve in a stack. While stack is not empty, get
205
         * Features and looks for adjacent to it. For each adjacent feature, verify
206
         * its dissolve field value, and if it is similar to feature to dissolve
207
         * with, obtain a new feature by unioning their geometries and by applying
208
         * sumarization functions to its numeric attributes. For each adjacent
209
         * feature, put it in the Stack
210
         */
211
        public void visit(IGeometry g, int index) throws VisitException {
212
                if(g == null)
213
                        return;
214
                if(g.getGeometryType() != XTypes.POLYGON &&
215
                                g.getGeometryType() != XTypes.MULTI)
216
                        return;
217
                if (!dissolvedGeometries.get(index)) {
218
                        // if we havent dissolved this feature
219
                        Stack toDissol = new Stack();// stack for adjacent features
220
                        DissolvedFeature feature;
221
                        try {
222
                                feature = createFeature(g, index);
223
                                toDissol.push(feature);
224
                                ArrayList geometries = new ArrayList();
225
                                Value[] values = dissolveGeometries(toDissol, geometries);
226
                                Geometry geometry = union(geometries);
227
                                Value[] valuesWithFID = new Value[values.length + 1];
228
                                System.arraycopy(values, 0, valuesWithFID, 1, values.length);
229
                                valuesWithFID[0] = ValueFactory.createValue(fid);
230
                                DissolvedFeature dissolved = new DissolvedFeature(null,valuesWithFID, fid/*index*/);
231
                                dissolved.setJtsGeometry(geometry);
232
                                this.featureProcessor.processFeature(dissolved);
233
                                fid++;
234
                                resetFunctions();
235
                        } catch (DriverException e) {
236
                                throw new VisitException(
237
                                                "Error al procesar las geometrias a fusionar durante dissolve");
238
                        } catch (com.iver.cit.gvsig.fmap.DriverException e) {
239
                                throw new VisitException(
240
                                                "Error al procesar las geometrias a fusionar durante dissolve");
241
                        }
242
                }// if
243
        }
244
        
245
        /**
246
         * Returns the union of all geometries of the list
247
         * @param geometries
248
         * @return
249
         */
250
        protected Geometry union(List geometries){
251
                Geometry union = null;
252
                Geometry[] geom = new Geometry[geometries.size()];
253
                geometries.toArray(geom);                
254
                GeometryFactory fact = geom[0].getFactory();
255
            Geometry geomColl = fact.createGeometryCollection(geom);    
256
            union = geomColl.buffer(0);    
257
            return union;
258
        }
259
        
260

    
261
        /**
262
         * FIXME Redise?ar esto, pues el codigo es similar al de Spatial Join
263
         * 
264
         */
265
        protected void resetFunctions() {
266
                if(numericField_sumarizeFunction == null)
267
                        return;
268
                Iterator fieldsIt = numericField_sumarizeFunction.keySet().iterator();
269
                while (fieldsIt.hasNext()) {
270
                        String field = (String) fieldsIt.next();
271
                        SummarizationFunction[] functions = (SummarizationFunction[]) numericField_sumarizeFunction
272
                                        .get(field);
273
                        for (int i = 0; i < functions.length; i++) {
274
                                functions[i].reset();
275
                        }// for
276
                }// while
277
        }
278

    
279
        /**
280
         * Inner class to manage dissolve geoprocess. It mantains feature info
281
         * interesting for dissolve (int index, JTS Geometry, etc)
282
         * 
283
         * @author azabala
284
         * 
285
         */
286
        protected class DissolvedFeature extends DefaultFeature {
287
                int index;
288
                Geometry jtsGeometry;
289

    
290
                public DissolvedFeature(IGeometry geom, Value[] att, int index) {
291
                        super(geom, att);
292
                        this.index = index;
293
                }
294

    
295
                public int getIndex() {
296
                        return index;
297
                }
298

    
299
                public Geometry getJtsGeometry() {
300
                        return jtsGeometry;
301
                }
302

    
303
                public void setJtsGeometry(Geometry jtsGeometry) {
304
                        this.jtsGeometry = jtsGeometry;
305
                }
306

    
307
                public IGeometry getGeometry() {
308
                        IGeometry solution = super.getGeometry();
309
                        if (solution == null && jtsGeometry != null) {
310
                                solution = FConverter.jts_to_igeometry(jtsGeometry);
311
                        }
312
                        return solution;
313
                }
314

    
315
        }
316

    
317
        /**
318
         * Creates a new IFeature with util info for dissolve geoprocess (it ignore
319
         * non numerical values, etc)
320
         * 
321
         * @param g
322
         * @param index
323
         * @return
324
         * @throws DriverException
325
         */
326
        protected DissolvedFeature createFeature(IGeometry g, int index)
327
                        throws DriverException {
328
                DissolvedFeature solution = null;
329
                int numNumericFields = 0;
330
                if(numericField_sumarizeFunction != null)
331
                        numNumericFields = numericField_sumarizeFunction.keySet().size();
332
                // attributes will be dissolve field and sumarized function for
333
                // numerical
334
                // values
335
                Value[] values = new Value[numNumericFields + 1];
336
                if (numericField_sumarizeFunction != null){
337
                        Iterator fieldIt = numericField_sumarizeFunction.keySet().iterator();
338
                        int valueIndex = 0;
339
                        while (fieldIt.hasNext()) {
340
                                String fieldName = (String) fieldIt.next();
341
                                int fieldIndex = recordset.getFieldIndexByName(fieldName);
342
                                values[valueIndex] = recordset.getFieldValue(index, fieldIndex);
343
                                valueIndex++;
344
                        }
345
                }
346
                /*
347
                 * FIXME In this case, we are dissolving with one only dissolve field.
348
                 * To work with many dissolve fields, we must to follow certain
349
                 * conventions: For example, first numeric fields, after that, dissolve
350
                 * fields
351
                 */
352
                int dissolveField = recordset.getFieldIndexByName(this.dissolveField);
353
                values[numNumericFields] = recordset
354
                                .getFieldValue(index, dissolveField);
355
                solution = new DissolvedFeature(g, values, index);
356
                return solution;
357
        }
358
        
359

    
360
//        // FIXME Mover esto a una utility class
361
//        protected Geometry fastUnion(Geometry g1, Geometry g2) {
362
//                Geometry[] geoms = new Geometry[2];
363
//                geoms[0] = g1;
364
//                geoms[1] = g2;
365
//                GeometryCollection gc = g1.getFactory().createGeometryCollection(geoms);
366
//                return gc.buffer(0d);
367
//        }
368

    
369
        protected boolean verifyIfDissolve(DissolvedFeature fet1,
370
                        DissolvedFeature fet2) {
371
                Geometry jtsGeo = fet1.getJtsGeometry();
372
                Geometry featureJtsGeo = fet2.getJtsGeometry();
373
                //FIXME Revisar si intersects considera dos arcos adjacentes
374
                //que no comparten nodo
375
                if (jtsGeo.intersects(featureJtsGeo)) {// They have at least
376
                        //a common point
377

    
378
                        // dissolveField is the last
379
                        int fieldIndex = 0;
380
                        if (numericField_sumarizeFunction != null)
381
                                fieldIndex = numericField_sumarizeFunction.keySet().size();
382
                        Value adjacentVal = fet1.getAttribute(fieldIndex);
383
                        Value val = fet2.getAttribute(fieldIndex);
384
                        if (adjacentVal.doEquals(val)) {
385
                                return true;
386
                        }// if val equals
387
                }// if touches
388
                return false;
389
        }
390

    
391
        /**
392
         * For each individual geometry processed in DissolveVisitor's visit method,
393
         * this Visitor visits its adjacent polygons geometries to check dissolve
394
         * conditions.
395
         * 
396
         * @author azabala
397
         * 
398
         */
399
        protected class IndividualGeometryDissolveVisitor implements FeatureVisitor {
400
                /**
401
                 * Marks index of features that have been dissolved yet
402
                 */
403
                FBitSet dissolvedFeatures;
404

    
405
                /**
406
                 * It saves all features for we are looking for adjacent geometries.
407
                 * Dissolving is similar to network tracking algorithms: one feature is
408
                 * adjacent to two, two is adjacent to four, etc We will save features
409
                 * to process in this stack
410
                 */
411
                Stack featuresToDissolve;
412

    
413
                /**
414
                 * Field use to dissolve adjacent geometries with the same value for it
415
                 * 
416
                 * FIXME Change it for an evaluator of logical expresions
417
                 */
418
                String dissolveField;
419

    
420
                /**
421
                 * Maps for each numerical field its sumarization functions
422
                 */
423
                Map fields_sumarizeFunc;
424

    
425
                /**
426
                 * Feature for which we are looking for features to dissolve
427
                 */
428
                DissolvedFeature feature;
429

    
430
                /**
431
                 * jts geometry of feature
432
                 */
433
                private Geometry featureJtsGeo;
434

    
435
                /**
436
                 * Numeric values result of a sumarization operation
437
                 */
438
                private List sumarizedValues;
439

    
440
                /**
441
                 * Constructor
442
                 * 
443
                 * @param feature
444
                 *            Feature we are analizing to found its adjacents
445
                 * 
446
                 * @param dissolvedFeatures
447
                 *            bitset that marks all analyzed features (to not to analyze
448
                 *            later)
449
                 * 
450
                 * @param featuresToDissolve
451
                 *            stack where we put adjacent features to analyze later
452
                 * 
453
                 * @param fields_sumarize
454
                 *            maps a numeric field of the solution layer with its
455
                 *            sumarization functions
456
                 */
457
                protected IndividualGeometryDissolveVisitor(DissolvedFeature feature,
458
                                FBitSet dissolvedFeatures, Stack featuresToDissolve,
459
                                Map fields_sumarize) {
460
                        this.dissolvedFeatures = dissolvedFeatures;
461
                        this.feature = feature;
462
                        this.featuresToDissolve = featuresToDissolve;
463
                        this.featureJtsGeo = feature.getGeometry().toJTSGeometry();
464
                        feature.setJtsGeometry(featureJtsGeo);
465
                        this.sumarizedValues = new ArrayList();
466
                        this.fields_sumarizeFunc = fields_sumarize;
467

    
468
                }
469

    
470
                public String getProcessDescription() {
471
                        return "Dissolving a polygon with its adjacents";
472
                }
473

    
474
                /**
475
                 * Applies to sumarization functions feature values.
476
                 * 
477
                 * @throws DriverException
478
                 * 
479
                 * FIXME Redise?ar, pues el codigo es similar al de Spatial Join
480
                 */
481
                protected void applySumarizeFunction(int recordIndex)
482
                                throws DriverException {
483
                        // TODO Redesing this with extensible dissolve
484
                        if (fields_sumarizeFunc == null)
485
                                return;
486

    
487
                        Iterator fieldsIt = fields_sumarizeFunc.keySet().iterator();
488
                        while (fieldsIt.hasNext()) {
489
                                String field = (String) fieldsIt.next();
490
                                int fieldIndex = recordset.getFieldIndexByName(field);
491
                                Value valToSumarize = recordset.getFieldValue(recordIndex,
492
                                                fieldIndex);
493
                                SummarizationFunction[] functions = (SummarizationFunction[]) fields_sumarizeFunc
494
                                                .get(field);
495
                                for (int i = 0; i < functions.length; i++) {
496
                                        functions[i].process((NumericValue) valToSumarize);
497
                                        sumarizedValues.add(functions[i].getSumarizeValue());
498
                                }// for
499
                        }// while
500
                }
501

    
502
                /**
503
                 * Analizes a feature (defined by g and its index) to see if it is an
504
                 * adjacent feature to the given feature, and to check its dissolve
505
                 * condition.
506
                 * 
507
                 * @param g
508
                 * @param index
509
                 */
510
                public void visit(IGeometry g, int index) throws VisitException {
511
                        // Is it the feature whose adjacents we are looking for?
512
                        if (index == feature.getIndex())
513
                                return;
514
                        // have we dissolved this feature yet?
515
                        if (dissolvedFeatures.get(index))
516
                                return;
517
                        try {
518
                                DissolvedFeature adjacentFeature = createFeature(g, index);
519
                                Geometry jtsGeo = g.toJTSGeometry();
520
                                adjacentFeature.setJtsGeometry(jtsGeo);
521
                                if (verifyIfDissolve(feature, adjacentFeature)) {
522
                                        dissolvedFeatures.set(index);
523

    
524
                                        // we actualize geometry by unioning
525
                                        featuresToDissolve.push(adjacentFeature);
526
                                        // group by attributes
527
                                        applySumarizeFunction(index);
528
                                }
529
                        } catch (DriverException e) {
530
                                throw new VisitException(
531
                                                "Error al cargar los pol?gonos adyacentes durante un dissolve");
532
                        }        
533
                }// visit
534

    
535
                public void stop(FLayer layer) {
536
                }
537

    
538
                public boolean start(FLayer layer) {
539
                        try {
540
                                recordset = ((AlphanumericData) layer).getRecordset();
541
                                this.applySumarizeFunction(feature.getIndex());
542

    
543
                        } catch (com.iver.cit.gvsig.fmap.DriverException e) {
544
                                return false;
545
                        } catch (DriverException e) {
546
                                return false;
547
                        }
548
                        return true;
549
                }
550

    
551
                public void setFields_sumarizeFunc(Map fields_sumarizeFunc) {
552
                        this.fields_sumarizeFunc = fields_sumarizeFunc;
553
                }
554

    
555
                public Map getFields_sumarizeFunc() {
556
                        return fields_sumarizeFunc;
557
                }
558

    
559
                public Geometry getFeatureJtsGeo() {
560
                        return featureJtsGeo;
561
                }
562

    
563
                public Value[] getSumarizedValues() {
564
                        Value[] solution = new Value[sumarizedValues.size()];
565
                        sumarizedValues.toArray(solution);
566
                        return solution;
567
                }
568

    
569
                public Value[] getSumarizedValues2() {
570
                        Value[] solution = null;
571
                        ArrayList values = new ArrayList();
572
                        if (fields_sumarizeFunc != null){
573
                                Iterator fieldsIt = fields_sumarizeFunc.keySet().iterator();
574
                                while (fieldsIt.hasNext()) {
575
                                        String field = (String) fieldsIt.next();
576
                                        SummarizationFunction[] functions = (SummarizationFunction[]) fields_sumarizeFunc
577
                                                        .get(field);
578
                                        for (int i = 0; i < functions.length; i++) {
579
                                                values.add(functions[i].getSumarizeValue());
580
                                        }// for
581
                                }// while
582
                        }//if
583
                        if (dissolveField != null) {
584
                                try {
585
                                        int dissolveFieldIndex = recordset
586
                                                        .getFieldIndexByName(dissolveField);
587
                                        Value dissolveField = recordset.getFieldValue(feature
588
                                                        .getIndex(), dissolveFieldIndex);
589
                                        values.add(dissolveField);
590
                                } catch (DriverException e) {
591
                                        // TODO Auto-generated catch block
592
                                        e.printStackTrace();
593
                                }
594
                        }
595
                        solution = new Value[values.size()];
596
                        values.toArray(solution);
597
                        return solution;
598
                }
599

    
600
                public void setDissolveField(String dissolveField) {
601
                        this.dissolveField = dissolveField;
602

    
603
                }
604

    
605
                public void setProcessedFeature(DissolvedFeature feature2) {
606
                        this.feature = feature2;
607

    
608
                }
609
        }// IndividualDissolve
610
        
611
        
612

    
613
        protected Value[] dissolveGeometries(Stack toDissol,
614
                        List geometries) throws com.iver.cit.gvsig.fmap.DriverException,
615
                        VisitException {
616

    
617
                IndividualGeometryDissolveVisitor visitor = null;
618
                DissolvedFeature feature = null;
619
                while (toDissol.size() != 0) {
620
                        feature = (DissolvedFeature) toDissol.pop();
621
                        // flags this idx (to not to process in future)
622
                        dissolvedGeometries.set(feature.getIndex());
623
                        if (visitor == null) {
624
                                visitor = new IndividualGeometryDissolveVisitor(feature,
625
                                                dissolvedGeometries, toDissol,
626
                                                numericField_sumarizeFunction);
627
                                visitor.setDissolveField(this.dissolveField);
628
                        } else {
629
                                visitor.setProcessedFeature(feature);
630
                        }
631
                        Rectangle2D bounds = feature.getGeometry().getBounds2D();
632
                        double xmin = bounds.getMinX();
633
                        double ymin = bounds.getMinY();
634
                        double xmax = bounds.getMaxX();
635
                        double ymax = bounds.getMaxY();
636
                        double magnify = 15d;
637
                        Rectangle2D query = new Rectangle2D.Double(xmin - magnify, ymin
638
                                        - magnify, (xmax - xmin) + magnify, (ymax - ymin) + magnify);
639

    
640
                        strategy.process(visitor, query);
641
                        //al final de toda la pila de llamadas recursivas, 
642
                        //geometries tendr? todas las geometrias que debemos dissolver
643
                        geometries.add(feature.getJtsGeometry());
644
                }// while
645
                Value[] values = visitor.getSumarizedValues2();
646
                return values;
647
        }
648

    
649
        protected DissolvedFeature dissolve(Stack toDissol)
650
                        throws com.iver.cit.gvsig.fmap.DriverException, VisitException {
651

    
652
                DissolvedFeature feature = null;
653
                Geometry jtsGeometry = null;
654
                IndividualGeometryDissolveVisitor visitor = null;
655
                while (toDissol.size() != 0) {
656
                        feature = (DissolvedFeature) toDissol.pop();
657
                        // flags this idx (to not to process in future)
658
                        dissolvedGeometries.set(feature.getIndex());
659
                        if (visitor == null) {
660
                                visitor = new IndividualGeometryDissolveVisitor(feature,
661
                                                dissolvedGeometries, toDissol,
662
                                                numericField_sumarizeFunction);
663
                                visitor.setDissolveField(this.dissolveField);
664
                        } else {
665
                                visitor.setProcessedFeature(feature);
666
                        }
667
                        Rectangle2D bounds = feature.getGeometry().getBounds2D();
668
                        double xmin = bounds.getMinX();
669
                        double ymin = bounds.getMinY();
670
                        double xmax = bounds.getMaxX();
671
                        double ymax = bounds.getMaxY();
672
                        double magnify = 15d;
673
                        Rectangle2D query = new Rectangle2D.Double(xmin - magnify, ymin
674
                                        - magnify, (xmax - xmin) + magnify, (ymax - ymin) + magnify);
675

    
676
                        strategy.process(visitor, query);
677

    
678
                        Geometry jtsGeo = visitor.getFeatureJtsGeo();
679
                        if (jtsGeometry == null) {
680
                                jtsGeometry = jtsGeo;
681
                        } else {
682
                                jtsGeometry = jtsGeometry.union(jtsGeo);
683
                        }
684
                }// while
685
                Value[] values = visitor.getSumarizedValues2();
686
                feature = new DissolvedFeature(null, values, -1);
687
                feature.setJtsGeometry(jtsGeometry);
688
                return feature;
689
        }
690

    
691
        public void stop(FLayer layer) {
692
                this.featureProcessor.finish();
693
        }
694

    
695
        public boolean start(FLayer layer) {
696
                if (layer instanceof AlphanumericData && layer instanceof VectorialData) {
697
                        try {
698
                                dissolvedLayer = (FLyrVect) layer;
699
                                recordset = ((AlphanumericData) layer).getRecordset();
700
                                featureProcessor.start();
701
                        } catch (com.iver.cit.gvsig.fmap.DriverException e) {
702
                                return false;
703
                        } catch (EditionException e) {
704
                                return false;
705
                        }
706
                        return true;
707
                }
708
                return false;
709
        }
710

    
711
        public void setStrategy(Strategy strategy) {
712
                this.strategy = strategy;
713
        }
714

    
715
        public String getProcessDescription() {
716
                return "Dissolving polygons of a layer";
717
        }
718

    
719
}