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 | 300 | nbrodin | /**
|
---|---|---|---|
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 | 335 | nbrodin | boolean selectedGeomInput,
|
123 | boolean selectedGeomOutput,
|
||
124 | 300 | nbrodin | String idField) throws DataException { |
125 | this.outFeatStoreTable = outFeatStoreTable;
|
||
126 | this.nameIdField = idField;
|
||
127 | this.inFeatureStore = inFeatStore;
|
||
128 | 335 | nbrodin | this.selectedGeomInput = selectedGeomInput;
|
129 | this.selectedGeomOverlay = selectedGeomOutput;
|
||
130 | 300 | nbrodin | FeatureSet featuresSet = null;
|
131 | featuresSet = inFeatStore.getFeatureSet(); |
||
132 | |||
133 | setFeatureStore(outFeatStore, attrNames); |
||
134 | DisposableIterator it = null;
|
||
135 | |||
136 | 335 | nbrodin | if(selectedGeomInput) {
|
137 | 300 | nbrodin | 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 | 316 | nbrodin | while (iCount < featureList.size() && !process.getTaskMonitor().isCanceled()) {
|
169 | 300 | nbrodin | 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 | 316 | nbrodin | while (iCount < featureList.size() && !process.getTaskMonitor().isCanceled()) {
|
196 | 300 | nbrodin | 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 | } |