Statistics
| Revision:

gvsig-geoprocess / org.gvsig.geoprocess / trunk / org.gvsig.geoprocess / org.gvsig.geoprocess.algorithm / org.gvsig.geoprocess.algorithm.fusespatially / src / main / java / org / gvsig / geoprocess / algorithm / fusespatially / FuseSpatiallyOperationFast.java @ 335

History | View | Annotate | Download (12 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.fusespatially;
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.FeatureAttributeDescriptor;
54
import org.gvsig.fmap.dal.feature.FeatureSelection;
55
import org.gvsig.fmap.dal.feature.FeatureSet;
56
import org.gvsig.fmap.dal.feature.FeatureStore;
57
import org.gvsig.fmap.geom.exception.CreateGeometryException;
58
import org.gvsig.geoprocess.algorithm.base.core.GeometryOperation;
59
import org.gvsig.geoprocess.algorithm.base.util.GeometryUtil;
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
 * Fuse spatially operation
68
 * @author <a href="mailto:nachobrodin@gmail.com">Nacho Brodin</a>
69
 */
70
public class FuseSpatiallyOperationFast extends GeometryOperation {
71
        private static Logger                                  logger                        = LoggerFactory.getLogger(FuseSpatiallyOperationFast.class.getName());
72
        private ArrayList<Element>               featureList        = null; 
73
        private String                           nameIdField        = null;
74
        private FeatureStore                     outFeatStoreTable  = 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 FuseSpatiallyOperationFast(AbstractSextanteGeoProcess process) {
85
                super(process);
86
                featureList = new ArrayList<Element>();
87
        }
88

    
89
        @Override
90
        public EditableFeature invoke(org.gvsig.fmap.geom.Geometry g,
91
                        Feature featureInput) {
92
                // TODO Auto-generated method stub
93
                return null;
94
        }
95

    
96
        @Override
97
        public void invoke(org.gvsig.fmap.geom.Geometry g,
98
                        EditableFeature featureInput) {
99
                // TODO Auto-generated method stub
100
                
101
        }
102
        
103
        /**
104
         * Computes a complete operation over the input FeatureStore. The result of this operation
105
         * is stored in the output FeatureStore. This method will call once for each geometry.
106
         * @param inFeatStore
107
         *        Input FeatureStore
108
         * @param outFeatStore
109
         *        Output FeatureStore
110
         * @param attrNames
111
         *        List of attributes to build the output feature store
112
         * @param selectedGeom
113
         *        If it is true only the selected geometries will be processed
114
         * @throws DataException
115
         */
116
        @SuppressWarnings("deprecation")
117
        public void computesGeometryOperation(FeatureStore inFeatStore,
118
                                                                        FeatureStore outFeatStore,
119
                                                                        FeatureStore outFeatStoreTable,
120
                                                                        String[] attrNames,
121
                                                                        String[] attrNamesTable,
122
                                                                        boolean selectedGeomInput,
123
                                                                        boolean selectedGeomOutput,
124
                                                                        String idField) throws DataException {
125
                this.outFeatStoreTable = outFeatStoreTable;
126
                this.nameIdField = idField;
127
                this.inFeatureStore = inFeatStore;
128
                this.selectedGeomInput = selectedGeomInput;
129
                this.selectedGeomOverlay = selectedGeomOutput;
130
                FeatureSet featuresSet = null;
131
                featuresSet = inFeatStore.getFeatureSet();
132
                
133
                setFeatureStore(outFeatStore, attrNames);
134
                DisposableIterator it = null;
135

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

    
227
                if(persister != null)
228
                        persister.end();
229
                
230
        }
231
        
232
        /**
233
         * Computes the union of the list of geometries
234
         * @param listResult
235
         * @param elem1
236
         * @return
237
         */
238
        private Geometry computesUnion(List<Geometry> listResult, Element elem1) {
239
                int splitValue = 500;
240
                Geometry newGeom = null;
241
                if(listResult.size() > splitValue) {
242
                        List<List<Geometry>> list = splitList(listResult, splitValue);
243
                        List<Geometry> result = new ArrayList<Geometry>();
244
                        for (int i = 0; i < list.size(); i++) {
245
                                Geometry aux = GeometryUtil.geometryUnion(list.get(i), elem1.feat.getDefaultGeometry().getGeometryType().getType());
246
                                result.add(aux);
247
                        }
248
                        for (int i = 0; i < result.size(); i++) {
249
                                newGeom = GeometryUtil.geometryUnion(result, elem1.feat.getDefaultGeometry().getGeometryType().getType());
250
                        }
251
                } else {
252
                        newGeom = GeometryUtil.geometryUnion(listResult, elem1.feat.getDefaultGeometry().getGeometryType().getType());        
253
                }
254
                return newGeom;
255
        }
256
        
257
        /**
258
         * Splits the array of geometries to compute its union because JTS cannot support
259
         * a lot of geometries
260
         * @param list
261
         * @param n
262
         * @return
263
         */
264
        private List<List<Geometry>> splitList(List<Geometry> list, int n) {
265
                int elements = (int)(list.size() / n);
266
                List<List<Geometry>> l = new ArrayList<List<Geometry>>();
267
                for (int i = 0; i < elements; i++) {
268
                        l.add(list.subList((i * n), (i * n) + n));
269
                }
270
                if(elements * n < list.size()) {
271
                        l.add(list.subList((elements * n), list.size()));
272
                }
273
                return l;
274
        }
275
        
276
        /**
277
         * Builds the union of all lists 
278
         * @param listResult
279
         * @param listToJoin
280
         */
281
        private void buildListToJoin(List<Geometry> listResult, List<Element> listToJoin, int reference) {
282
                for (int i = 0; i < listToJoin.size(); i++) {
283
                        Element elem = listToJoin.get(i);
284
                        if(!elem.insertedToJoin) {
285
                                elem.insertedToJoin = true;
286
                                buildListToJoin(listResult, elem.overlapList, reference);
287
                                try {
288
                                        insertInTable(outFeatStoreTable, elem.feat, reference);
289
                                } catch (DataException e) {
290
                                        logger.info("Imposible insertar en la tabla", e);
291
                                }
292
                                listResult.add(elem.jtsGeom);
293
                        }
294
                }
295
        }
296
        
297
        /**
298
         * Adds a feature to the output
299
         * @param newGeom
300
         * @param feat
301
         * @param newFeatID
302
         * @throws DataException
303
         * @throws CreateGeometryException
304
         */
305
        private void addFeatureToOutput(Geometry newGeom, 
306
                        Feature feat, 
307
                        int newFeatID) throws DataException, CreateGeometryException {
308
                //Si hay una tabla aparte esta capa solo lleva el id como referencia a la tabla de campos
309
                if(outFeatStoreTable != null) { 
310
                        lastEditFeature = persister.addFeature(newGeom, nameIdField, newFeatID);
311
                } else {
312
                        //Si no hay tabla se ponen todos los campos de la tabla de entrada
313
                        String[] fieldNames = persister.getFieldNamesWithoutGeom();
314
                        ArrayList<String> fields = new ArrayList<String>();
315
                        ArrayList<Object> values = new ArrayList<Object>();
316
                        fields.add(nameIdField);
317
                        values.add(newFeatID);
318
                        for (int j = 0; j < fieldNames.length; j++) {
319
                                Object obj = feat.get(fieldNames[j]);
320
                                if(obj != null && fieldNames[j].compareTo(nameIdField) != 0) {
321
                                        fields.add(fieldNames[j]);
322
                                        values.add(obj);
323
                                }
324
                        }
325
                        lastEditFeature = persister.addFeature(newGeom, fields, values);
326
                }
327
        }
328
        
329
        /**
330
         * Insert in the output table a new feature with the fields of the input feature. Moreover 
331
         * exists a field that is an identifier which is a reference to the fusion layer.
332
         * @param outFeatureStoreTable
333
         * @param f
334
         * @throws DataException
335
         */
336
        private void insertInTable(FeatureStore outFeatureStoreTable, Feature f, int reference) throws DataException {
337
                if(outFeatureStoreTable == null)
338
                        return;
339
                EditableFeature edFeat = outFeatureStoreTable.createNewFeature();
340
                edFeat.set(nameIdField, reference);
341
                FeatureAttributeDescriptor[] attrList = f.getType().getAttributeDescriptors();
342
                for (int j = 0; j < attrList.length; j++) {
343
                        if(attrList[j].getName().compareTo("GEOMETRY") != 0) {
344
                                edFeat.set(attrList[j].getName(), f.get(attrList[j].getName()));
345
                        }
346
                }
347
                outFeatureStoreTable.insert(edFeat);
348
        }
349
        
350
}
351