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 / FuseSpatiallyOperationFast2.java @ 347

History | View | Annotate | Download (13 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 FuseSpatiallyOperationFast2 extends GeometryOperation {
71
        private static Logger                                  logger                        = LoggerFactory.getLogger(FuseSpatiallyOperationFast2.class.getName());
72
        private ArrayList<Element>               featureList        = null; 
73
        private String                           nameIdField        = null;
74
        private FeatureStore                     outFeatStoreTable  = null;
75
        private NodeTree                         baseTree           = 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 FuseSpatiallyOperationFast2(AbstractSextanteGeoProcess process) {
103
                super(process);
104
                featureList = new ArrayList<Element>();
105
        }
106

    
107
        @Override
108
        public EditableFeature invoke(org.gvsig.fmap.geom.Geometry g,
109
                        Feature featureInput) {
110
                // TODO Auto-generated method stub
111
                return null;
112
        }
113

    
114
        @Override
115
        public void invoke(org.gvsig.fmap.geom.Geometry g,
116
                        EditableFeature featureInput) {
117
                // TODO Auto-generated method stub
118
                
119
        }
120
        
121
        /**
122
         * Computes a complete operation over the input FeatureStore. The result of this operation
123
         * is stored in the output FeatureStore. This method will call once for each geometry.
124
         * @param inFeatStore
125
         *        Input FeatureStore
126
         * @param outFeatStore
127
         *        Output FeatureStore
128
         * @param attrNames
129
         *        List of attributes to build the output feature store
130
         * @param selectedGeom
131
         *        If it is true only the selected geometries will be processed
132
         * @throws DataException
133
         */
134
        @SuppressWarnings("deprecation")
135
        public void computesGeometryOperation(FeatureStore inFeatStore,
136
                                                                        FeatureStore outFeatStore,
137
                                                                        FeatureStore outFeatStoreTable,
138
                                                                        String[] attrNames,
139
                                                                        String[] attrNamesTable,
140
                                                                        boolean selectedGeomInput,
141
                                                                        boolean selectedGeomOutput,
142
                                                                        String idField) throws DataException {
143
                this.outFeatStoreTable = outFeatStoreTable;
144
                this.nameIdField = idField;
145
                this.inFeatureStore = inFeatStore;
146
                this.selectedGeomInput = selectedGeomInput;
147
                this.selectedGeomOverlay = selectedGeomOutput;
148
                FeatureSet featuresSet = null;
149
                featuresSet = inFeatStore.getFeatureSet();
150
                
151
                setFeatureStore(outFeatStore, attrNames);
152
                DisposableIterator it = null;
153

    
154
                if(selectedGeomInput) {
155
            FeatureSelection ds = inFeatStore.getFeatureSelection();
156
            it = ds.iterator();
157
            numberOfFeatures = (int) ds.getSelectedCount();
158
                } else {
159
                        it = featuresSet.iterator();
160
                        numberOfFeatures = (int)featuresSet.getSize();
161
                }
162
                
163
        if (status != null) 
164
            status.setRangeOfValues(0, numberOfFeatures);
165
        if(process != null) 
166
            process.setProgress(0, numberOfFeatures);
167
                
168
        //Crear lista de elementos
169
                int iCount = 0;
170
                while( it.hasNext() && !process.getTaskMonitor().isCanceled()) {
171
                        Feature feat = (Feature)it.next();
172
                        Element el = new Element();
173
                        el.feat = feat;
174
                        el.id = iCount;
175
                        featureList.add(el);
176
            if (status != null && process != null) 
177
                status.setCurValue(iCount);
178
            if(process != null) 
179
                process.setProgress(iCount, numberOfFeatures);
180
                        iCount ++;
181
                }
182
                it.dispose();
183
                
184
                //Crear listas de solapes para cada feature
185
                iCount = 0;
186
                while (iCount < featureList.size() && !process.getTaskMonitor().isCanceled()) {
187
                        Element elem1 = featureList.get(iCount);
188
                        org.gvsig.fmap.geom.Geometry geom1 = elem1.feat.getDefaultGeometry();
189
                        if (status != null)  
190
                status.setCurValue(iCount);
191
            if(process != null)
192
                process.setProgress(iCount, numberOfFeatures);
193
            
194
                        for (int i = iCount + 1; i < featureList.size(); i++) {
195
                                Element elem2 = featureList.get(i);
196
                                org.gvsig.fmap.geom.Geometry geom2 = elem2.feat.getDefaultGeometry();
197
                                if(areBBoxesOverlaping(geom1, geom2)) {
198
                                        if(elem1.jtsGeom == null)
199
                                                elem1.jtsGeom = GeometryUtil.geomToJTS(geom1);
200
                                        elem2.jtsGeom = GeometryUtil.geomToJTS(geom2);
201
                                        if(elem1.jtsGeom.intersects(elem2.jtsGeom))        {
202
                                                elem1.overlapList.add(elem2);
203
                                                elem2.overlapList.add(elem1);
204
                                        }
205
                                }
206
                        }
207
                        iCount ++;
208
                }
209
                
210
                iCount = 0;
211
                int iFeat = 0;
212
                while (iCount < featureList.size() && !process.getTaskMonitor().isCanceled()) {
213
                        Element elem1 = featureList.get(iCount);
214
                        if (status != null) 
215
                status.setCurValue(iCount);
216
            if(process != null) 
217
                process.setProgress(iCount, numberOfFeatures);
218
      
219
                        if(!elem1.insertedToJoin) {
220
                                buildListToJoin(elem1, iFeat);
221
                                iFeat ++;
222
                        }
223
                        iCount ++;
224
                }
225

    
226
                if(persister != null)
227
                        persister.end();
228
                
229
        }
230
        
231
        private boolean areBBoxesOverlaping(org.gvsig.fmap.geom.Geometry g1, org.gvsig.fmap.geom.Geometry g2) {
232
                if(g1.getEnvelope().getMaximum(0) < g2.getEnvelope().getMinimum(0))
233
                        return false;
234
                if(g1.getEnvelope().getMinimum(0) > g2.getEnvelope().getMaximum(0))
235
                        return false;
236
                if(g1.getEnvelope().getMaximum(1) < g2.getEnvelope().getMinimum(1))
237
                        return false;
238
                if(g1.getEnvelope().getMinimum(1) > g2.getEnvelope().getMaximum(1))
239
                        return false;
240
                return true;
241
        }
242
        
243
        /**
244
         * Computes the union of the list of geometries
245
         * @param listResult
246
         * @param elem1
247
         * @return
248
         */
249
        private Geometry computesUnion(List<Geometry> listResult, Element elem1) {
250
                int splitValue = 500;
251
                Geometry newGeom = null;
252
                if(listResult.size() > splitValue) {
253
                        List<List<Geometry>> list = splitList(listResult, splitValue);
254
                        List<Geometry> result = new ArrayList<Geometry>();
255
                        for (int i = 0; i < list.size(); i++) {
256
                                Geometry aux = GeometryUtil.geometryUnion(list.get(i), elem1.feat.getDefaultGeometry().getGeometryType().getType());
257
                                result.add(aux);
258
                        }
259
                        for (int i = 0; i < result.size(); i++) {
260
                                newGeom = GeometryUtil.geometryUnion(result, elem1.feat.getDefaultGeometry().getGeometryType().getType());
261
                        }
262
                } else {
263
                        newGeom = GeometryUtil.geometryUnion(listResult, elem1.feat.getDefaultGeometry().getGeometryType().getType());        
264
                }
265
                return newGeom;
266
        }
267
        
268
        /**
269
         * Splits the array of geometries to compute its union because JTS cannot support
270
         * a lot of geometries
271
         * @param list
272
         * @param n
273
         * @return
274
         */
275
        private List<List<Geometry>> splitList(List<Geometry> list, int n) {
276
                int elements = (int)(list.size() / n);
277
                List<List<Geometry>> l = new ArrayList<List<Geometry>>();
278
                for (int i = 0; i < elements; i++) {
279
                        l.add(list.subList((i * n), (i * n) + n));
280
                }
281
                if(elements * n < list.size()) {
282
                        l.add(list.subList((elements * n), list.size()));
283
                }
284
                return l;
285
        }
286
        
287
        /**
288
         * Builds the union of all lists 
289
         * @param listResult
290
         * @param listToJoin
291
         */
292
        private void buildListToJoin(Element elem, int iFeat) {
293
                Geometry newGeom = null;
294
                
295
                if(elem.overlapList.size() == 0) {
296
                        if(!elem.insertedToJoin)
297
                                elem.insertedToJoin = true;
298
                        newGeom = elem.jtsGeom;
299
                } else {
300
                        List<Geometry> listResult = new ArrayList<Geometry>();
301
                        NodeTree subtree = new NodeTree(elem, null);
302
                        //Hacemos un recorrido en profundidad del ?rbol para a?adir
303
                        //todos los elementos a la lista de geometrias a unir sin
304
                        //repetir ninguna.
305
                        while (subtree != null) {
306
                                if(!subtree.element.insertedToJoin) {
307
                                        listResult.add(subtree.element.jtsGeom);
308
                                        subtree.element.insertedToJoin = true;
309
                                }
310
                                
311
                                boolean back = false;
312
                                
313
                                Element l = subtree.getNext();
314
                                if(l == null) 
315
                                        back = true;
316
                                
317
                                while(!back && l.insertedToJoin) {
318
                                        l = subtree.getNext();
319
                                        if(l == null) 
320
                                                back = true;
321
                                }
322
                                
323
                                if(back) {
324
                                        subtree = subtree.parent;
325
                                        continue;
326
                                }
327
                                
328
                                subtree = new NodeTree(l, subtree);
329
                        }
330
                        
331
                        newGeom = computesUnion(listResult, elem);
332
                }
333
                
334
                try {
335
                        insertInTable(outFeatStoreTable, elem.feat, iFeat);
336
                        addFeatureToOutput(newGeom, elem.feat, iFeat);
337
                } catch (DataException e) {
338
                        logger.info("Imposible insertar en la tabla", e);
339
                } catch (CreateGeometryException e) {
340
                        logger.info("Error a?adiendo geometr?a", e);
341
                }
342
                
343
        }
344
        
345
        /**
346
         * Adds a feature to the output
347
         * @param newGeom
348
         * @param feat
349
         * @param newFeatID
350
         * @throws DataException
351
         * @throws CreateGeometryException
352
         */
353
        private void addFeatureToOutput(Geometry newGeom, 
354
                        Feature feat, 
355
                        int newFeatID) throws DataException, CreateGeometryException {
356
                //Si hay una tabla aparte esta capa solo lleva el id como referencia a la tabla de campos
357
                if(outFeatStoreTable != null) { 
358
                        lastEditFeature = persister.addFeature(newGeom, nameIdField, newFeatID);
359
                } else {
360
                        //Si no hay tabla se ponen todos los campos de la tabla de entrada
361
                        String[] fieldNames = persister.getFieldNamesWithoutGeom();
362
                        ArrayList<String> fields = new ArrayList<String>();
363
                        ArrayList<Object> values = new ArrayList<Object>();
364
                        fields.add(nameIdField);
365
                        values.add(newFeatID);
366
                        for (int j = 0; j < fieldNames.length; j++) {
367
                                Object obj = feat.get(fieldNames[j]);
368
                                if(obj != null && fieldNames[j].compareTo(nameIdField) != 0) {
369
                                        fields.add(fieldNames[j]);
370
                                        values.add(obj);
371
                                }
372
                        }
373
                        lastEditFeature = persister.addFeature(newGeom, fields, values);
374
                }
375
        }
376
        
377
        /**
378
         * Insert in the output table a new feature with the fields of the input feature. Moreover 
379
         * exists a field that is an identifier which is a reference to the fusion layer.
380
         * @param outFeatureStoreTable
381
         * @param f
382
         * @throws DataException
383
         */
384
        private void insertInTable(FeatureStore outFeatureStoreTable, Feature f, int reference) throws DataException {
385
                if(outFeatureStoreTable == null)
386
                        return;
387
                EditableFeature edFeat = outFeatureStoreTable.createNewFeature();
388
                edFeat.set(nameIdField, reference);
389
                FeatureAttributeDescriptor[] attrList = f.getType().getAttributeDescriptors();
390
                for (int j = 0; j < attrList.length; j++) {
391
                        if(attrList[j].getName().compareTo("GEOMETRY") != 0) {
392
                                edFeat.set(attrList[j].getName(), f.get(attrList[j].getName()));
393
                        }
394
                }
395
                outFeatureStoreTable.insert(edFeat);
396
        }
397
        
398
}
399