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 @ 335

History | View | Annotate | Download (11.1 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.lib.sextante.AbstractSextanteGeoProcess;
60
import org.gvsig.tools.dispose.DisposableIterator;
61
import org.slf4j.Logger;
62
import org.slf4j.LoggerFactory;
63

    
64
import com.vividsolutions.jts.geom.Geometry;
65
/**
66
 * Dissolve operation
67
 * @author <a href="mailto:nachobrodin@gmail.com">Nacho Brodin</a>
68
 */
69
public class DissolveOperationFast extends GeometryOperation {
70
        private static Logger                                  logger                      = LoggerFactory.getLogger(DissolveOperationFast.class.getName());
71
        private EditableFeature                  lastEditFeature  = null;
72
        private ArrayList<Element>               featureList      = null;       
73
        private IDissolveRule                    rule             = null;
74
        private Summary                          summary          = null; 
75
        
76
        class Element {
77
                public int                 id              = -1;
78
                public Feature             feat            = null;
79
                public List<Element>       overlapList     = new ArrayList<Element>();
80
                public boolean             insertedToJoin  = false;
81
                public Geometry            jtsGeom         = null;
82
        }
83
        
84
        public DissolveOperationFast(IDissolveRule rule, AbstractSextanteGeoProcess p) {
85
                super(p);
86
                this.rule = rule;
87
                featureList = new ArrayList<Element>();
88
        }
89

    
90
        /*
91
         * (non-Javadoc)
92
         * @see org.gvsig.geoprocess.algorithm.base.core.GeometryOperation#invoke(org.gvsig.fmap.geom.Geometry, org.gvsig.fmap.dal.feature.Feature)
93
         */
94
        public EditableFeature invoke(org.gvsig.fmap.geom.Geometry g, Feature feature) {
95
                return null;
96
        }
97
        
98
        /*
99
         * (non-Javadoc)
100
         * @see org.gvsig.geoprocess.algorithm.base.core.GeometryOperation#invoke(org.gvsig.fmap.geom.Geometry, org.gvsig.fmap.dal.feature.EditableFeature)
101
         */
102
        public void invoke(org.gvsig.fmap.geom.Geometry g, EditableFeature feature) {
103
                if(g == null)
104
                        return;
105
        }
106
        
107
        /*
108
         * (non-Javadoc)
109
         * @see org.gvsig.geoprocess.algorithm.base.core.IOperation#getResult()
110
         */
111
        public Object getResult() {
112
                return lastEditFeature;
113
        }
114
        
115
        /**
116
         * Computes a complete operation over the input FeatureStore. The result of this operation
117
         * is stored in the output FeatureStore. 
118
         * @param inFeatStore
119
         *        Input FeatureStore
120
         * @param outFeatStore
121
         *        Output FeatureStore
122
         * @param attrNames
123
         *        List of attributes to build the output feature store
124
         * @param selectedGeom
125
         *        If it is true only the selected geometries will be processed
126
         * @throws DataException
127
         */
128
        @SuppressWarnings({ "deprecation" })
129
        public void computesGeometryOperation(FeatureStore inFeatStore,
130
                                                                        FeatureStore outFeatStore,
131
                                                                        String[] attrNames,
132
                                                                        boolean selectedGeomInput,
133
                                                                        boolean selectedGeomOutput,
134
                                                                        boolean closeOutStore) throws DataException {
135
                this.inFeatureStore = inFeatStore;
136
                FeatureSet featuresSet = null;
137
                featuresSet = inFeatStore.getFeatureSet();
138
                
139
                setFeatureStore(outFeatStore, attrNames);
140
                DisposableIterator it = null;
141

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

    
230
                if(closeOutStore && persister != null)
231
                        persister.end();
232
        }
233
        
234
        /**
235
         * Computes the union of the list of geometries
236
         * @param listResult
237
         * @param elem1
238
         * @return
239
         */
240
        private Geometry computesUnion(List<Geometry> listResult, Element elem1) {
241
                int splitValue = 500;
242
                Geometry newGeom = null;
243
                if(listResult.size() > splitValue) {
244
                        List<List<Geometry>> list = splitList(listResult, splitValue);
245
                        List<Geometry> result = new ArrayList<Geometry>();
246
                        for (int i = 0; i < list.size(); i++) {
247
                                Geometry aux = GeometryUtil.geometryUnion(list.get(i), elem1.feat.getDefaultGeometry().getGeometryType().getType());
248
                                result.add(aux);
249
                        }
250
                        for (int i = 0; i < result.size(); i++) {
251
                                newGeom = GeometryUtil.geometryUnion(result, elem1.feat.getDefaultGeometry().getGeometryType().getType());
252
                        }
253
                } else {
254
                        newGeom = GeometryUtil.geometryUnion(listResult, elem1.feat.getDefaultGeometry().getGeometryType().getType());        
255
                }
256
                return newGeom;
257
        }
258
        
259
        /**
260
         * Splits the array of geometries to compute its union because JTS cannot support
261
         * a lot of geometries
262
         * @param list
263
         * @param n
264
         * @return
265
         */
266
        private List<List<Geometry>> splitList(List<Geometry> list, int n) {
267
                int elements = (int)(list.size() / n);
268
                List<List<Geometry>> l = new ArrayList<List<Geometry>>();
269
                for (int i = 0; i < elements; i++) {
270
                        l.add(list.subList((i * n), (i * n) + n));
271
                }
272
                if(elements * n < list.size()) {
273
                        l.add(list.subList((elements * n), list.size()));
274
                }
275
                return l;
276
        }
277
        
278
        /**
279
         * Adds a feature to the output
280
         * @param newGeom
281
         * @param feat
282
         * @param newFeatID
283
         * @throws DataException
284
         * @throws CreateGeometryException
285
         */
286
        private void addFeatureToOutput(Geometry newGeom, Feature feat, int newFeatID) throws DataException, CreateGeometryException {
287
                EditableFeature result = persister.getOutputFeatureStore().createNewFeature();
288
                result.setDouble(0, newFeatID);
289
                result.set(1, feat.get(rule.getIndexField()));
290
                result.setGeometry("GEOMETRY", GeometryUtil.jtsToGeom(newGeom));
291
                summary.loadEditableFeature(result);
292
                lastEditFeature = persister.addFeature(result, result.getDefaultGeometry());
293
        }
294
        
295
        /**
296
         * Builds the union of all lists 
297
         * @param listResult
298
         * @param listToJoin
299
         */
300
        private void buildListToJoin(List<Geometry> listResult, List<Element> listToJoin) {
301
                for (int i = 0; i < listToJoin.size(); i++) {
302
                        Element elem = listToJoin.get(i);
303
                        if(!elem.insertedToJoin) {
304
                                elem.insertedToJoin = true;
305
                                buildListToJoin(listResult, elem.overlapList);
306
                                summary.updateValues(elem.feat);
307
                                //org.gvsig.fmap.geom.Geometry dalGeom = elem.feat.getDefaultGeometry();
308
                                //Geometry jtsGeom = GeometryUtil.geomToJTS(dalGeom);
309
                                listResult.add(elem.jtsGeom);
310
                        }
311
                }
312
        }
313
        
314
}
315