Statistics
| Revision:

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

History | View | Annotate | Download (21 KB)

1 5412 azabala
/*
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$
47
 * $Log$
48 5628 azabala
 * Revision 1.2  2006-06-02 18:21:28  azabala
49
 * *** empty log message ***
50
 *
51
 * Revision 1.1  2006/05/24 21:11:14  azabala
52 5412 azabala
 * primera version en cvs despues de refactoring orientado a crear un framework extensible de geoprocessing
53
 *
54
 * Revision 1.5  2006/05/08 15:37:26  azabala
55
 * added alphanumeric dissolve
56
 *
57
 * Revision 1.4  2006/05/01 19:14:30  azabala
58
 * comentario
59
 *
60
 * Revision 1.3  2006/03/15 18:33:24  azabala
61
 * *** empty log message ***
62
 *
63
 * Revision 1.2  2006/03/07 21:01:33  azabala
64
 * *** empty log message ***
65
 *
66
 * Revision 1.1  2006/03/06 19:48:39  azabala
67
 * *** empty log message ***
68
 *
69
 * Revision 1.2  2006/03/05 19:58:30  azabala
70
 * *** empty log message ***
71
 *
72
 * Revision 1.1  2006/02/26 20:54:04  azabala
73
 * *** empty log message ***
74
 *
75
 *
76
 */
77
package com.iver.cit.gvsig.geoprocess.dissolve.fmap;
78
79
import java.awt.geom.Rectangle2D;
80
import java.util.ArrayList;
81
import java.util.Iterator;
82
import java.util.List;
83
import java.util.Map;
84
import java.util.Stack;
85
86
import com.hardcode.gdbms.engine.data.driver.DriverException;
87
import com.hardcode.gdbms.engine.values.NumericValue;
88
import com.hardcode.gdbms.engine.values.Value;
89
import com.hardcode.gdbms.engine.values.ValueFactory;
90
import com.iver.cit.gvsig.fmap.core.DefaultFeature;
91
import com.iver.cit.gvsig.fmap.core.IGeometry;
92
import com.iver.cit.gvsig.fmap.core.v02.FConverter;
93
import com.iver.cit.gvsig.fmap.edition.EditionException;
94
import com.iver.cit.gvsig.fmap.layers.FBitSet;
95
import com.iver.cit.gvsig.fmap.layers.FLayer;
96
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
97
import com.iver.cit.gvsig.fmap.layers.SelectableDataSource;
98
import com.iver.cit.gvsig.fmap.layers.layerOperations.AlphanumericData;
99
import com.iver.cit.gvsig.fmap.layers.layerOperations.VectorialData;
100
import com.iver.cit.gvsig.fmap.operations.strategies.FeatureVisitor;
101
import com.iver.cit.gvsig.fmap.operations.strategies.Strategy;
102
import com.iver.cit.gvsig.fmap.operations.strategies.VisitException;
103
import com.iver.cit.gvsig.geoprocess.core.fmap.FeatureProcessor;
104
import com.iver.cit.gvsig.geoprocess.core.fmap.SummarizationFunction;
105
import com.vividsolutions.jts.geom.Geometry;
106
import com.vividsolutions.jts.geom.GeometryFactory;
107
108
/**
109
 * <p>
110
 * This FeatureVisitor processes each geometry of a polygon layer, looks for
111
 * adjacent polygons and verify values of a dissolve field. If these values are
112
 * coincident, it creates a new polygon by unioning original polygons. Also
113
 * applies a sumarization function to numeric fields of original features.
114
 * </p>
115
 *
116
 * @author azabala
117
 *
118
 */
