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

History | View | Annotate | Download (15.5 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.algorithm.base.util.JTSFacade;
61
import org.gvsig.geoprocess.lib.sextante.AbstractSextanteGeoProcess;
62
import org.slf4j.Logger;
63
import org.slf4j.LoggerFactory;
64

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

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

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

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

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