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

History | View | Annotate | Download (15.9 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 modify it under
7
 * the terms of the GNU General Public License as published by the Free Software
8
 * Foundation; either version 2 of the License, or (at your option) any later
9
 * version.
10
 *
11
 * This program is distributed in the hope that it will be useful, but WITHOUT
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14
 * details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with
17
 * this program; if not, write to the Free Software Foundation, Inc., 51
18
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
 *
20
 * For any additional information, do not hesitate to contact us at info AT
21
 * gvsig.com, or visit our website www.gvsig.com.
22
 */
23
/*
24

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

    
45
import java.util.ArrayList;
46
import java.util.List;
47

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

    
62
import com.vividsolutions.jts.geom.Geometry;
63
import java.util.Iterator;
64

    
65
/**
66
 * Dissolve operation
67
 *
68
 * @author <a href="mailto:nachobrodin@gmail.com">Nacho Brodin</a>
69
 */
70
public class DissolveOperationFast extends GeometryOperation {
71

    
72
    private static Logger logger = LoggerFactory.getLogger(DissolveOperationFast.class.getName());
73
    private EditableFeature lastEditFeature = null;
74
    private ArrayList<Element> featureList = null;
75
    private IDissolveRule rule = null;
76
    private Summary summary = null;
77

    
78
    class Element {
79

    
80
        public int id = -1;
81
        public Feature feat = null;
82
        public List<Element> overlapList = new ArrayList<Element>();
83
        public boolean insertedToJoin = false;
84
        public Geometry jtsGeom = null;
85
    }
86

    
87
    class NodeTree {
88

    
89
        public Element element = null;
90
        public int pos = 0;
91
        public NodeTree parent = null;
92

    
93
        public NodeTree(Element node, NodeTree parent) {
94
            this.element = node;
95
            this.parent = parent;
96
        }
97

    
98
        public Element getNext() {
99
            if (pos < element.overlapList.size()) {
100
                return element.overlapList.get(pos++);
101
            }
102
            return null;
103
        }
104
    }
105

    
106
    public DissolveOperationFast(IDissolveRule rule, AbstractSextanteGeoProcess p) {
107
        super(p);
108
        this.rule = rule;
109
        featureList = new ArrayList<Element>();
110
    }
111

    
112
    /*
113
     * (non-Javadoc)
114
     * @see org.gvsig.geoprocess.algorithm.base.core.GeometryOperation#invoke(org.gvsig.fmap.geom.Geometry, org.gvsig.fmap.dal.feature.Feature)
115
     */
116
    public EditableFeature invoke(org.gvsig.fmap.geom.Geometry g, Feature feature) {
117
        return null;
118
    }
119

    
120
    /*
121
     * (non-Javadoc)
122
     * @see org.gvsig.geoprocess.algorithm.base.core.GeometryOperation#invoke(org.gvsig.fmap.geom.Geometry, org.gvsig.fmap.dal.feature.EditableFeature)
123
     */
124
    public void invoke(org.gvsig.fmap.geom.Geometry g, EditableFeature feature) {
125
        if (g == null) {
126
            return;
127
        }
128
    }
129

    
130
    /*
131
     * (non-Javadoc)
132
     * @see org.gvsig.geoprocess.algorithm.base.core.IOperation#getResult()
133
     */
134
    public Object getResult() {
135
        return lastEditFeature;
136
    }
137

    
138
    /**
139
     * Computes a complete operation over the input FeatureStore. The result of
140
     * this operation is stored in the output FeatureStore.
141
     *
142
     * @param inFeatStore Input FeatureStore
143
     * @param outFeatStore Output FeatureStore
144
     * @param attrNames List of attributes to build the output feature store
145
     * @param selectedGeom If it is true only the selected geometries will be
146
     * processed
147
     * @throws DataException
148
     */
149
    @SuppressWarnings({"deprecation"})
150
    public void computesGeometryOperation(FeatureStore inFeatStore,
151
            FeatureStore outFeatStore,
152
            String[] attrNames,
153
            boolean selectedGeomInput,
154
            boolean selectedGeomOutput,
155
            boolean closeOutStore) throws DataException {
156
        this.inFeatureStore = inFeatStore;
157
        FeatureSet featuresSet = null;
158
        featuresSet = inFeatStore.getFeatureSet();
159

    
160
        setFeatureStore(outFeatStore, attrNames);
161
        Iterator it = null;
162

    
163
        if (selectedGeomInput) {
164
            FeatureSelection ds = inFeatStore.getFeatureSelection();
165
            it = ds.iterator();
166
            numberOfFeatures = (int) ds.getSelectedCount();
167
        } else {
168
            it = featuresSet.iterator();
169
            numberOfFeatures = (int) featuresSet.getSize();
170
        }
171

    
172
        if (status != null && process != null) {
173
            status.setRangeOfValues(0, numberOfFeatures);
174
            process.setProgress(0, numberOfFeatures);
175
        }
176

    
177
        //Crear lista de elementos
178
        int iCount = 0;
179
        while (it.hasNext() && !process.getTaskMonitor().isCanceled()) {
180
            Feature feat = (Feature) it.next();
181
            Element el = new Element();
182
            el.feat = feat.getCopy();
183
            el.id = iCount;
184
            featureList.add(el);
185
            if (status != null && process != null) {
186
                status.setCurValue(iCount);
187
                process.setProgress(iCount, numberOfFeatures);
188
            }
189
            iCount++;
190
        }
191
        //it.dispose();
192

    
193
        //Crear listas de solapes para cada feature
194
        iCount = 0;
195
        while (iCount < featureList.size() && !process.getTaskMonitor().isCanceled()) {
196
            Element elem1 = featureList.get(iCount);
197
            org.gvsig.fmap.geom.Geometry geom1 = elem1.feat.getDefaultGeometry();
198
            elem1.jtsGeom = GeometryUtil.geomToJTS(geom1);
199

    
200
            if (status != null) {
201
                status.setCurValue(iCount);
202
            }
203
            if (process != null) {
204
                process.setProgress(iCount, numberOfFeatures);
205
            }
206

    
207
            for (int i = iCount + 1; i < featureList.size(); i++) {
208
                Element elem2 = featureList.get(i);
209
                org.gvsig.fmap.geom.Geometry geom2 = elem2.feat.getDefaultGeometry();
210
                elem2.jtsGeom = GeometryUtil.geomToJTS(geom2);
211
                if (rule.verifyIfDissolve(elem1.jtsGeom, elem2.jtsGeom, elem1.feat, elem2.feat)) {
212
                    elem1.overlapList.add(elem2);
213
                    elem2.overlapList.add(elem1);
214
                }
215
            }
216
            iCount++;
217
        }
218

    
219
                //Se calculan las listas de geometrias a unir
220
        //Para cada feature se obtiene su lista de elementos que solapan y para
221
        //cada elemento que solapa se obtiene su lista. Finalmente todas se unen y
222
        //y se hace un insert de una feature nueva
223
        List<Geometry> listResult = new ArrayList<Geometry>();
224
        iCount = 0;
225
        int iFeat = 0;
226
        summary = new Summary(rule, outFeatStore.getDefaultFeatureType());
227
        while (iCount < featureList.size() && !process.getTaskMonitor().isCanceled()) {
228
            Element elem1 = featureList.get(iCount);
229
            summary.loadDefaultSummarizes(elem1.feat);
230
            if (status != null) {
231
                status.setCurValue(iCount);
232
            }
233
            if (process != null) {
234
                process.setProgress(iCount, numberOfFeatures);
235
            }
236

    
237
            if (!elem1.insertedToJoin) {
238
                buildListToJoin(elem1, iFeat);
239
                iFeat++;
240
            }
241

    
242
            /*if(!elem1.insertedToJoin) {
243
             elem1.insertedToJoin = true;
244
             listResult.clear();
245
             //org.gvsig.fmap.geom.Geometry dalGeom = elem1.feat.getDefaultGeometry();
246
             //Geometry jtsGeom = GeometryUtil.geomToJTS(dalGeom);
247
             listResult.add(elem1.jtsGeom);
248

249
             buildListToJoin(listResult, elem1.overlapList);
250
             Geometry newGeom = computesUnion(listResult, elem1);//GeometryUtil.geometryUnion(listResult, elem1.feat.getDefaultGeometry().getGeometryType().getType());
251
             try {
252
             addFeatureToOutput(newGeom, elem1.feat, iFeat);
253
             } catch (CreateGeometryException e) {
254
             logger.info("Error a?adiendo geometr?a", e);
255
             } catch (DataException e) {
256
             logger.info("Error a?adiendo geometr?a", e);
257
             }
258
             iFeat ++;
259
             }*/
260
            iCount++;
261
        }
262

    
263
        if (closeOutStore && persister != null) {
264
            persister.end();
265
        }
266
    }
267

    
268
    /**
269
     * Computes the union of the list of geometries
270
     *
271
     * @param listResult
272
     * @param elem1
273
     * @return
274
     */
275
    private Geometry computesUnion(List<Geometry> listResult, Element elem1) {
276
        int splitValue = 500;
277
        Geometry newGeom = null;
278
        if (listResult.size() > splitValue) {
279
            List<List<Geometry>> list = splitList(listResult, splitValue);
280
            List<Geometry> result = new ArrayList<Geometry>();
281
            for (int i = 0; i < list.size(); i++) {
282
                Geometry aux = GeometryUtil.geometryUnion(list.get(i), elem1.feat.getDefaultGeometry().getGeometryType().getType());
283
                result.add(aux);
284
            }
285
            for (int i = 0; i < result.size(); i++) {
286
                newGeom = GeometryUtil.geometryUnion(result, elem1.feat.getDefaultGeometry().getGeometryType().getType());
287
            }
288
        } else {
289
            newGeom = GeometryUtil.geometryUnion(listResult, elem1.feat.getDefaultGeometry().getGeometryType().getType());
290
        }
291
        return newGeom;
292
    }
293

    
294
    private Geometry computesUnion3(List<Geometry> listResult) {
295
        Geometry newGeom = null;
296
        int iCount = 0;
297
        int max = listResult.size();
298
        if (process != null) {
299
            process.setName("Generating union");
300
        }
301
        while (listResult.size() > 1) {
302
            List<Geometry> list = new ArrayList<Geometry>();
303
            if (status != null) {
304
                status.setCurValue(iCount);
305
            }
306
            if (process != null) {
307
                process.setProgress(iCount, max);
308
            }
309
            for (int i = 0; i < listResult.size(); i = i + 2) {
310
                if (i == (listResult.size() - 1)) {
311
                    list.add(listResult.get(i));
312
                } else {
313
                    newGeom = JTSFacade.union(listResult.get(i), listResult.get(i + 1));
314
                    list.add(newGeom);
315
                }
316
            }
317
            listResult = list;
318
        }
319
        return newGeom;
320
    }
321

    
322
    /**
323
     * Splits the array of geometries to compute its union because JTS cannot
324
     * support a lot of geometries
325
     *
326
     * @param list
327
     * @param n
328
     * @return
329
     */
330
    private List<List<Geometry>> splitList(List<Geometry> list, int n) {
331
        int elements = (int) (list.size() / n);
332
        List<List<Geometry>> l = new ArrayList<List<Geometry>>();
333
        for (int i = 0; i < elements; i++) {
334
            l.add(list.subList((i * n), (i * n) + n));
335
        }
336
        if (elements * n < list.size()) {
337
            l.add(list.subList((elements * n), list.size()));
338
        }
339
        return l;
340
    }
341

    
342
    /**
343
     * Adds a feature to the output
344
     *
345
     * @param newGeom
346
     * @param feat
347
     * @param newFeatID
348
     * @throws DataException
349
     * @throws CreateGeometryException
350
     */
351
    private void addFeatureToOutput(Geometry newGeom, Feature feat, int newFeatID) throws DataException, CreateGeometryException {
352
        EditableFeature result = persister.getOutputFeatureStore().createNewFeature();
353
        result.setDouble(0, newFeatID);
354
        result.set(1, feat.get(rule.getFieldName()));
355
        result.setGeometry("GEOMETRY", GeometryUtil.jtsToGeom(newGeom));
356
        summary.loadEditableFeature(result);
357
        lastEditFeature = persister.addFeature(result, result.getDefaultGeometry());
358
    }
359

    
360
    /**
361
     * Builds the union of all lists
362
     *
363
     * @param listResult
364
     * @param listToJoin
365
     */
366
    private void buildListToJoin(List<Geometry> listResult, List<Element> listToJoin) {
367
        for (int i = 0; i < listToJoin.size(); i++) {
368
            Element elem = listToJoin.get(i);
369
            if (!elem.insertedToJoin) {
370
                elem.insertedToJoin = true;
371
                buildListToJoin(listResult, elem.overlapList);
372
                summary.updateValues(elem.feat);
373
                                //org.gvsig.fmap.geom.Geometry dalGeom = elem.feat.getDefaultGeometry();
374
                //Geometry jtsGeom = GeometryUtil.geomToJTS(dalGeom);
375
                listResult.add(elem.jtsGeom);
376
            }
377
        }
378
    }
379

    
380
    /**
381
     * Builds the union of all lists
382
     *
383
     * @param listResult
384
     * @param listToJoin
385
     */
386
    private void buildListToJoin(Element elem, int iFeat) {
387
        Geometry newGeom = null;
388

    
389
        if (elem.overlapList.size() == 0) {
390
            if (!elem.insertedToJoin) {
391
                elem.insertedToJoin = true;
392
            }
393
            try {
394
                summary.updateValues(elem.feat);
395
                addFeatureToOutput(elem.jtsGeom, elem.feat, iFeat);
396
            } catch (CreateGeometryException e) {
397
                logger.info("Error a?adiendo geometr?a", e);
398
            } catch (DataException e) {
399
                logger.info("Error a?adiendo geometr?a", e);
400
            }
401
        } else {
402
            List<Geometry> listResult = new ArrayList<Geometry>();
403
            NodeTree subtree = new NodeTree(elem, null);
404
                        //Hacemos un recorrido en profundidad del ?rbol para a?adir
405
            //todos los elementos a la lista de geometrias a unir sin
406
            //repetir ninguna.
407
            while (subtree != null) {
408
                if (!subtree.element.insertedToJoin) {
409
                    listResult.add(subtree.element.jtsGeom);
410
                    summary.updateValues(subtree.element.feat);
411
                    subtree.element.insertedToJoin = true;
412
                }
413

    
414
                boolean back = false;
415

    
416
                Element l = subtree.getNext();
417
                if (l == null) {
418
                    back = true;
419
                }
420

    
421
                while (!back && l.insertedToJoin) {
422
                    l = subtree.getNext();
423
                    if (l == null) {
424
                        back = true;
425
                    }
426
                }
427

    
428
                if (back) {
429
                    subtree = subtree.parent;
430
                    continue;
431
                }
432
                subtree = new NodeTree(l, subtree);
433
            }
434
            newGeom = computesUnion3(listResult);
435

    
436
            try {
437
                addFeatureToOutput(newGeom, elem.feat, iFeat);
438
            } catch (DataException e) {
439
                logger.info("Imposible insertar en la tabla", e);
440
            } catch (CreateGeometryException e) {
441
                logger.info("Error a?adiendo geometr?a", e);
442
            }
443
        }
444

    
445
    }
446

    
447
}