119
public class DissolveVisitor implements FeatureVisitor {
120
121
        /**
122
         * Allows to get attributes of disolved layer features
123
         */
124
        protected SelectableDataSource recordset;
125
126
        /**
127
         * Is used to do spatial querys (looking for adjacent polygons to visited
128
         * feature geometry
129
         */
130
        protected FLyrVect dissolvedLayer;
131
132
        /**
133
         * Field which adjacent features must have the same value to dissolve them
134
         */
135
        protected String dissolveField;
136
137
        /**
138
         * It marks all features that have already been dissolved (to avoid process
139
         * them in subsecuent steps)
140
         *
141
         */
142
        protected FBitSet dissolvedGeometries;
143
144
        /**
145
         * Relates a numerical field name with its sumarization functions
146
         */
147
        protected Map numericField_sumarizeFunction;
148
149
        /**
150
         * Processes results of dissolve operations (save them in a file, or cache
151
         * them in memory, etc)
152
         */
153
        protected FeatureProcessor featureProcessor;
154
155
        /**
156
         * Strategy of the layer we want to dissolve
157
         */
158
        protected Strategy strategy;
159
        /**
160
         * Index of the result
161
         */
162
        protected int fid = 0;
163
164
        /**
165
         * Constructor
166
         * @param dissolveField
167
         * @param processor
168
         */
169
        public DissolveVisitor(String dissolveField, FeatureProcessor processor) {
170
                this.dissolveField = dissolveField;
171
                this.featureProcessor = processor;
172
                dissolvedGeometries = new FBitSet();
173
        }
174
175
        public int getNumProcessedGeometries() {
176
                return dissolvedGeometries.cardinality();
177
        }
178
179
        public void setDissolvedAttributesInfo(Map numericField_sumFunction) {
180
                this.numericField_sumarizeFunction = numericField_sumFunction;
181
        }
182
183
        /*
184
         * Algorithm to compute dissolve is strongly based in depth first algorithm
185
         * to traverse graphs.
186
         *
187
         * It puts features to dissolve in a stack. While stack is not empty, get
188
         * Features and looks for adjacent to it. For each adjacent feature, verify
189
         * its dissolve field value, and if it is similar to feature to dissolve
190
         * with, obtain a new feature by unioning their geometries and by applying
191
         * sumarization functions to its numeric attributes. For each adjacent
192
         * feature, put it in the Stack
193
         */
194
        public void visit(IGeometry g, int index) throws VisitException {
195 5628 azabala
                if(g == null)
196
                        return;
197 5412 azabala
                if (!dissolvedGeometries.get(index)) {
198
                        // if we havent dissolved this feature
199
                        Stack toDissol = new Stack();// stack for adjacent features
200
                        DissolvedFeature feature;
201
                        try {
202
                                feature = createFeature(g, index);
203
                                toDissol.push(feature);
204
                                ArrayList geometries = new ArrayList();
205
                                Value[] values = dissolveGeometries(toDissol, geometries);
206
                                Geometry geometry = union(geometries);
207
                                Value[] valuesWithFID = new Value[values.length + 1];
208
                                System.arraycopy(values, 0, valuesWithFID, 1, values.length);
209
                                valuesWithFID[0] = ValueFactory.createValue(fid);
210
                                DissolvedFeature dissolved = new DissolvedFeature(null,valuesWithFID, fid/*index*/);
211
                                dissolved.setJtsGeometry(geometry);
212
                                this.featureProcessor.processFeature(dissolved);
213
                                fid++;
214
                                resetFunctions();
215
                        } catch (DriverException e) {
216
                                throw new VisitException(
217
                                                "Error al procesar las geometrias a fusionar durante dissolve");
218
                        } catch (com.iver.cit.gvsig.fmap.DriverException e) {
219
                                throw new VisitException(
220
                                                "Error al procesar las geometrias a fusionar durante dissolve");
221
                        }
222
                }// if
223
        }
224
225
        /**
226
         * Returns the union of all geometries of the list
227
         * @param geometries
228
         * @return
229
         */
230
        protected Geometry union(List geometries){
231
                Geometry union = null;
232
                Geometry[] geom = new Geometry[geometries.size()];
233
                geometries.toArray(geom);
234
                //This algorithm is a lot of slower than comment one
235
                //based in buffer(0), but is robust (in JTS union
236
                //always nodes geometries
237
//                for(int i = 0; i < geom.length; i++){
238
//                        if(union == null)
239
//                                union = geom[i];
240
//                        else{
241
//                                //Revisar si no podemos calcular la interseccion, las
242
//                                //dos diferencias, y dissolver estas
243
//                                union = union.union(geom[i]);
244
//
245
//                                //FIXME Esto est? dando TopologyException por un tubo
246
//                        }
247
//                }
248
                GeometryFactory fact = geom[0].getFactory();
249
            Geometry geomColl = fact.createGeometryCollection(geom);
250
            union = geomColl.buffer(0);
251
            return union;
252
        }
253
254
        /**
255
         * FIXME Redise?ar esto, pues el codigo es similar al de Spatial Join
256
         *
257
         */
258
        protected void resetFunctions() {
259
                if(numericField_sumarizeFunction == null)
260
                        return;
261
                Iterator fieldsIt = numericField_sumarizeFunction.keySet().iterator();
262
                while (fieldsIt.hasNext()) {
263
                        String field = (String) fieldsIt.next();
264
                        SummarizationFunction[] functions = (SummarizationFunction[]) numericField_sumarizeFunction
265
                                        .get(field);
266
                        for (int i = 0; i < functions.length; i++) {
267
                                functions[i].reset();
268
                        }// for
269
                }// while
270
        }
271
272
        /**
273
         * Inner class to manage dissolve geoprocess. It mantains feature info
274
         * interesting for dissolve (int index, JTS Geometry, etc)
275
         *
276
         * @author azabala
277
         *
278
         */
279
        protected class DissolvedFeature extends DefaultFeature {
280
                int index;
281
                Geometry jtsGeometry;
282
283
                public DissolvedFeature(IGeometry geom, Value[] att, int index) {
284
                        super(geom, att);
285
                        this.index = index;
286
                }
287
288
                public int getIndex() {
289
                        return index;
290
                }
291
292
                public Geometry getJtsGeometry() {
293
                        return jtsGeometry;
294
                }
295
296
                public void setJtsGeometry(Geometry jtsGeometry) {
297
                        this.jtsGeometry = jtsGeometry;
298
                }
299
300
                public IGeometry getGeometry() {
301
                        IGeometry solution = super.getGeometry();
302
                        if (solution == null && jtsGeometry != null) {
303
                                solution = FConverter.jts_to_igeometry(jtsGeometry);
304
                        }
305
                        return solution;
306
                }
307
308
        }
309
310
        /**
311
         * Creates a new IFeature with util info for dissolve geoprocess (it ignore
312
         * non numerical values, etc)
313
         *
314
         * @param g
315
         * @param index
316
         * @return
317
         * @throws DriverException
318
         */
319
        protected DissolvedFeature createFeature(IGeometry g, int index)
320
                        throws DriverException {
321
                DissolvedFeature solution = null;
322
                int numNumericFields = 0;
323
                if(numericField_sumarizeFunction != null)
324
                        numNumericFields = numericField_sumarizeFunction.keySet().size();
325
                // attributes will be dissolve field and sumarized function for
326
                // numerical
327
                // values
328
                Value[] values = new Value[numNumericFields + 1];
329
                if (numericField_sumarizeFunction != null){
330
                        Iterator fieldIt = numericField_sumarizeFunction.keySet().iterator();
331
                        int valueIndex = 0;
332
                        while (fieldIt.hasNext()) {
333
                                String fieldName = (String) fieldIt.next();
334
                                int fieldIndex = recordset.getFieldIndexByName(fieldName);
335
                                values[valueIndex] = recordset.getFieldValue(index, fieldIndex);
336
                                valueIndex++;
337
                        }
338
                }
339
                /*
340
                 * FIXME In this case, we are dissolving with one only dissolve field.
341
                 * To work with many dissolve fields, we must to follow certain
342
                 * conventions: For example, first numeric fields, after that, dissolve
343
                 * fields
344
                 */
345
                int dissolveField = recordset.getFieldIndexByName(this.dissolveField);
346
                values[numNumericFields] = recordset
347
                                .getFieldValue(index, dissolveField);
348
                solution = new DissolvedFeature(g, values, index);
349
                return solution;
350
        }
351
352
353
//        // FIXME Mover esto a una utility class
354
//        protected Geometry fastUnion(Geometry g1, Geometry g2) {
355
//                Geometry[] geoms = new Geometry[2];
356
//                geoms[0] = g1;
357
//                geoms[1] = g2;
358
//                GeometryCollection gc = g1.getFactory().createGeometryCollection(geoms);
359
//                return gc.buffer(0d);
360
//        }
361
362
        protected boolean verifyIfDissolve(DissolvedFeature fet1,
363
                        DissolvedFeature fet2) {
364
                Geometry jtsGeo = fet1.getJtsGeometry();
365
                Geometry featureJtsGeo = fet2.getJtsGeometry();
366
                //FIXME Revisar si intersects considera dos arcos adjacentes
367
                //que no comparten nodo
368
                if (jtsGeo.intersects(featureJtsGeo)) {// They have at least
369
                        //a common point
370
371
                        // dissolveField is the last
372
                        int fieldIndex = 0;
373
                        if (numericField_sumarizeFunction != null)
374
                                fieldIndex = numericField_sumarizeFunction.keySet().size();
375
                        Value adjacentVal = fet1.getAttribute(fieldIndex);
376
                        Value val = fet2.getAttribute(fieldIndex);
377
                        if (adjacentVal.doEquals(val)) {
378
                                return true;
379
                        }// if val equals
380
                }// if touches
381
                return false;
382
        }
383
384
        /**
385
         * For each individual geometry processed in DissolveVisitor's visit method,
386
         * this Visitor visits its adjacent polygons geometries to check dissolve
387
         * conditions.
388
         *
389
         * @author azabala
390
         *
391
         */
392
        protected class IndividualGeometryDissolveVisitor implements FeatureVisitor {
393
                /**
394
                 * Marks index of features that have been dissolved yet
395
                 */
396
                FBitSet dissolvedFeatures;
397
398
                /**
399
                 * It saves all features for we are looking for adjacent geometries.
400
                 * Dissolving is similar to network tracking algorithms: one feature is
401
                 * adjacent to two, two is adjacent to four, etc We will save features
402
                 * to process in this stack
403
                 */
404
                Stack featuresToDissolve;
405
406
                /**
407
                 * Field use to dissolve adjacent geometries with the same value for it
408
                 *
409
                 * FIXME Change it for an evaluator of logical expresions
410
                 */
411
                String dissolveField;
412
413
                /**
414
                 * Maps for each numerical field its sumarization functions
415
                 */
416
                Map fields_sumarizeFunc;
417
418
                /**
419
                 * Feature for which we are looking for features to dissolve
420
                 */
421
                DissolvedFeature feature;
422
423
                /**
424
                 * jts geometry of feature
425
                 */
426
                private Geometry featureJtsGeo;
427
428
                /**
429
                 * Numeric values result of a sumarization operation
430
                 */
431
                private List sumarizedValues;
432
433
                /**
434
                 * Constructor
435
                 *
436
                 * @param feature
437
                 *            Feature we are analizing to found its adjacents
438
                 *
439
                 * @param dissolvedFeatures
440
                 *            bitset that marks all analyzed features (to not to analyze
441
                 *            later)
442
                 *
443
                 * @param featuresToDissolve
444
                 *            stack where we put adjacent features to analyze later
445
                 *
446
                 * @param fields_sumarize
447
                 *            maps a numeric field of the solution layer with its
448
                 *            sumarization functions
449
                 */
450
                protected IndividualGeometryDissolveVisitor(DissolvedFeature feature,
451
                                FBitSet dissolvedFeatures, Stack featuresToDissolve,
452
                                Map fields_sumarize) {
453
                        this.dissolvedFeatures = dissolvedFeatures;
454
                        this.feature = feature;
455
                        this.featuresToDissolve = featuresToDissolve;
456
                        this.featureJtsGeo = feature.getGeometry().toJTSGeometry();
457
                        feature.setJtsGeometry(featureJtsGeo);
458
                        this.sumarizedValues = new ArrayList();
459
                        this.fields_sumarizeFunc = fields_sumarize;
460
461
                }
462
463
                public String getProcessDescription() {
464
                        return "Dissolving a polygon with its adjacents";
465
                }
466
467
                /**
468
                 * Applies to sumarization functions feature values.
469
                 *
470
                 * @throws DriverException
471
                 *
472
                 * FIXME Redise?ar, pues el codigo es similar al de Spatial Join
473
                 */
474
                protected void applySumarizeFunction(int recordIndex)
475
                                throws DriverException {
476
                        // TODO Redesing this with extensible dissolve
477
                        if (fields_sumarizeFunc == null)
478
                                return;
479
480
                        Iterator fieldsIt = fields_sumarizeFunc.keySet().iterator();
481
                        while (fieldsIt.hasNext()) {
482
                                String field = (String) fieldsIt.next();
483
                                int fieldIndex = recordset.getFieldIndexByName(field);
484
                                Value valToSumarize = recordset.getFieldValue(recordIndex,
485
                                                fieldIndex);
486
                                SummarizationFunction[] functions = (SummarizationFunction[]) fields_sumarizeFunc
487
                                                .get(field);
488
                                for (int i = 0; i < functions.length; i++) {
489
                                        functions[i].process((NumericValue) valToSumarize);
490
                                        sumarizedValues.add(functions[i].getSumarizeValue());
491
                                }// for
492
                        }// while
493
                }
494
495
                /**
496
                 * Analizes a feature (defined by g and its index) to see if it is an
497
                 * adjacent feature to the given feature, and to check its dissolve
498
                 * condition.
499
                 *
500
                 * @param g
501
                 * @param index
502
                 */
503
                public void visit(IGeometry g, int index) throws VisitException {
504
                        // Is it the feature whose adjacents we are looking for?
505
                        if (index == feature.getIndex())
506
                                return;
507
                        // have we dissolved this feature yet?
508
                        if (dissolvedFeatures.get(index))
509
                                return;
510
                        try {
511
                                DissolvedFeature adjacentFeature = createFeature(g, index);
512
                                Geometry jtsGeo = g.toJTSGeometry();
513
                                adjacentFeature.setJtsGeometry(jtsGeo);
514
                                if (verifyIfDissolve(feature, adjacentFeature)) {
515
                                        dissolvedFeatures.set(index);
516
517
                                        // we actualize geometry by unioning
518
                                        featuresToDissolve.push(adjacentFeature);
519
                                        // group by attributes
520
                                        applySumarizeFunction(index);
521
                                }
522
                        } catch (DriverException e) {
523
                                throw new VisitException(
524
                                                "Error al cargar los pol?gonos adyacentes durante un dissolve");
525
                        }
526
                }// visit
527
528
                public void stop(FLayer layer) {
529
                }
530
531
                public boolean start(FLayer layer) {
532
                        try {
533
                                recordset = ((AlphanumericData) layer).getRecordset();
534
                                this.applySumarizeFunction(feature.getIndex());
535
536
                        } catch (com.iver.cit.gvsig.fmap.DriverException e) {
537
                                return false;
538
                        } catch (DriverException e) {
539
                                return false;
540
                        }
541
                        return true;
542
                }
543
544
                public void setFields_sumarizeFunc(Map fields_sumarizeFunc) {
545
                        this.fields_sumarizeFunc = fields_sumarizeFunc;
546
                }
547
548
                public Map getFields_sumarizeFunc() {
549
                        return fields_sumarizeFunc;
550
                }
551
552
                public Geometry getFeatureJtsGeo() {
553
                        return featureJtsGeo;
554
                }
555
556
                public Value[] getSumarizedValues() {
557
                        Value[] solution = new Value[sumarizedValues.size()];
558
                        sumarizedValues.toArray(solution);
559
                        return solution;
560
                }
561
562
                public Value[] getSumarizedValues2() {
563
                        Value[] solution = null;
564
                        ArrayList values = new ArrayList();
565
                        if (fields_sumarizeFunc != null){
566
                                Iterator fieldsIt = fields_sumarizeFunc.keySet().iterator();
567
                                while (fieldsIt.hasNext()) {
568
                                        String field = (String) fieldsIt.next();
569
                                        SummarizationFunction[] functions = (SummarizationFunction[]) fields_sumarizeFunc
570
                                                        .get(field);
571
                                        for (int i = 0; i < functions.length; i++) {
572
                                                values.add(functions[i].getSumarizeValue());
573
                                        }// for
574
                                }// while
575
                        }//if
576
                        if (dissolveField != null) {
577
                                try {
578
                                        int dissolveFieldIndex = recordset
579
                                                        .getFieldIndexByName(dissolveField);
580
                                        Value dissolveField = recordset.getFieldValue(feature
581
                                                        .getIndex(), dissolveFieldIndex);
582
                                        values.add(dissolveField);
583
                                } catch (DriverException e) {
584
                                        // TODO Auto-generated catch block
585
                                        e.printStackTrace();
586
                                }
587
                        }
588
                        solution = new Value[values.size()];
589
                        values.toArray(solution);
590
                        return solution;
591
                }
592
593
                public void setDissolveField(String dissolveField) {
594
                        this.dissolveField = dissolveField;
595
596
                }
597
598
                public void setProcessedFeature(DissolvedFeature feature2) {
599
                        this.feature = feature2;
600
601
                }
602
        }// IndividualDissolve
603
604
605
606
        protected Value[] dissolveGeometries(Stack toDissol,
607
                        List geometries) throws com.iver.cit.gvsig.fmap.DriverException,
608
                        VisitException {
609
610
                IndividualGeometryDissolveVisitor visitor = null;
611
                DissolvedFeature feature = null;
612
                while (toDissol.size() != 0) {
613
                        feature = (DissolvedFeature) toDissol.pop();
614
                        // flags this idx (to not to process in future)
615
                        dissolvedGeometries.set(feature.getIndex());
616
                        if (visitor == null) {
617
                                visitor = new IndividualGeometryDissolveVisitor(feature,
618
                                                dissolvedGeometries, toDissol,
619
                                                numericField_sumarizeFunction);
620
                                visitor.setDissolveField(this.dissolveField);
621
                        } else {
622
                                visitor.setProcessedFeature(feature);
623
                        }
624
                        Rectangle2D bounds = feature.getGeometry().getBounds2D();
625
                        double xmin = bounds.getMinX();
626
                        double ymin = bounds.getMinY();
627
                        double xmax = bounds.getMaxX();
628
                        double ymax = bounds.getMaxY();
629
                        double magnify = 15d;
630
                        Rectangle2D query = new Rectangle2D.Double(xmin - magnify, ymin
631
                                        - magnify, (xmax - xmin) + magnify, (ymax - ymin) + magnify);
632
633
                        strategy.process(visitor, query);
634
                        //al final de toda la pila de llamadas recursivas,
635
                        //geometries tendr? todas las geometrias que debemos dissolver
636
                        geometries.add(feature.getJtsGeometry());
637
                }// while
638
                Value[] values = visitor.getSumarizedValues2();
639
                return values;
640
        }
641
642
        protected DissolvedFeature dissolve(Stack toDissol)
643
                        throws com.iver.cit.gvsig.fmap.DriverException, VisitException {
644
645
                DissolvedFeature feature = null;
646
                Geometry jtsGeometry = null;
647
                IndividualGeometryDissolveVisitor visitor = null;
648
                while (toDissol.size() != 0) {
649
                        feature = (DissolvedFeature) toDissol.pop();
650
                        // flags this idx (to not to process in future)
651
                        dissolvedGeometries.set(feature.getIndex());
652
                        if (visitor == null) {
653
                                visitor = new IndividualGeometryDissolveVisitor(feature,
654
                                                dissolvedGeometries, toDissol,
655
                                                numericField_sumarizeFunction);
656
                                visitor.setDissolveField(this.dissolveField);
657
                        } else {
658
                                visitor.setProcessedFeature(feature);
659
                        }
660
                        Rectangle2D bounds = feature.getGeometry().getBounds2D();
661
                        double xmin = bounds.getMinX();
662
                        double ymin = bounds.getMinY();
663
                        double xmax = bounds.getMaxX();
664
                        double ymax = bounds.getMaxY();
665
                        double magnify = 15d;
666
                        Rectangle2D query = new Rectangle2D.Double(xmin - magnify, ymin
667
                                        - magnify, (xmax - xmin) + magnify, (ymax - ymin) + magnify);
668
669
                        strategy.process(visitor, query);
670
671
                        Geometry jtsGeo = visitor.getFeatureJtsGeo();
672
                        if (jtsGeometry == null) {
673
                                jtsGeometry = jtsGeo;
674
                        } else {
675
                                jtsGeometry = jtsGeometry.union(jtsGeo);
676
                        }
677
                }// while
678
                Value[] values = visitor.getSumarizedValues2();
679
                feature = new DissolvedFeature(null, values, -1);
680
                feature.setJtsGeometry(jtsGeometry);
681
                return feature;
682
        }
683
684
        public void stop(FLayer layer) {
685
                this.featureProcessor.finish();
686
        }
687
688
        public boolean start(FLayer layer) {
689
                if (layer instanceof AlphanumericData && layer instanceof VectorialData) {
690
                        try {
691
                                dissolvedLayer = (FLyrVect) layer;
692
                                recordset = ((AlphanumericData) layer).getRecordset();
693
                                featureProcessor.start();
694
                        } catch (com.iver.cit.gvsig.fmap.DriverException e) {
695
                                return false;
696
                        } catch (EditionException e) {
697
                                return false;
698
                        }
699
                        return true;
700
                }
701
                return false;
702
        }
703
704
        public void setStrategy(Strategy strategy) {
705
                this.strategy = strategy;
706
        }
707
708
        public String getProcessDescription() {
709
                return "Dissolving polygons of a layer";
710
        }
711
712
}