Statistics
| Revision:

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

History | View | Annotate | Download (21.6 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 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/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.driver.exceptions.ReadDriverException;
99
import com.hardcode.gdbms.engine.data.driver.DriverException;
100
import com.hardcode.gdbms.engine.values.NumericValue;
101
import com.hardcode.gdbms.engine.values.Value;
102
import com.hardcode.gdbms.engine.values.ValueFactory;
103
import com.iver.cit.gvsig.exceptions.expansionfile.ExpansionFileReadException;
104
import com.iver.cit.gvsig.exceptions.visitors.ProcessVisitorException;
105
import com.iver.cit.gvsig.exceptions.visitors.StartVisitorException;
106
import com.iver.cit.gvsig.exceptions.visitors.VisitorException;
107
import com.iver.cit.gvsig.fmap.core.DefaultFeature;
108
import com.iver.cit.gvsig.fmap.core.IGeometry;
109
import com.iver.cit.gvsig.fmap.core.v02.FConverter;
110
import com.iver.cit.gvsig.fmap.layers.FBitSet;
111
import com.iver.cit.gvsig.fmap.layers.FLayer;
112
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
113
import com.iver.cit.gvsig.fmap.layers.SelectableDataSource;
114
import com.iver.cit.gvsig.fmap.layers.layerOperations.AlphanumericData;
115
import com.iver.cit.gvsig.fmap.layers.layerOperations.VectorialData;
116
import com.iver.cit.gvsig.fmap.operations.strategies.FeatureVisitor;
117
import com.iver.cit.gvsig.fmap.operations.strategies.Strategy;
118
import com.iver.cit.gvsig.geoprocess.core.fmap.FeatureProcessor;
119
import com.iver.cit.gvsig.geoprocess.core.fmap.SummarizationFunction;
120
import com.iver.cit.gvsig.geoprocess.core.fmap.XTypes;
121
import com.vividsolutions.jts.geom.Geometry;
122
import com.vividsolutions.jts.geom.GeometryFactory;
123

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

    
137
        /**
138
         * Allows to get attributes of disolved layer features
139
         */
140
        protected SelectableDataSource recordset;
141

    
142
        /**
143
         * Is used to do spatial querys (looking for adjacent polygons to visited
144
         * feature geometry
145
         */
146
        protected FLyrVect dissolvedLayer;
147

    
148
        /**
149
         * Field which adjacent features must have the same value to dissolve them
150
         */
151
        protected String dissolveField;
152

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

    
160
        /**
161
         * Relates a numerical field name with its sumarization functions
162
         */
163
        protected Map numericField_sumarizeFunction;
164

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

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

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

    
191
        public int getNumProcessedGeometries() {
192
                return dissolvedGeometries.cardinality();
193
        }
194

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

    
199
        /*
200
         * Algorithm to compute dissolve is strongly based in depth first algorithm
201
         * to traverse graphs.
202
         *
203
         * It puts features to dissolve in a stack. While stack is not empty, get
204
         * Features and looks for adjacent to it. For each adjacent feature, verify
205
         * its dissolve field value, and if it is similar to feature to dissolve
206
         * with, obtain a new feature by unioning their geometries and by applying
207
         * sumarization functions to its numeric attributes. For each adjacent
208
         * feature, put it in the Stack
209
         */
210
        public void visit(IGeometry g, int index) throws VisitorException, ProcessVisitorException {
211
                if(g == null)
212
                        return;
213
                if(g.getGeometryType() != XTypes.POLYGON &&
214
                                g.getGeometryType() != XTypes.MULTI)
215
                        return;
216
                if (!dissolvedGeometries.get(index)) {
217
                        // if we havent dissolved this feature
218
                        Stack toDissol = new Stack();// stack for adjacent features
219
                        DissolvedFeature feature;
220
                        try {
221
                                feature = createFeature(g, index);
222
                                toDissol.push(feature);
223
                                ArrayList geometries = new ArrayList();
224
                                Value[] values = dissolveGeometries(toDissol, geometries);
225
                                Geometry geometry = union(geometries);
226
                                Value[] valuesWithFID = new Value[values.length + 1];
227
                                System.arraycopy(values, 0, valuesWithFID, 1, values.length);
228
                                valuesWithFID[0] = ValueFactory.createValue(fid);
229
                                DissolvedFeature dissolved = new DissolvedFeature(null,valuesWithFID, fid/*index*/);
230
                                dissolved.setJtsGeometry(geometry);
231
                                this.featureProcessor.processFeature(dissolved);
232
                                fid++;
233
                                resetFunctions();
234
                        } catch (ReadDriverException e) {
235
                                throw new ProcessVisitorException(recordset.getName(),e,
236
                                        "Error al procesar las geometrias a fusionar durante dissolve");
237
                        } catch (ExpansionFileReadException e) {
238
                                throw new ProcessVisitorException(recordset.getName(),e,
239
                                        "Error al procesar las geometrias a fusionar durante dissolve");
240
                        } catch (VisitorException e) {
241
                                throw new ProcessVisitorException(recordset.getName(),e,
242
                                "Error al procesar las geometrias a fusionar durante dissolve");
243
                        }
244
                }// if
245
        }
246

    
247
        /**
248
         * Returns the union of all geometries of the list
249
         * @param geometries
250
         * @return
251
         */
252
        protected Geometry union(List geometries){
253
                Geometry union = null;
254
                Geometry[] geom = new Geometry[geometries.size()];
255
                geometries.toArray(geom);
256
                GeometryFactory fact = geom[0].getFactory();
257
            Geometry geomColl = fact.createGeometryCollection(geom);
258
System.out.println(geomColl.toText());
259
            union = geomColl.buffer(0);
260
System.out.println(union.toText());
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 ReadDriverException
328
         * @throws DriverException
329
         */
330
        protected DissolvedFeature createFeature(IGeometry g, int index) throws ReadDriverException {
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
                 * @throws ReadDriverException
480
                 *
481
                 * @throws DriverException
482
                 *
483
                 * FIXME Redise?ar, pues el codigo es similar al de Spatial Join
484
                 */
485
                protected void applySumarizeFunction(int recordIndex) throws ReadDriverException {
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 VisitorException, ProcessVisitorException {
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 (ReadDriverException e) {
533
                                throw new ProcessVisitorException(recordset.getName(),e,
534
                                                "Error al cargar los pol?gonos adyacentes durante un dissolve");
535
                        }
536
                }// visit
537

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

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

    
546
                        } catch (ReadDriverException e) {
547
                                return false;
548
                        }
549
                        return true;
550
                }
551

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

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

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

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

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

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

    
604
                }
605

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

    
609
                }
610
        }// IndividualDissolve
611

    
612

    
613

    
614
        protected Value[] dissolveGeometries(Stack toDissol,
615
                        List geometries) throws ProcessVisitorException, ReadDriverException, ExpansionFileReadException, VisitorException {
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 ReadDriverException, ExpansionFileReadException, VisitorException {
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) throws VisitorException {
692
                this.featureProcessor.finish();
693
        }
694

    
695
        public boolean start(FLayer layer) throws StartVisitorException {
696
                if (layer instanceof AlphanumericData && layer instanceof VectorialData) {
697
                        try {
698
                                dissolvedLayer = (FLyrVect) layer;
699
                                recordset = ((AlphanumericData) layer).getRecordset();
700
                                featureProcessor.start();
701
                        } catch (ReadDriverException e) {
702
                                return false;
703
                        }
704
                        return true;
705
                }
706
                return false;
707
        }
708

    
709
        public void setStrategy(Strategy strategy) {
710
                this.strategy = strategy;
711
        }
712

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

    
717
}