Statistics
| Revision:

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

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

    
88
import java.awt.geom.Rectangle2D;
89
import java.util.ArrayList;
90
import java.util.Iterator;
91
import java.util.List;
92
import java.util.Map;
93
import java.util.Stack;
94

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

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

    
131
        /**
132
         * Allows to get attributes of disolved layer features
133
         */
134
        protected SelectableDataSource recordset;
135

    
136
        /**
137
         * Is used to do spatial querys (looking for adjacent polygons to visited
138
         * feature geometry
139
         */
140
        protected FLyrVect dissolvedLayer;
141

    
142
        /**
143
         * Field which adjacent features must have the same value to dissolve them
144
         */
145
        protected String dissolveField;
146

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

    
154
        /**
155
         * Relates a numerical field name with its sumarization functions
156
         */
157
        protected Map numericField_sumarizeFunction;
158

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

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

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

    
185
        public int getNumProcessedGeometries() {
186
                return dissolvedGeometries.cardinality();
187
        }
188

    
189
        public void setDissolvedAttributesInfo(Map numericField_sumFunction) {
190
                this.numericField_sumarizeFunction = numericField_sumFunction;
191
        }
192

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

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

    
273
        /**
274
         * Inner class to manage dissolve geoprocess. It mantains feature info
275
         * interesting for dissolve (int index, JTS Geometry, etc)
276
         * 
277
         * @author azabala
278
         * 
279
         */
280
        protected class DissolvedFeature extends DefaultFeature {
281
                int index;
282
                Geometry jtsGeometry;
283

    
284
                public DissolvedFeature(IGeometry geom, Value[] att, int index) {
285
                        super(geom, att);
286
                        this.index = index;
287
                }
288

    
289
                public int getIndex() {
290
                        return index;
291
                }
292

    
293
                public Geometry getJtsGeometry() {
294
                        return jtsGeometry;
295
                }
296

    
297
                public void setJtsGeometry(Geometry jtsGeometry) {
298
                        this.jtsGeometry = jtsGeometry;
299
                }
300

    
301
                public IGeometry getGeometry() {
302
                        IGeometry solution = super.getGeometry();
303
                        if (solution == null && jtsGeometry != null) {
304
                                solution = FConverter.jts_to_igeometry(jtsGeometry);
305
                        }
306
                        return solution;
307
                }
308

    
309
        }
310

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

    
354
//        // FIXME Mover esto a una utility class
355
//        protected Geometry fastUnion(Geometry g1, Geometry g2) {
356
//                Geometry[] geoms = new Geometry[2];
357
//                geoms[0] = g1;
358
//                geoms[1] = g2;
359
//                GeometryCollection gc = g1.getFactory().createGeometryCollection(geoms);
360
//                return gc.buffer(0d);
361
//        }
362

    
363
        protected boolean verifyIfDissolve(DissolvedFeature fet1,
364
                        DissolvedFeature fet2) {
365
                Geometry jtsGeo = fet1.getJtsGeometry();
366
                Geometry featureJtsGeo = fet2.getJtsGeometry();
367
                //FIXME Revisar si intersects considera dos arcos adjacentes
368
                //que no comparten nodo
369
                if (jtsGeo.intersects(featureJtsGeo)) {// They have at least
370
                        //a common point
371

    
372
                        // dissolveField is the last
373
                        int fieldIndex = 0;
374
                        if (numericField_sumarizeFunction != null)
375
                                fieldIndex = numericField_sumarizeFunction.keySet().size();
376
                        Value adjacentVal = fet1.getAttribute(fieldIndex);
377
                        Value val = fet2.getAttribute(fieldIndex);
378
                        if (adjacentVal.doEquals(val)) {
379
                                return true;
380
                        }// if val equals
381
                }// if touches
382
                return false;
383
        }
384

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

    
399
                /**
400
                 * It saves all features for we are looking for adjacent geometries.
401
                 * Dissolving is similar to network tracking algorithms: one feature is
402
                 * adjacent to two, two is adjacent to four, etc We will save features
403
                 * to process in this stack
404
                 */
405
                Stack featuresToDissolve;
406

    
407
                /**
408
                 * Field use to dissolve adjacent geometries with the same value for it
409
                 * 
410
                 * FIXME Change it for an evaluator of logical expresions
411
                 */
412
                String dissolveField;
413

    
414
                /**
415
                 * Maps for each numerical field its sumarization functions
416
                 */
417
                Map fields_sumarizeFunc;
418

    
419
                /**
420
                 * Feature for which we are looking for features to dissolve
421
                 */
