Statistics
| Revision:

gvsig-geoprocess / org.gvsig.geoprocess / trunk / org.gvsig.geoprocess / org.gvsig.geoprocess.algorithm / org.gvsig.geoprocess.algorithm.buffer / src / main / java / org / gvsig / geoprocess / algorithm / buffer / FuseOperation.java @ 741

History | View | Annotate | Download (13.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 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.buffer;
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.FeatureSet;
52
import org.gvsig.fmap.dal.feature.FeatureStore;
53
import org.gvsig.fmap.geom.exception.CreateGeometryException;
54
import org.gvsig.geoprocess.algorithm.base.core.GeometryOperation;
55
import org.gvsig.geoprocess.algorithm.base.util.GeometryUtil;
56
import org.gvsig.geoprocess.algorithm.base.util.JTSFacade;
57
import org.gvsig.geoprocess.lib.sextante.AbstractSextanteGeoProcess;
58
import org.slf4j.Logger;
59
import org.slf4j.LoggerFactory;
60

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

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

    
71
    private static Logger logger = LoggerFactory.getLogger(FuseOperation.class.getName());
72
    private List<Element> featureList = null;
73
    private String nameIdField = "FID";
74
    private int iFeat = 0;
75

    
76
    class Element {
77

    
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
        public void finalize() throws Throwable {
85
            super.finalize();
86
            overlapList.clear();
87
        }
88
    }
89

    
90
    class NodeTree {
91

    
92
        public Element element = null;
93
        public int pos = 0;
94
        public NodeTree parent = null;
95

    
96
        public NodeTree(Element node, NodeTree parent) {
97
            this.element = node;
98
            this.parent = parent;
99
        }
100

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

    
109
    public FuseOperation(AbstractSextanteGeoProcess process) {
110
        super(process);
111
        featureList = new ArrayList<Element>();
112
    }
113

    
114
    @Override
115
    public EditableFeature invoke(org.gvsig.fmap.geom.Geometry g,
116
            Feature featureInput) {
117
        // TODO Auto-generated method stub
118
        return null;
119
    }
120

    
121
    @Override
122
    public void invoke(org.gvsig.fmap.geom.Geometry g,
123
            EditableFeature featureInput) {
124
                // TODO Auto-generated method stub
125

    
126
    }
127

    
128
    /**
129
     * Computes a complete operation over the input FeatureStore. The result of
130
     * this operation is stored in the output FeatureStore. This method will
131
     * call once for each geometry.
132
     *
133
     * @param inFeatStore Input FeatureStore
134
     * @param outFeatStore Output FeatureStore
135
     * @throws DataException
136
     */
137
    @SuppressWarnings("deprecation")
138
    public void computesGeometryOperation(FeatureStore inFeatStore,
139
            FeatureStore outFeatStore,
140
            String[] attrNames,
141
            boolean first) throws DataException {
142
        if (featureList != null) {
143
            featureList.clear();
144
        }
145
        this.inFeatureStore = inFeatStore;
146
        FeatureSet featuresSet = inFeatStore.getFeatureSet();
147

    
148
        if (first) {
149
            setFeatureStore(outFeatStore, attrNames);
150
        }
151
        Iterator it = featuresSet.iterator();
152

    
153
        numberOfFeatures = (int) featuresSet.getSize();
154

    
155
        if (status != null) {
156
            status.setRangeOfValues(0, numberOfFeatures);
157
        }
158
        if (process != null) {
159
            process.setProgress(0, numberOfFeatures);
160
        }
161

    
162
        //Crear lista de elementos
163
        int iCount = 0;
164
        while (it.hasNext() && !process.getTaskMonitor().isCanceled()) {
165
            Feature feat = (Feature) it.next();
166
            Element el = new Element();
167
            el.feat = feat;
168
            el.id = iCount;
169
            featureList.add(el);
170
            if (status != null && process != null) {
171
                status.setCurValue(iCount);
172
            }
173
            if (process != null) {
174
                process.setProgress(iCount, numberOfFeatures);
175
            }
176
            iCount++;
177
        }
178
        //it.dispose();
179

    
180
        //Crear listas de solapes para cada feature
181
        iCount = 0;
182
        while (iCount < featureList.size() && !process.getTaskMonitor().isCanceled()) {
183
            Element elem1 = featureList.get(iCount);
184
            org.gvsig.fmap.geom.Geometry geom1 = elem1.feat.getDefaultGeometry();
185
            if (status != null) {
186
                status.setCurValue(iCount);
187
            }
188
            if (process != null) {
189
                process.setProgress(iCount, numberOfFeatures);
190
            }
191

    
192
            for (int i = iCount + 1; i < featureList.size(); i++) {
193
                Element elem2 = featureList.get(i);
194
                org.gvsig.fmap.geom.Geometry geom2 = elem2.feat.getDefaultGeometry();
195
                if (areBBoxesOverlaping(geom1, geom2)) {
196
                    if (elem1.jtsGeom == null) {
197
                        elem1.jtsGeom = GeometryUtil.geomToJTS(geom1);
198
                    }
199
                    elem2.jtsGeom = GeometryUtil.geomToJTS(geom2);
200
                    if (elem1.jtsGeom.intersects(elem2.jtsGeom)) {
201
                        elem1.overlapList.add(elem2);
202
                        elem2.overlapList.add(elem1);
203
                    }
204
                }
205
            }
206
            iCount++;
207
        }
208

    
209
        iCount = 0;
210

    
211
        while (iCount < featureList.size() && !process.getTaskMonitor().isCanceled()) {
212
            Element elem1 = featureList.get(iCount);
213
            if (status != null) {
214
                status.setCurValue(iCount);
215
            }
216
            if (process != null) {
217
                process.setProgress(iCount, numberOfFeatures);
218
            }
219

    
220
            if (!elem1.insertedToJoin) {
221
                buildListToJoin(elem1);
222
            }
223

    
224
            iCount++;
225
        }
226

    
227
    }
228

    
229
    public void end() {
230
        if (persister != null) {
231
            persister.end();
232
        }
233
    }
234

    
235
    private boolean areBBoxesOverlaping(org.gvsig.fmap.geom.Geometry g1, org.gvsig.fmap.geom.Geometry g2) {
236
        if (g1.getEnvelope().getMaximum(0) < g2.getEnvelope().getMinimum(0)) {
237
            return false;
238
        }
239
        if (g1.getEnvelope().getMinimum(0) > g2.getEnvelope().getMaximum(0)) {
240
            return false;
241
        }
242
        if (g1.getEnvelope().getMaximum(1) < g2.getEnvelope().getMinimum(1)) {
243
            return false;
244
        }
245
        if (g1.getEnvelope().getMinimum(1) > g2.getEnvelope().getMaximum(1)) {
246
            return false;
247
        }
248
        return true;
249
    }
250

    
251
    private Geometry computesUnion(List<Geometry> listResult) {
252
        Geometry newGeom = null;
253
        int iCount = 0;
254
        int max = listResult.size();
255
        if (process != null) {
256
            process.setName("Generating union");
257
        }
258
        while (listResult.size() > 1) {
259
            List<Geometry> list = new ArrayList<Geometry>();
260
            if (status != null) {
261
                status.setCurValue(iCount);
262
            }
263
            if (process != null) {
264
                process.setProgress(iCount, max);
265
            }
266
            for (int i = 0; i < listResult.size(); i = i + 2) {
267
                if (i == (listResult.size() - 1)) {
268
                    list.add(listResult.get(i));
269
                } else {
270
                    newGeom = JTSFacade.union(listResult.get(i), listResult.get(i + 1));
271
                    list.add(newGeom);
272
                }
273
            }
274
            listResult = list;
275
        }
276
        return newGeom;
277
    }
278

    
279
    /**
280
     * Builds the union of all lists
281
     *
282
     * @param listResult
283
     * @param listToJoin
284
     */
285
    private void buildListToJoin(Element elem) {
286
        Geometry newGeom = null;
287

    
288
        if (elem.overlapList.size() == 0) {
289
            if (!elem.insertedToJoin) {
290
                elem.insertedToJoin = true;
291
            }
292
            try {
293
                addFeatureToOutput(elem.feat.getDefaultGeometry(), elem.feat);
294
            } catch (DataException e) {
295
                logger.info("Imposible insertar en la tabla", e);
296
            } catch (CreateGeometryException e) {
297
                logger.info("Error a?adiendo geometr?a", e);
298
            }
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

    
318
                while (!back && l.insertedToJoin) {
319
                    l = subtree.getNext();
320
                    if (l == null) {
321
                        back = true;
322
                    }
323
                }
324

    
325
                if (back) {
326
                    subtree = subtree.parent;
327
                    continue;
328
                }
329
                subtree = new NodeTree(l, subtree);
330
            }
331
            newGeom = computesUnion(listResult);
332

    
333
            try {
334
                addFeatureToOutput(newGeom, elem.feat);
335
            } catch (DataException e) {
336
                logger.info("Imposible insertar en la tabla", e);
337
            } catch (CreateGeometryException e) {
338
                logger.info("Error a?adiendo geometr?a", e);
339
            }
340
        }
341

    
342
    }
343

    
344
    /**
345
     * Adds a feature to the output
346
     *
347
     * @param newGeom
348
     * @param feat
349
     * @param newFeatID
350
     * @throws DataException
351
     * @throws CreateGeometryException
352
     */
353
    private void addFeatureToOutput(org.gvsig.fmap.geom.Geometry newGeom,
354
            Feature feat) throws DataException, CreateGeometryException {
355
        String[] fieldNames = persister.getFieldNamesWithoutGeom();
356
        ArrayList<String> fields = new ArrayList<String>();
357
        ArrayList<Object> values = new ArrayList<Object>();
358
        fields.add(nameIdField);
359
        values.add(iFeat);
360
        for (int j = 0; j < fieldNames.length; j++) {
361
            Object obj = feat.get(fieldNames[j]);
362
            if (obj != null && fieldNames[j].compareTo(nameIdField) != 0) {
363
                fields.add(fieldNames[j]);
364
                values.add(obj);
365
            }
366
        }
367
        lastEditFeature = persister.addFeature(newGeom, fields, values);
368
        iFeat++;
369

    
370
    }
371

    
372
    /**
373
     * Adds a feature to the output
374
     *
375
     * @param newGeom
376
     * @param feat
377
     * @param newFeatID
378
     * @throws DataException
379
     * @throws CreateGeometryException
380
     */
381
    private void addFeatureToOutput(Geometry newGeom,
382
            Feature feat) throws DataException, CreateGeometryException {
383
        String[] fieldNames = persister.getFieldNamesWithoutGeom();
384
        ArrayList<String> fields = new ArrayList<String>();
385
        ArrayList<Object> values = new ArrayList<Object>();
386
        fields.add(nameIdField);
387
        values.add(iFeat);
388
        for (int j = 0; j < fieldNames.length; j++) {
389
            Object obj = feat.get(fieldNames[j]);
390
            if (obj != null && fieldNames[j].compareTo(nameIdField) != 0) {
391
                fields.add(fieldNames[j]);
392
                values.add(obj);
393
            }
394
        }
395
        lastEditFeature = persister.addFeature(newGeom, fields, values);
396
        iFeat++;
397
    }
398
}