Statistics
| Revision:

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

History | View | Annotate | Download (18.7 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 5628 2006-06-02 18:21:28Z azabala $
47
 * $Log$
48
 * 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
 * primera version en cvs despues de refactoring orientado a crear un framework extensible de geoprocessing
53
 *
54
 *
55
 */
56
package com.iver.cit.gvsig.geoprocess.dissolve.fmap;
57

    
58
import java.awt.geom.Rectangle2D;
59
import java.io.IOException;
60
import java.util.ArrayList;
61
import java.util.Enumeration;
62
import java.util.Iterator;
63
import java.util.List;
64
import java.util.Map;
65
import java.util.Stack;
66

    
67
import org.cresques.cts.ICoordTrans;
68

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

    
94
/**
95
 * <p>
96
 * Dissolve features in base of a given dissolve criteria.
97
 * </p>
98
 * By 'dissolving' we understand the union of the geometry of many features
99
 * 
100
 * @author azabala
101
 * 
102
 */
103
public class FeatureDissolver {
104

    
105
        public static final int ALPHANUMERIC_DISSOLVE = 0;
106

    
107
        public static final int SPATIAL_DISSOLVE = 1;
108

    
109
        private int dissolveType = ALPHANUMERIC_DISSOLVE;
110

    
111
        /**
112
         * Fetches attributes of disolved layer features
113
         */
114
        protected SelectableDataSource recordset;
115
        
116
        protected ICoordTrans ct;
117

    
118
        /**
119
         * Is used to do spatial querys (looking for adjacent polygons to visited
120
         * feature geometry
121
         */
122
        protected FLyrVect dissolvedLayer;
123

    
124
        /**
125
         * It marks all features that have already been dissolved (to avoid process
126
         * them in subsecuent steps)
127
         * 
128
         */
129
        protected FBitSet dissolvedGeometries;
130

    
131
        /**
132
         * Relates a numerical field name with its sumarization functions
133
         */
134
        protected Map numericField_sumarizeFunction;
135

    
136
        /**
137
         * Processes results of dissolve operations (save them in a file, or cache
138
         * them in memory, etc)
139
         */
140
        protected FeatureProcessor featureProcessor;
141

    
142
        /**
143
         * Index of the result
144
         */
145
        protected int fid = 0;
146

    
147
        /**
148
         * It decides if two features must be dissolved, and builds the feature
149
         * resulting of the dissolution
150
         */
151
        protected IDissolveCriteria dissolveCriteria;
152

    
153
        /**
154
         * 
155
         * @param processor
156
         * @param layer
157
         * @throws GeoprocessException
158
         */
159
        public FeatureDissolver(FeatureProcessor processor, FLyrVect layer,
160
                        Map numericField_sumFunction, IDissolveCriteria criteria, int dissolveType)
161
                        throws GeoprocessException {
162

    
163
                this.featureProcessor = processor;
164
                this.numericField_sumarizeFunction = numericField_sumFunction;
165
                this.dissolveCriteria = criteria;
166
                this.dissolveType = dissolveType;
167
                dissolvedGeometries = new FBitSet();
168

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

    
190
        public void setDissolveCriteria(IDissolveCriteria criteria) {
191
                this.dissolveCriteria = criteria;
192
        }
193

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

    
198
        public int getNumProcessedGeometries() {
199
                return dissolvedGeometries.cardinality();
200
        }
201

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

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

    
270
        class DissolveVisitor implements FeatureVisitor {
271
                
272
                IDissolveCriteria criteria;
273
                int index1;
274
                Stack stack;
275
                List geometries;
276
                ReadableVectorial va;
277
                FunctionSummarizer sumarizer;
278
                CancellableMonitorable cancel;
279

    
280
                DissolveVisitor(IDissolveCriteria criteria, int index1, Stack stack,
281
                                List geometries, ReadableVectorial va,
282
                                FunctionSummarizer sumarizer, CancellableMonitorable cancel) {
283
                        this.criteria = criteria;
284
                        this.index1 = index1;
285
                        this.stack = stack;
286
                        this.geometries = geometries;
287
                        this.va = va;
288
                        this.sumarizer = sumarizer;
289
                        this.cancel = cancel;
290
                }
291

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

    
307
                        if (dissolvedGeometries.get(index2)) {
308
                                // Esta geometria ya ha sido procesada
309
                                return;
310
                        }
311

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

    
344
                public String getProcessDescription() {
345
                        return "";
346
                }
347

    
348
                public void stop(FLayer layer) {
349
                }
350

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

    
424
                SpatialDissolveVisitor(IDissolveCriteria criteria, Geometry geo1, StackEntry entry1, 
425
                                Stack stack,
426
                                List geometries, ReadableVectorial va,
427
                                FunctionSummarizer sumarizer, CancellableMonitorable cancel) {
428
                        this.criteria = criteria;
429
                        this.geom1 = geo1;
430
                        this.entry1 = entry1;
431
                        this.stack = stack;
432
                        this.geometries = geometries;
433
                        this.va = va;
434
                        this.sumarizer = sumarizer;
435
                        this.cancel = cancel;
436
                }
437
                
438
                void setSeed(StackEntry entry, Geometry jtsGeo){
439
                        this.entry1 = entry;
440
                        this.geom1 = jtsGeo;
441
                }
442
                
443
                
444

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

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

    
489
                public String getProcessDescription() {
490
                        return "";
491
                }
492

    
493
                public void stop(FLayer layer) {
494
                }
495

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

    
610
        private void dumpStack(Stack stack) {
611
                Enumeration e = stack.elements();
612
                System.out.println("#####Elementos por procesar");
613
                while(e.hasMoreElements()){
614
                        System.out.println("#######-     "+((StackEntry)e.nextElement()).index);
615
                }
616
        }
617

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