422
                DissolvedFeature feature;
423

    
424
                /**
425
                 * jts geometry of feature
426
                 */
427
                private Geometry featureJtsGeo;
428

    
429
                /**
430
                 * Numeric values result of a sumarization operation
431
                 */
432
                private List sumarizedValues;
433

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

    
462
                }
463

    
464
                public String getProcessDescription() {
465
                        return "Dissolving a polygon with its adjacents";
466
                }
467

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

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

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

    
518
                                        // we actualize geometry by unioning
519
                                        featuresToDissolve.push(adjacentFeature);
520
                                        // group by attributes
521
                                        applySumarizeFunction(index);
522
                                }
523
                        } catch (DriverException e) {
524
                                throw new VisitException(
525
                                                "Error al cargar los pol?gonos adyacentes durante un dissolve");
526
                        }        
527
                }// visit
528

    
529
                public void stop(FLayer layer) {
530
                }
531

    
532
                public boolean start(FLayer layer) {
533
                        try {
534
                                recordset = ((AlphanumericData) layer).getRecordset();
535
                                this.applySumarizeFunction(feature.getIndex());
536

    
537
                        } catch (com.iver.cit.gvsig.fmap.DriverException e) {
538
                                return false;
539
                        } catch (DriverException e) {
540
                                return false;
541
                        }
542
                        return true;
543
                }
544

    
545
                public void setFields_sumarizeFunc(Map fields_sumarizeFunc) {
546
                        this.fields_sumarizeFunc = fields_sumarizeFunc;
547
                }
548

    
549
                public Map getFields_sumarizeFunc() {
550
                        return fields_sumarizeFunc;
551
                }
552

    
553
                public Geometry getFeatureJtsGeo() {
554
                        return featureJtsGeo;
555
                }
556

    
557
                public Value[] getSumarizedValues() {
558
                        Value[] solution = new Value[sumarizedValues.size()];
559
                        sumarizedValues.toArray(solution);
560
                        return solution;
561
                }
562

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

    
594
                public void setDissolveField(String dissolveField) {
595
                        this.dissolveField = dissolveField;
596

    
597
                }
598

    
599
                public void setProcessedFeature(DissolvedFeature feature2) {
600
                        this.feature = feature2;
601

    
602
                }
603
        }// IndividualDissolve
604
        
605
        
606

    
607
        protected Value[] dissolveGeometries(Stack toDissol,
608
                        List geometries) throws com.iver.cit.gvsig.fmap.DriverException,
609
                        VisitException {
610

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

    
634
                        strategy.process(visitor, query);
635
                        //al final de toda la pila de llamadas recursivas, 
636
                        //geometries tendr? todas las geometrias que debemos dissolver
637
                        geometries.add(feature.getJtsGeometry());
638
                }// while
639
                Value[] values = visitor.getSumarizedValues2();
640
                return values;
641
        }
642

    
643
        protected DissolvedFeature dissolve(Stack toDissol)
644
                        throws com.iver.cit.gvsig.fmap.DriverException, VisitException {
645

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

    
670
                        strategy.process(visitor, query);
671

    
672
                        Geometry jtsGeo = visitor.getFeatureJtsGeo();
673
                        if (jtsGeometry == null) {
674
                                jtsGeometry = jtsGeo;
675
                        } else {
676
                                jtsGeometry = jtsGeometry.union(jtsGeo);
677
                        }
678
                }// while
679
                Value[] values = visitor.getSumarizedValues2();
680
                feature = new DissolvedFeature(null, values, -1);
681
                feature.setJtsGeometry(jtsGeometry);
682
                return feature;
683
        }
684

    
685
        public void stop(FLayer layer) {
686
                this.featureProcessor.finish();
687
        }
688

    
689
        public boolean start(FLayer layer) {
690
                if (layer instanceof AlphanumericData && layer instanceof VectorialData) {
691
                        try {
692
                                dissolvedLayer = (FLyrVect) layer;
693
                                recordset = ((AlphanumericData) layer).getRecordset();
694
                                featureProcessor.start();
695
                        } catch (com.iver.cit.gvsig.fmap.DriverException e) {
696
                                return false;
697
                        } catch (EditionException e) {
698
                                return false;
699
                        }
700
                        return true;
701
                }
702
                return false;
703
        }
704

    
705
        public void setStrategy(Strategy strategy) {
706
                this.strategy = strategy;
707
        }
708

    
709
        public String getProcessDescription() {
710
                return "Dissolving polygons of a layer";
711
        }
712

    
713
}