Statistics
| Revision:

root / trunk / extensions / extGeoProcessing / src / com / iver / cit / gvsig / geoprocess / impl / dissolve / fmap / DissolveVisitor.java @ 5918

History | View | Annotate | Download (21.3 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 5918 2006-06-20 18:20:45Z azabala $
47
 * $Log$
48
 * Revision 1.1  2006-06-20 18:20:45  azabala
49
 * first version in cvs
50
 *
51
 * Revision 1.3  2006/06/08 18:24:43  azabala
52
 * modificaciones para admitir capas de shapeType MULTI
53
 *
54
 * Revision 1.2  2006/06/02 18:21:28  azabala
55
 * *** empty log message ***
56
 *
57
 * Revision 1.1  2006/05/24 21:11:14  azabala
58
 * primera version en cvs despues de refactoring orientado a crear un framework extensible de geoprocessing
59
 *
60
 * Revision 1.5  2006/05/08 15:37:26  azabala
61
 * added alphanumeric dissolve
62
 *
63
 * Revision 1.4  2006/05/01 19:14:30  azabala
64
 * comentario
65
 *
66
 * Revision 1.3  2006/03/15 18:33:24  azabala
67
 * *** empty log message ***
68
 *
69
 * Revision 1.2  2006/03/07 21:01:33  azabala
70
 * *** empty log message ***
71
 *
72
 * Revision 1.1  2006/03/06 19:48:39  azabala
73
 * *** empty log message ***
74
 *
75
 * Revision 1.2  2006/03/05 19:58:30  azabala
76
 * *** empty log message ***
77
 *
78
 * Revision 1.1  2006/02/26 20:54:04  azabala
79
 * *** empty log message ***
80
 *
81
 *
82
 */
83
package com.iver.cit.gvsig.geoprocess.impl.dissolve.fmap;
84

    
85
import java.awt.geom.Rectangle2D;
86
import java.util.ArrayList;
87
import java.util.Iterator;
88
import java.util.List;
89
import java.util.Map;
90
import java.util.Stack;
91

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

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

    
128
        /**
129
         * Allows to get attributes of disolved layer features
130
         */
131
        protected SelectableDataSource recordset;
132

    
133
        /**
134
         * Is used to do spatial querys (looking for adjacent polygons to visited
135
         * feature geometry
136
         */
137
        protected FLyrVect dissolvedLayer;
138

    
139
        /**
140
         * Field which adjacent features must have the same value to dissolve them
141
         */
142
        protected String dissolveField;
143

    
144
        /**
145
         * It marks all features that have already been dissolved (to avoid process
146
         * them in subsecuent steps)
147
         * 
148
         */
149
        protected FBitSet dissolvedGeometries;
150

    
151
        /**
152
         * Relates a numerical field name with its sumarization functions
153
         */
154
        protected Map numericField_sumarizeFunction;
155

    
156
        /**
157
         * Processes results of dissolve operations (save them in a file, or cache
158
         * them in memory, etc)
159
         */
160
        protected FeatureProcessor featureProcessor;
161

    
162
        /**
163
         * Strategy of the layer we want to dissolve
164
         */
165
        protected Strategy strategy;
166
        /**
167
         * Index of the result
168
         */
169
        protected int fid = 0;
170

    
171
        /**
172
         * Constructor
173
         * @param dissolveField
174
         * @param processor
175
         */
176
        public DissolveVisitor(String dissolveField, FeatureProcessor processor) {
177
                this.dissolveField = dissolveField;
178
                this.featureProcessor = processor;
179
                dissolvedGeometries = new FBitSet();
180
        }
181

    
182
        public int getNumProcessedGeometries() {
183
                return dissolvedGeometries.cardinality();
184
        }
185

    
186
        public void setDissolvedAttributesInfo(Map numericField_sumFunction) {
187
                this.numericField_sumarizeFunction = numericField_sumFunction;
188
        }
189

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

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

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

    
293
                public DissolvedFeature(IGeometry geom, Value[] att, int index) {
294
                        super(geom, att);
295
                        this.index = index;
296
                }
297

    
298
                public int getIndex() {
299
                        return index;
300
                }
301

    
302
                public Geometry getJtsGeometry() {
303
                        return jtsGeometry;
304
                }
305

    
306
                public void setJtsGeometry(Geometry jtsGeometry) {
307
                        this.jtsGeometry = jtsGeometry;
308
                }
309

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

    
318
        }
319

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

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

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

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

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

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

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

    
423
                /**
424
                 * Maps for each numerical field its sumarization functions
425
                 */
426
                Map fields_sumarizeFunc;
427

    
428
                /**
429
                 * Feature for which we are looking for features to dissolve
430
                 */
431
                DissolvedFeature feature;
432

    
433
                /**
434
                 * jts geometry of feature
435
                 */
436
                private Geometry featureJtsGeo;
437

    
438
                /**
439
                 * Numeric values result of a sumarization operation
440
                 */
441
                private List sumarizedValues;
442

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

    
471
                }
472

    
473
                public String getProcessDescription() {
474
                        return "Dissolving a polygon with its adjacents";
475
                }
476

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

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

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

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

    
538
                public void stop(FLayer layer) {
539
                }
540

    
541
                public boolean start(FLayer layer) {
542
                        try {
543
                                recordset = ((AlphanumericData) layer).getRecordset();
544
                                this.applySumarizeFunction(feature.getIndex());
545

    
546
                        } catch (com.iver.cit.gvsig.fmap.DriverException e) {
547
                                return false;
548
                        } catch (DriverException e) {
549
                                return false;
550
                        }
551
                        return true;
552
                }
553

    
554
                public void setFields_sumarizeFunc(Map fields_sumarizeFunc) {
555
                        this.fields_sumarizeFunc = fields_sumarizeFunc;
556
                }
557

    
558
                public Map getFields_sumarizeFunc() {
559
                        return fields_sumarizeFunc;
560
                }
561

    
562
                public Geometry getFeatureJtsGeo() {
563
                        return featureJtsGeo;
564
                }
565

    
566
                public Value[] getSumarizedValues() {
567
                        Value[] solution = new Value[sumarizedValues.size()];
568
                        sumarizedValues.toArray(solution);
569
                        return solution;
570
                }
571

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

    
603
                public void setDissolveField(String dissolveField) {
604
                        this.dissolveField = dissolveField;
605

    
606
                }
607

    
608
                public void setProcessedFeature(DissolvedFeature feature2) {
609
                        this.feature = feature2;
610

    
611
                }
612
        }// IndividualDissolve
613
        
614
        
615

    
616
        protected Value[] dissolveGeometries(Stack toDissol,
617
                        List geometries) throws com.iver.cit.gvsig.fmap.DriverException,
618
                        VisitException {
619

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

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

    
652
        protected DissolvedFeature dissolve(Stack toDissol)
653
                        throws com.iver.cit.gvsig.fmap.DriverException, VisitException {
654

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

    
679
                        strategy.process(visitor, query);
680

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

    
694
        public void stop(FLayer layer) {
695
                this.featureProcessor.finish();
696
        }
697

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

    
714
        public void setStrategy(Strategy strategy) {
715
                this.strategy = strategy;
716
        }
717

    
718
        public String getProcessDescription() {
719
                return "Dissolving polygons of a layer";
720
        }
721

    
722
}