Statistics
| Revision:

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

History | View | Annotate | Download (19 KB)

1
/*
2
 * Created on 12-may-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: FeatureDissolver.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.2  2006/06/02 18:21:28  azabala
55
 * *** empty log message ***
56
 *
57
 * Revision 1.1  2006/05/24 21:11:14  azabala
58
 * primera version en cvs despues de refactoring orientado a crear un framework extensible de geoprocessing
59
 *
60
 *
61
 */
62
package com.iver.cit.gvsig.geoprocess.impl.dissolve.fmap;
63

    
64
import java.awt.geom.Rectangle2D;
65
import java.io.IOException;
66
import java.util.ArrayList;
67
import java.util.Enumeration;
68
import java.util.Iterator;
69
import java.util.List;
70
import java.util.Map;
71
import java.util.Stack;
72

    
73
import org.cresques.cts.ICoordTrans;
74

    
75
import com.iver.cit.gvsig.fmap.DriverException;
76
import com.iver.cit.gvsig.fmap.core.IFeature;
77
import com.iver.cit.gvsig.fmap.core.IGeometry;
78
import com.iver.cit.gvsig.fmap.core.v02.FConverter;
79
import com.iver.cit.gvsig.fmap.drivers.DriverIOException;
80
import com.iver.cit.gvsig.fmap.edition.EditionException;
81
import com.iver.cit.gvsig.fmap.layers.FBitSet;
82
import com.iver.cit.gvsig.fmap.layers.FLayer;
83
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
84
import com.iver.cit.gvsig.fmap.layers.ReadableVectorial;
85
import com.iver.cit.gvsig.fmap.layers.SelectableDataSource;
86
import com.iver.cit.gvsig.fmap.layers.layerOperations.AlphanumericData;
87
import com.iver.cit.gvsig.fmap.layers.layerOperations.VectorialData;
88
import com.iver.cit.gvsig.fmap.operations.strategies.FeatureVisitor;
89
import com.iver.cit.gvsig.fmap.operations.strategies.Strategy;
90
import com.iver.cit.gvsig.fmap.operations.strategies.StrategyManager;
91
import com.iver.cit.gvsig.fmap.operations.strategies.VisitException;
92
import com.iver.cit.gvsig.geoprocess.core.fmap.FeatureProcessor;
93
import com.iver.cit.gvsig.geoprocess.core.fmap.GeoprocessException;
94
import com.iver.utiles.swing.threads.Cancellable;
95
import com.iver.utiles.swing.threads.CancellableMonitorable;
96
import com.vividsolutions.jts.geom.Geometry;
97
import com.vividsolutions.jts.geom.GeometryCollection;
98
import com.vividsolutions.jts.geom.GeometryFactory;
99

    
100
/**
101
 * <p>
102
 * Dissolve features in base of a given dissolve criteria.
103
 * </p>
104
 * By 'dissolving' we understand the union of the geometry of many features
105
 * 
106
 * @author azabala
107
 * 
108
 */
