Statistics
| Revision:

gvsig-geoprocess / org.gvsig.geoprocess / trunk / org.gvsig.geoprocess / org.gvsig.geoprocess.algorithm / org.gvsig.geoprocess.algorithm.dissolve / src / main / java / org / gvsig / geoprocess / algorithm / dissolve / DissolveOperationFast.java @ 353

History | View | Annotate | Download (14 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2012 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
/*
25

26
 * gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
27
 *
28
 * Copyright (C) 2010 Generalitat Valenciana.
29
 *
30
 * This program is free software; you can redistribute it and/or
31
 * modify it under the terms of the GNU General Public License
32
 * as published by the Free Software Foundation; either version 2
33
 * of the License, or (at your option) any later version.
34
 *
35
 * This program is distributed in the hope that it will be useful,
36
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38
 * GNU General Public License for more details.
39
 *
40
 * You should have received a copy of the GNU General Public License
41
 * along with this program; if not, write to the Free Software
42
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
43
 */
44

    
45
package org.gvsig.geoprocess.algorithm.dissolve;
46

    
47
import java.util.ArrayList;
48
import java.util.List;
49

    
50
import org.gvsig.fmap.dal.exception.DataException;
51
import org.gvsig.fmap.dal.feature.EditableFeature;
52
import org.gvsig.fmap.dal.feature.Feature;
53
import org.gvsig.fmap.dal.feature.FeatureSelection;
54
import org.gvsig.fmap.dal.feature.FeatureSet;
55
import org.gvsig.fmap.dal.feature.FeatureStore;
56
import org.gvsig.fmap.geom.exception.CreateGeometryException;
57
import org.gvsig.geoprocess.algorithm.base.core.GeometryOperation;
58
import org.gvsig.geoprocess.algorithm.base.util.GeometryUtil;
59
import org.gvsig.geoprocess.algorithm.base.util.JTSFacade;
60
import org.gvsig.geoprocess.lib.sextante.AbstractSextanteGeoProcess;
61
import org.gvsig.tools.dispose.DisposableIterator;
62
import org.slf4j.Logger;
63
import org.slf4j.LoggerFactory;
64

    
65
import com.vividsolutions.jts.geom.Geometry;
66
/**
67
 * Dissolve operation
68
 * @author <a href="mailto:nachobrodin@gmail.com">Nacho Brodin</a>
69
 */
70
public class DissolveOperationFast extends GeometryOperation {
71
        private static Logger                                  logger                      = LoggerFactory.getLogger(DissolveOperationFast.class.getName());
72
        private EditableFeature                  lastEditFeature  = null;
73
        private ArrayList<Element>               featureList      = null;       
74
        private IDissolveRule                    rule             = null;
75
        private Summary                          summary          = null; 
76
        
77
        class Element {
78
                public int                 id              = -1;
79
                public Feature             feat            = null;
80
                public List<Element>       overlapList     = new ArrayList<Element>();
81
                public boolean             insertedToJoin  = false;
82
                public Geometry            jtsGeom         = null;
83
        }
84
        
85
        class NodeTree {
86
                public Element       element     = null;
87
                public int           pos         = 0;
88
                public NodeTree       parent      = null;
89
                
90
                public NodeTree(Element node, NodeTree parent) {
91
                        this.element = node;
92
                        this.parent = parent;
93
                }
94
                
95
                public Element getNext() {
96
                        if(pos < element.overlapList.size())
97
                                return element.overlapList.get(pos++);
98
                        return null;
99
                }
100
        }
101
        
102
        public DissolveOperationFast(IDissolveRule rule, AbstractSextanteGeoProcess p) {
103
                super(p);
104
                this.rule = rule;
105
                featureList = new ArrayList<Element>();
106
        }
107

    
108
        /*
109
         * (non-Javadoc)
110
         * @see org.gvsig.geoprocess.algorithm.base.core.GeometryOperation#invoke(org.gvsig.fmap.geom.Geometry, org.gvsig.fmap.dal.feature.Feature)
111
         */
112
        public EditableFeature invoke(org.gvsig.fmap.geom.Geometry g, Feature feature) {
113
                return null;
114
        }
115
        
116
        /*
117
         * (non-Javadoc)
118
         * @see org.gvsig.geoprocess.algorithm.base.core.GeometryOperation#invoke(org.gvsig.fmap.geom.Geometry, org.gvsig.fmap.dal.feature.EditableFeature)
119
         */
120
        public void invoke(org.gvsig.fmap.geom.Geometry g, EditableFeature feature) {
121
                if(g == null)
122
                        return;
123
        }
124
        
125
        /*
126
         * (non-Javadoc)
127
         * @see org.gvsig.geoprocess.algorithm.base.core.IOperation#getResult()
128
         */
129
        public Object getResult() {
130
                return lastEditFeature;
131
        }
132
        
133
        /**
134
         * Computes a complete operation over the input FeatureStore. The result of this operation
135
         * is stored in the output FeatureStore. 
136
         * @param inFeatStore
137
         *        Input FeatureStore
138
         * @param outFeatStore
139
         *        Output FeatureStore
140
         * @param attrNames
141
         *        List of attributes to build the output feature store
142
         * @param selectedGeom
143
         *        If it is true only the selected geometries will be processed
144
         * @throws DataException
145
         */
146
        @SuppressWarnings({ "deprecation" })
147
        public void computesGeometryOperation(FeatureStore inFeatStore,
148
                                                                        FeatureStore outFeatStore,
149
                                                                        String[] attrNames,
150
                                                                        boolean selectedGeomInput,
151
                                                                        boolean selectedGeomOutput,
152
                                                                        boolean closeOutStore) throws DataException {
153
                this.inFeatureStore = inFeatStore;
154
                FeatureSet featuresSet = null;
155
                featuresSet = inFeatStore.getFeatureSet();
156
                
157
                setFeatureStore(outFeatStore, attrNames);
158
                DisposableIterator it = null;
159

    
160
                if(selectedGeomInput) {
161
            FeatureSelection ds = inFeatStore.getFeatureSelection();
162
            it = ds.iterator();
163
            numberOfFeatures = (int) ds.getSelectedCount();
164
                } else {
165
                        it = featuresSet.iterator();
166
                        numberOfFeatures = (int)featuresSet.getSize();
167
                }
168
                
169
        if (status != null && process != null) {
170
            status.setRangeOfValues(0, numberOfFeatures);
171
            process.setProgress(0, numberOfFeatures);
172
        }
173
                
174
        //Crear lista de elementos
175
                int iCount = 0;
176
                while( it.hasNext() && !process.getTaskMonitor().isCanceled()) {
177
                        Feature feat = (Feature)it.next();
178
                        Element el = new Element();
179
                        el.feat = feat;
180
                        el.id = iCount;
181
                        featureList.add(el);
182
            if (status != null && process != null) {
183
                status.setCurValue(iCount);
184
                process.setProgress(iCount, numberOfFeatures);
185
            }
186
                        iCount ++;
187
                }
188
                it.dispose();
189
                
190
                //Crear listas de solapes para cada feature
191
                iCount = 0;
192
                while (iCount < featureList.size() && !process.getTaskMonitor().isCanceled()) {
193
                        Element elem1 = featureList.get(iCount);
194
                        org.gvsig.fmap.geom.Geometry geom1 = elem1.feat.getDefaultGeometry();
195
                        elem1.jtsGeom = GeometryUtil.geomToJTS(geom1);
196
                        
197
                        if (status != null) 
198
                status.setCurValue(iCount);
199
            if(process != null) 
200
                process.setProgress(iCount, numberOfFeatures);
201
            
202
                        for (int i = iCount + 1; i < featureList.size(); i++) {
203
                                Element elem2 = featureList.get(i);
204
                                org.gvsig.fmap.geom.Geometry geom2 = elem2.feat.getDefaultGeometry();
205
                                elem2.jtsGeom = GeometryUtil.geomToJTS(geom2);
206
                                if(rule.verifyIfDissolve(elem1.jtsGeom, elem2.jtsGeom, elem1.feat, elem2.feat)) {
207
                                        elem1.overlapList.add(elem2);
208
                                        elem2.overlapList.add(elem1);
209
                                }
210
                        }
211
                        iCount ++;
212
                }
213
                
214
                //Se calculan las listas de geometrias a unir
215
                //Para cada feature se obtiene su lista de elementos que solapan y para 
216
                //cada elemento que solapa se obtiene su lista. Finalmente todas se unen y 
217
                //y se hace un insert de una feature nueva
218
                List<Geometry> listResult = new ArrayList<Geometry>();
219
                iCount = 0;
220
                int iFeat = 0;
221
                summary = new Summary(rule, outFeatStore.getDefaultFeatureType());
222
                while (iCount < featureList.size() && !process.getTaskMonitor().isCanceled()) {
223
                        Element elem1 = featureList.get(iCount);
224
                        summary.loadDefaultSummarizes(elem1.feat);
225
                        if (status != null) 
226
                status.setCurValue(iCount);
227
            if(process != null) 
228
                process.setProgress(iCount, numberOfFeatures);
229
            
230
            if(!elem1.insertedToJoin) {
231
                                buildListToJoin(elem1, iFeat);
232
                                iFeat ++;
233
                        }
234
            
235
                        /*if(!elem1.insertedToJoin) {
236
                                elem1.insertedToJoin = true;
237
                                listResult.clear();
238
                                //org.gvsig.fmap.geom.Geometry dalGeom = elem1.feat.getDefaultGeometry();
239
                                //Geometry jtsGeom = GeometryUtil.geomToJTS(dalGeom);
240
                                listResult.add(elem1.jtsGeom);
241
                                
242
                                buildListToJoin(listResult, elem1.overlapList);
243
                                Geometry newGeom = computesUnion(listResult, elem1);//GeometryUtil.geometryUnion(listResult, elem1.feat.getDefaultGeometry().getGeometryType().getType());
244
                                try {
245
                                        addFeatureToOutput(newGeom, elem1.feat, iFeat);
246
                                } catch (CreateGeometryException e) {
247
                                        logger.info("Error a?adiendo geometr?a", e);
248
                                } catch (DataException e) {
249
                                        logger.info("Error a?adiendo geometr?a", e);
250
                                }
251
                                iFeat ++;
252
                        }*/
253
                        iCount ++;
254
                }
255

    
256
                if(closeOutStore && persister != null)
257
                        persister.end();
258
        }
259
        
260
        /**
261
         * Computes the union of the list of geometries
262
         * @param listResult
263
         * @param elem1
264
         * @return
265
         */
266
        private Geometry computesUnion(List<Geometry> listResult, Element elem1) {
267
                int splitValue = 500;
268
                Geometry newGeom = null;
269
                if(listResult.size() > splitValue) {
270
                        List<List<Geometry>> list = splitList(listResult, splitValue);
271
                        List<Geometry> result = new ArrayList<Geometry>();
272
                        for (int i = 0; i < list.size(); i++) {
273
                                Geometry aux = GeometryUtil.geometryUnion(list.get(i), elem1.feat.getDefaultGeometry().getGeometryType().getType());
274
                                result.add(aux);
275
                        }
276
                        for (int i = 0; i < result.size(); i++) {
277
                                newGeom = GeometryUtil.geometryUnion(result, elem1.feat.getDefaultGeometry().getGeometryType().getType());
278
                        }
279
                } else {
280
                        newGeom = GeometryUtil.geometryUnion(listResult, elem1.feat.getDefaultGeometry().getGeometryType().getType());        
281
                }
282
                return newGeom;
283
        }
284
        
285
        private Geometry computesUnion3(List<Geometry> listResult) {
286
                Geometry newGeom = null;
287
                int iCount = 0;
288
                int max = listResult.size();
289
                if(process != null)
290
                        process.setName("Generating union");
291
                while(listResult.size() > 1) {
292
                        List<Geometry> list = new ArrayList<Geometry>();
293
                        if (status != null)  
294
                status.setCurValue(iCount);
295
            if(process != null)
296
                process.setProgress(iCount, max);
297
                        for (int i = 0; i < listResult.size(); i = i + 2) {
298
                                if(i == (listResult.size() - 1))
299
                                        list.add(listResult.get(i));
300
                                else {
301
                                        newGeom = JTSFacade.union(listResult.get(i), listResult.get(i + 1));
302
                                        list.add(newGeom);
303
                                }
304
                        }
305
                        listResult = list;
306
                }
307
                return newGeom;
308
        }
309
        
310
        /**
311
         * Splits the array of geometries to compute its union because JTS cannot support
312
         * a lot of geometries
313
         * @param list
314
         * @param n
315
         * @return
316
         */
317
        private List<List<Geometry>> splitList(List<Geometry> list, int n) {
318
                int elements = (int)(list.size() / n);
319
                List<List<Geometry>> l = new ArrayList<List<Geometry>>();
320
                for (int i = 0; i < elements; i++) {
321
                        l.add(list.subList((i * n), (i * n) + n));
322
                }
323
                if(elements * n < list.size()) {
324
                        l.add(list.subList((elements * n), list.size()));
325
                }
326
                return l;
327
        }
328
        
329
        /**
330
         * Adds a feature to the output
331
         * @param newGeom
332
         * @param feat
333
         * @param newFeatID
334
         * @throws DataException
335
         * @throws CreateGeometryException
336
         */
337
        private void addFeatureToOutput(Geometry newGeom, Feature feat, int newFeatID) throws DataException, CreateGeometryException {
338
                EditableFeature result = persister.getOutputFeatureStore().createNewFeature();
339
                result.setDouble(0, newFeatID);
340
                result.set(1, feat.get(rule.getIndexField()));
341
                result.setGeometry("GEOMETRY", GeometryUtil.jtsToGeom(newGeom));
342
                summary.loadEditableFeature(result);
343
                lastEditFeature = persister.addFeature(result, result.getDefaultGeometry());
344
        }
345
        
346
        /**
347
         * Builds the union of all lists 
348
         * @param listResult
349
         * @param listToJoin
350
         */
351
        private void buildListToJoin(List<Geometry> listResult, List<Element> listToJoin) {
352
                for (int i = 0; i < listToJoin.size(); i++) {
353
                        Element elem = listToJoin.get(i);
354
                        if(!elem.insertedToJoin) {
355
                                elem.insertedToJoin = true;
356
                                buildListToJoin(listResult, elem.overlapList);
357
                                summary.updateValues(elem.feat);
358
                                //org.gvsig.fmap.geom.Geometry dalGeom = elem.feat.getDefaultGeometry();
359
                                //Geometry jtsGeom = GeometryUtil.geomToJTS(dalGeom);
360
                                listResult.add(elem.jtsGeom);
361
                        }
362
                }
363
        }
364
        
365
        /**
366
         * Builds the union of all lists 
367
         * @param listResult
368
         * @param listToJoin
369
         */
370
        private void buildListToJoin(Element elem, int iFeat) {
371
                Geometry newGeom = null;
372
                
373
                if(elem.overlapList.size() == 0) {
374
                        if(!elem.insertedToJoin)
375
                                elem.insertedToJoin = true;
376
                        try {
377
                                addFeatureToOutput(elem.jtsGeom, elem.feat, iFeat);
378
                        } catch (CreateGeometryException e) {
379
                                logger.info("Error a?adiendo geometr?a", e);
380
                        } catch (DataException e) {
381
                                logger.info("Error a?adiendo geometr?a", e);
382
                        }
383
                } else {
384
                        List<Geometry> listResult = new ArrayList<Geometry>();
385
                        NodeTree subtree = new NodeTree(elem, null);
386
                        //Hacemos un recorrido en profundidad del ?rbol para a?adir
387
                        //todos los elementos a la lista de geometrias a unir sin
388
                        //repetir ninguna.
389
                        while (subtree != null) {
390
                                if(!subtree.element.insertedToJoin) {
391
                                        listResult.add(subtree.element.jtsGeom);
392
                                        summary.updateValues(subtree.element.feat);
393
                                        subtree.element.insertedToJoin = true;
394
                                }
395
                                
396
                                boolean back = false;
397
                                
398
                                Element l = subtree.getNext();
399
                                if(l == null) 
400
                                        back = true;
401
                                
402
                                while(!back && l.insertedToJoin) {
403
                                        l = subtree.getNext();
404
                                        if(l == null) 
405
                                                back = true;
406
                                }
407
                                
408
                                if(back) {
409
                                        subtree = subtree.parent;
410
                                        continue;
411
                                }
412
                                subtree = new NodeTree(l, subtree);
413
                        }
414
                        newGeom = computesUnion3(listResult);
415
                        
416
                        try {
417
                                addFeatureToOutput(newGeom, elem.feat, iFeat);
418
                        } catch (DataException e) {
419
                                logger.info("Imposible insertar en la tabla", e);
420
                        } catch (CreateGeometryException e) {
421
                                logger.info("Error a?adiendo geometr?a", e);
422
                        }
423
                }
424
                
425
        }
426
        
427
}
428