109
public class FeatureDissolver {
110

    
111
        public static final int ALPHANUMERIC_DISSOLVE = 0;
112

    
113
        public static final int SPATIAL_DISSOLVE = 1;
114

    
115
        private int dissolveType = ALPHANUMERIC_DISSOLVE;
116

    
117
        /**
118
         * Fetches attributes of disolved layer features
119
         */
120
        protected SelectableDataSource recordset;
121
        
122
        protected ICoordTrans ct;
123

    
124
        /**
125
         * Is used to do spatial querys (looking for adjacent polygons to visited
126
         * feature geometry
127
         */
128
        protected FLyrVect dissolvedLayer;
129

    
130
        /**
131
         * It marks all features that have already been dissolved (to avoid process
132
         * them in subsecuent steps)
133
         * 
134
         */
135
        protected FBitSet dissolvedGeometries;
136

    
137
        /**
138
         * Relates a numerical field name with its sumarization functions
139
         */
140
        protected Map numericField_sumarizeFunction;
141

    
142
        /**
143
         * Processes results of dissolve operations (save them in a file, or cache
144
         * them in memory, etc)
145
         */
146
        protected FeatureProcessor featureProcessor;
147

    
148
        /**
149
         * Index of the result
150
         */
151
        protected int fid = 0;
152

    
153
        /**
154
         * It decides if two features must be dissolved, and builds the feature
155
         * resulting of the dissolution
156
         */
157
        protected IDissolveCriteria dissolveCriteria;
158

    
159
        /**
160
         * 
161
         * @param processor
162
         * @param layer
163
         * @throws GeoprocessException
164
         */
165
        public FeatureDissolver(FeatureProcessor processor, FLyrVect layer,
166
                        Map numericField_sumFunction, IDissolveCriteria criteria, int dissolveType)
167
                        throws GeoprocessException {
168

    
169
                this.featureProcessor = processor;
170
                this.numericField_sumarizeFunction = numericField_sumFunction;
171
                this.dissolveCriteria = criteria;
172
                this.dissolveType = dissolveType;
173
                dissolvedGeometries = new FBitSet();
174

    
175
                if (layer instanceof AlphanumericData && layer instanceof VectorialData) {
176
                        try {
177
                                dissolvedLayer = (FLyrVect) layer;
178
                                recordset = ((AlphanumericData) layer).getRecordset();
179
                                ct = dissolvedLayer.getCoordTrans();
180
                                featureProcessor.start();
181
                        } catch (com.iver.cit.gvsig.fmap.DriverException e) {
182
                                throw new GeoprocessException(
183
                                                "Error al acceder al recordset de la capa "
184
                                                                + layer.getName(), e);
185
                        } catch (EditionException e) {
186
                                throw new GeoprocessException(
187
                                                "Error al preparar donde se van a escribir los resultados del dissolve de la capa "
188
                                                                + layer.getName(), e);
189
                        }
190
                } else {
191
                        throw new GeoprocessException(
192
                                        "La capa a dissolver debe ser VectorialData y AlphanumericData");
193
                }
194
        }
195

    
196
        public void setDissolveCriteria(IDissolveCriteria criteria) {
197
                this.dissolveCriteria = criteria;
198
        }
199

    
200
        public void setDissolvedAttributesInfo(Map numericField_sumFunction) {
201
                this.numericField_sumarizeFunction = numericField_sumFunction;
202
        }
203

    
204
        public int getNumProcessedGeometries() {
205
                return dissolvedGeometries.cardinality();
206
        }
207

    
208
        public void dissolve(CancellableMonitorable cancel) throws GeoprocessException {
209
                try {
210
                        ReadableVectorial va = dissolvedLayer.getSource();
211
                        va.start();
212
                        for (int i = 0; i < va.getShapeCount(); i++) {// for each geometry
213
//                                if (cancel != null) {
214
//                                        cancel.reportStep();
215
//                                }
216
                                if (verifyCancelation(cancel, va)) {
217
                                        this.featureProcessor.finish();
218
                                        return;
219
                                }
220
                                
221
                                
222
                                //Ver si podemos optimizar esto de forma que solo
223
                                //se procesasen los elementos no marcados en el bitset
224
                                //(bitset de acceso aleatorio)
225
                                
226
                                if (!dissolvedGeometries.get(i)) {
227
                                        System.out.println("dissolviendo "+i);
228
                                        // if we havent processed this element yet
229
                                        try {
230
                                                if(dissolveType == SPATIAL_DISSOLVE)
231
                                                        process( i, va, cancel);
232
                                                else if(dissolveType == ALPHANUMERIC_DISSOLVE)
233
                                                        processAlphanumeric(i, va, cancel);
234
                                        } catch (DriverException e) {
235
                                                throw new GeoprocessException(
236
                                                                "Error accediendo a datos durante dissolve", e);
237
                                        } catch (VisitException e) {
238
                                                throw new GeoprocessException(
239
                                                                "Error procesando datos durante dissolve", e);
240
                                        } catch (IOException e) {
241
                                                throw new GeoprocessException(
242
                                                                "Error de I/O durante dissolve", e);
243
                                        }
244
                                }// if
245
                        }// for
246
                        va.stop();
247
                        this.featureProcessor.finish();
248
                } catch (DriverIOException e) {
249
                        e.printStackTrace();
250
                }
251
        }
252

    
253
        /**
254
         * Verifies cancelation events, and return a boolean flag if processes must
255
         * be stopped for this cancelations events.
256
         * 
257
         * @param cancel
258
         * @param va
259
         * @param visitor
260
         * @return
261
         * @throws DriverIOException
262
         */
263
        protected boolean verifyCancelation(Cancellable cancel, ReadableVectorial va) {
264
                if (cancel != null) {
265
                        if (cancel.isCanceled()) {
266
                                try {
267
                                        va.stop();
268
                                } finally {
269
                                        return true;
270
                                }
271
                        }
272
                }
273
                return false;
274
        }
275

    
276
        class DissolveVisitor implements FeatureVisitor {
277
                
278
                IDissolveCriteria criteria;
279
                int index1;
280
                Stack stack;
281
                List geometries;
282
                ReadableVectorial va;
283
                FunctionSummarizer sumarizer;
284
                CancellableMonitorable cancel;
285

    
286
                DissolveVisitor(IDissolveCriteria criteria, int index1, Stack stack,
287
                                List geometries, ReadableVectorial va,
288
                                FunctionSummarizer sumarizer, CancellableMonitorable cancel) {
289
                        this.criteria = criteria;
290
                        this.index1 = index1;
291
                        this.stack = stack;
292
                        this.geometries = geometries;
293
                        this.va = va;
294
                        this.sumarizer = sumarizer;
295
                        this.cancel = cancel;
296
                }
297

    
298
                public void visit(IGeometry g, int index2) throws VisitException {
299
                        if(g == null)
300
                                return;
301
                        if (verifyCancelation(cancel, va)) {
302
                                // TODO Revisar si hay problemas por llamar a finish
303
                                // varias veces
304
                                featureProcessor.finish();
305
                                return;
306
                        }
307
                        
308
                        if(index1 == index2){
309
                                //we dont want dissolve a feature with itself
310
                                return;
311
                        }
312

    
313
                        if (dissolvedGeometries.get(index2)) {
314
                                // Esta geometria ya ha sido procesada
315
                                return;
316
                        }
317

    
318
                        if (criteria.verifyIfDissolve(index1, index2)) {
319
                                //Redise?ar esto (es para que valga tanto para dissolves
320
                                //espaciales como alfanum?ricos
321
                                if(stack != null)
322
                                        stack.push(new Integer(index2));
323
                                try {
324
                                        if(criteria instanceof ISpatialDissolveCriteria){
325
                                                //Para ver el criterio de disolucion ya se ha 
326
                                                //leido la geometria
327
                                                geometries.add(
328
                                                                ((ISpatialDissolveCriteria)criteria).
329
                                                                getSecondGeometry().toJTSGeometry());
330
                                        }else{
331
                                                IGeometry g2 = va.getShape(index2);
332
                                                if(ct != null)
333
                                                        g2.reProject(ct);
334
                                                geometries.add(g2.toJTSGeometry());
335
                                        }
336
                                        sumarizer.applySumarizeFunction(index2);
337
                                } catch (DriverIOException e) {
338
                                        throw new VisitException(
339
                                                        "Error durante lectura de geometria en dissolve", e);
340
                                } catch (com.hardcode.gdbms.engine.data.driver.DriverException e) {
341
                                        throw new VisitException(
342
                                                        "Error durante lectura de geometria en dissolve", e);
343
                                }
344
                                //Esto se debe hacer externamente
345
                                if(stack == null)
346
                                        dissolvedGeometries.set(index2);
347
                        }
348
                }// visit
349

    
350
                public String getProcessDescription() {
351
                        return "";
352
                }
353

    
354
                public void stop(FLayer layer) {
355
                }
356

    
357
                public boolean start(FLayer layer) {
358
                        return true;
359
                }
360
        }
361
        
362
        /**
363
         * @param index1
364
         * @param va
365
         * @param cancel
366
         * @throws DriverException
367
         * @throws VisitException
368
         * @throws IOException
369
         * @throws DriverIOException
370
         */
371
        public void processAlphanumeric(int index1,
372
                                                        ReadableVectorial va, 
373
                                                        CancellableMonitorable cancel)
374
                                                        throws DriverException, VisitException, IOException,
375
                                                        DriverIOException{ 
376
                
377
                dissolvedGeometries.set(index1);
378
                Strategy strategy = StrategyManager.getStrategy(dissolvedLayer);
379
                ArrayList geometries = new ArrayList();
380
                //we add the 'seed' feature geometry
381
                IGeometry g1 = va.getShape(index1);
382
                if(g1 == null)
383
                        return;
384
                if(ct != null)
385
                        g1.reProject(ct);
386
                geometries.add(g1.toJTSGeometry());
387
                if(dissolveCriteria instanceof ISpatialDissolveCriteria){
388
                        ((ISpatialDissolveCriteria)dissolveCriteria).setCoordTrans(ct);
389
                        ((ISpatialDissolveCriteria)dissolveCriteria).setFirstGeometry(g1);
390
                }
391
                FunctionSummarizer sumarizer = new FunctionSummarizer(
392
                                numericField_sumarizeFunction, recordset);
393
                DissolveVisitor visitor = new DissolveVisitor(dissolveCriteria, index1, null,
394
                                geometries, va, sumarizer, cancel);
395
                strategy.process(visitor);
396
                IGeometry newGeometry = FConverter.jts_to_igeometry(union2(geometries));
397
                List sumarizedValues = sumarizer.getValues();
398
                IFeature dissolvedFeature = null;
399
                if(sumarizedValues != null || sumarizedValues.size() != 0){
400
                        dissolvedFeature =  dissolveCriteria.
401
                                                        getFeatureBuilder().
402
                                                        createFeature(newGeometry, 
403
                                                                                sumarizedValues, 
404
                                                                                                fid, 
405
                                                                                                index1);
406
                }else{
407
                        dissolvedFeature = dissolveCriteria.
408
                                                                getFeatureBuilder().
409
                                                                createFeature(newGeometry,
410
                                                                                index1, 
411
                                                                                fid);
412
                }
413
                fid++;
414
                featureProcessor.processFeature(dissolvedFeature);
415
                dissolveCriteria.clear();
416
        }
417
        
418
        
419
        class SpatialDissolveVisitor implements FeatureVisitor {
420
                
421
                IDissolveCriteria criteria;
422
                Geometry geom1;
423
                StackEntry entry1;
424
                Stack stack;
425
                List geometries;
426
                ReadableVectorial va;
427
                FunctionSummarizer sumarizer;
428
                CancellableMonitorable cancel;
429

    
430
                SpatialDissolveVisitor(IDissolveCriteria criteria, Geometry geo1, StackEntry entry1, 
431
                                Stack stack,
432
                                List geometries, ReadableVectorial va,
433
                                FunctionSummarizer sumarizer, CancellableMonitorable cancel) {
434
                        this.criteria = criteria;
435
                        this.geom1 = geo1;
436
                        this.entry1 = entry1;
437
                        this.stack = stack;
438
                        this.geometries = geometries;
439
                        this.va = va;
440
                        this.sumarizer = sumarizer;
441
                        this.cancel = cancel;
442
                }
443
                
444
                void setSeed(StackEntry entry, Geometry jtsGeo){
445
                        this.entry1 = entry;
446
                        this.geom1 = jtsGeo;
447
                }
448
                
449
                
450

    
451
                public void visit(IGeometry g, int index2) throws VisitException {
452
                        if(g == null)
453
                                return;
454
                        if (verifyCancelation(cancel, va)) {
455
                                // TODO Revisar si hay problemas por llamar a finish
456
                                // varias veces
457
                                featureProcessor.finish();
458
                                return;
459
                        }
460
                        
461
                        if(entry1.index == index2){
462
                                //we dont want dissolve a feature with itself
463
                                return;
464
                        }
465

    
466
                        if (dissolvedGeometries.get(index2)) {
467
                                // Esta geometria ya ha sido procesada
468
                                return;
469
                        }
470
                        if(criteria instanceof ISpatialDissolveCriteria){
471
                                ((ISpatialDissolveCriteria)criteria).setSecondGeometry(g);
472
                        }
473
                        if (criteria.verifyIfDissolve(entry1.index, index2)) {
474
                                StackEntry entry2 = new StackEntry();
475
                                entry2.g = g;
476
                                entry2.index = index2;
477
                                stack.push(entry2);
478
                                System.out.println("Anado "+index2+ " al stack");
479
                                dumpStack(stack);
480
                                if(criteria instanceof ISpatialDissolveCriteria)
481
                                {
482
                                        ISpatialDissolveCriteria c = (ISpatialDissolveCriteria)criteria;
483
                                        geometries.add(c.getSecondJts());
484
                                }else
485
                                        geometries.add(g.toJTSGeometry());
486
                                try {
487
                                        sumarizer.applySumarizeFunction(index2);
488
                                } catch (com.hardcode.gdbms.engine.data.driver.DriverException e) {
489
                                        throw new VisitException("Error al aplicar la funcion de sumarizacion en dissolve", e);
490
                                }
491
                                dissolvedGeometries.set(index2);
492
                        }
493
                }// visit
494

    
495
                public String getProcessDescription() {
496
                        return "";
497
                }
498

    
499
                public void stop(FLayer layer) {
500
                }
501

    
502
                public boolean start(FLayer layer) {
503
                        return true;
504
                }
505
        }
506
        
507
        class StackEntry{
508
                public IGeometry g;
509
                public int index;
510
        }
511
        /**
512
         * Processes the given feature looking for features to dissolve with. The
513
         * criteria to decide if dissolve two features is given by
514
         * IDissolveCriteria.
515
         * 
516
         * @param criteria
517
         *            decides if dissolve two features
518
         * @param index1
519
         *            index of feature we are processing
520
         * @param va
521
         *            it reads geometry of features
522
         * @param cancel
523
         *            listen cancelations
524
         * @throws VisitException
525
         * @throws DriverException
526
         * @throws IOException
527
         * @throws DriverIOException
528
         */
529
        public void process(int index1,
530
                        ReadableVectorial va, 
531
                        CancellableMonitorable cancel)
532
                        throws DriverException, VisitException, IOException,
533
                        DriverIOException {
534
                
535
                if(dissolvedGeometries.get(index1))
536
                        return;
537
                Strategy strategy = StrategyManager.getStrategy(dissolvedLayer);        
538
                IGeometry g1 = va.getShape(index1);
539
                if(g1 == null)
540
                        return;
541
                if(ct != null)
542
                        g1.reProject(ct);
543
                StackEntry entry = new StackEntry();
544
                entry.g = g1;
545
                entry.index = index1;
546
                Stack stack = new Stack();//it saves FMap geometries
547
                stack.push(entry);
548
                ArrayList geometries = new ArrayList();
549
                
550
                Geometry jtsGeo = g1.toJTSGeometry();
551
                geometries.add(jtsGeo);//it saves jts geometries
552
                
553
                if(dissolveCriteria instanceof ISpatialDissolveCriteria){
554
                        ((ISpatialDissolveCriteria)dissolveCriteria).setCoordTrans(ct);
555
                        ((ISpatialDissolveCriteria)dissolveCriteria).setFirstGeometry(g1);
556
                }
557
                FunctionSummarizer sumarizer = new FunctionSummarizer(
558
                                numericField_sumarizeFunction, recordset);
559
                SpatialDissolveVisitor visitor = new SpatialDissolveVisitor(dissolveCriteria, 
560
                                                                                                                                                        jtsGeo, 
561
                                                                                                                                                        entry, 
562
                                                                                                                                                        stack,
563
                                                                                                                                                        geometries, 
564
                                                                                                                                                        va, 
565
                                                                                                                                                        sumarizer, 
566
                                                                                                                                                        cancel);
567
                
568
                while (stack.size() != 0) {
569
                        dumpStack(stack);
570
                        StackEntry sEntry = (StackEntry) stack.pop();
571
                        dissolvedGeometries.set(sEntry.index);
572
        
573
                        /*//TODO
574
                         * Revisar si no deberiamos hacer
575
                         * ct.getInverted().convert(rect);
576
                         * 
577
                         * */
578
                        Rectangle2D rect = sEntry.g.getBounds2D();
579
                        if(ct != null)
580
                                rect = ct.convert(rect);
581
                        double xmin = rect.getMinX();
582
                        double ymin = rect.getMinY();
583
                        double xmax = rect.getMaxX();
584
                        double ymax = rect.getMaxY();
585
                        double magnify = 15d;
586
                        Rectangle2D query = new Rectangle2D.Double(xmin - magnify, ymin
587
                                        - magnify, (xmax - xmin) + magnify, (ymax - ymin) + magnify);
588
                        Geometry jts = sEntry.g.toJTSGeometry();
589
                        visitor.setSeed(sEntry, jts);
590
                        strategy.process(visitor, query);
591
                }// while
592
                
593
                
594
                IGeometry newGeometry = FConverter.jts_to_igeometry(union2(geometries));
595
                List sumarizedValues = sumarizer.getValues();
596
                IFeature dissolvedFeature = null;
597
                if(sumarizedValues != null || sumarizedValues.size() != 0){
598
                        dissolvedFeature =  dissolveCriteria.
599
                                                                getFeatureBuilder().
600
                                                                createFeature(newGeometry, 
601
                                                                                        sumarizedValues, 
602
                                                                                                        fid, 
603
                                                                                                        index1);
604
                }else{
605
                        dissolvedFeature = dissolveCriteria.
606
                                                                getFeatureBuilder().
607
                                                                createFeature(newGeometry,
608
                                                                                index1, 
609
                                                                                fid);
610
                }
611
                fid++;
612
                featureProcessor.processFeature(dissolvedFeature);
613
                dissolveCriteria.clear();
614
        }
615

    
616
        private void dumpStack(Stack stack) {
617
                Enumeration e = stack.elements();
618
                System.out.println("#####Elementos por procesar");
619
                while(e.hasMoreElements()){
620
                        System.out.println("#######-     "+((StackEntry)e.nextElement()).index);
621
                }
622
        }
623

    
624
        /**
625
         * Returns the union of all geometries of the list
626
         * 
627
         * @param geometries
628
         * @return
629
         */
630
        protected Geometry union(List geometries) {        
631
                Geometry union = null;
632
                GeometryFactory fact = ((Geometry)geometries.
633
                                                                        get(0)).getFactory();
634
                Iterator geomIt = geometries.iterator();
635
                while(geomIt.hasNext()){
636
                        Geometry g = (Geometry) geomIt.next();
637
                        if(union == null)
638
                                union = g;
639
                        else{
640
                                Geometry[] geomArray = {union, g};
641
                                GeometryCollection gCol = 
642
                                        fact.
643
                                        createGeometryCollection(geomArray);
644
                                union = gCol.buffer(0d);
645
                        }        
646
                }
647
                return union;
648
        }
649
        
650
        protected Geometry union3(List geometries) {
651
                long t0 = System.currentTimeMillis();                
652
                                Geometry union = null;
653
                                Iterator geomIt = geometries.iterator();
654
                                while(geomIt.hasNext()){
655
                                        Geometry g = (Geometry) geomIt.next();
656
                                        if(union == null)
657
                                                union = g;
658
                                        else{
659
                                                union = union.union(g);
660
                                        }        
661
                                }
662
                long t1 = System.currentTimeMillis();
663
                System.out.println((t1-t0)+ " en procesar union 3");
664
                                return union;
665
                        }
666
        
667
        protected Geometry union2(List geometries){                
668
                        Geometry union = null;
669
                        Geometry[] geom = new Geometry[geometries.size()];
670
                        geometries.toArray(geom);
671
                        GeometryFactory fact = geom[0].getFactory();
672
                    Geometry geomColl = fact.createGeometryCollection(geom);
673
                    System.out.println(geomColl.toText());
674
                    union = geomColl.buffer(0);
675
                    System.out.println(union.toText());
676
                    return union;
677
                
678
        }
679
}