svn-gvsig-desktop / tags / v1_1_Build_1015 / extensions / extGeoProcessing / src / com / iver / cit / gvsig / geoprocess / impl / dissolve / fmap / AdjacencyDissolveVisitor.java @ 13679
History | View | Annotate | Download (10.3 KB)
1 | 5918 | azabala | /*
|
---|---|---|---|
2 | * Created on 09-may-2006
|
||
3 | *
|
||
4 | * gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
|
||
5 | *
|
||
6 | * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
|
||
7 | *
|
||
8 | * This program is free software; you can redistribute it and/or
|
||
9 | * modify it under the terms of the GNU General Public License
|
||
10 | * as published by the Free Software Foundation; either version 2
|
||
11 | * of the License, or (at your option) any later version.
|
||
12 | *
|
||
13 | * This program is distributed in the hope that it will be useful,
|
||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
16 | * GNU General Public License for more details.
|
||
17 | *
|
||
18 | * You should have received a copy of the GNU General Public License
|
||
19 | * along with this program; if not, write to the Free Software
|
||
20 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA.
|
||
21 | *
|
||
22 | * For more information, contact:
|
||
23 | *
|
||
24 | * Generalitat Valenciana
|
||
25 | * Conselleria d'Infraestructures i Transport
|
||
26 | * Av. Blasco Ib??ez, 50
|
||
27 | * 46010 VALENCIA
|
||
28 | * SPAIN
|
||
29 | *
|
||
30 | * +34 963862235
|
||
31 | * gvsig@gva.es
|
||
32 | * www.gvsig.gva.es
|
||
33 | *
|
||
34 | * or
|
||
35 | *
|
||
36 | * IVER T.I. S.A
|
||
37 | * Salamanca 50
|
||
38 | * 46005 Valencia
|
||
39 | * Spain
|
||
40 | *
|
||
41 | * +34 963163400
|
||
42 | * dac@iver.es
|
||
43 | */
|
||
44 | /* CVS MESSAGES:
|
||
45 | *
|
||
46 | * $Id$
|
||
47 | * $Log$
|
||
48 | 12927 | azabala | * Revision 1.2.2.3 2007-08-06 19:08:48 azabala
|
49 | * bug solved (after dissolve all geometries next to a given one, solution was not set to null, so new solutions were added to previous solutions)
|
||
50 | *
|
||
51 | * Revision 1.2.2.2 2007/08/03 19:19:11 azabala
|
||
52 | 12916 | azabala | * solved bug (precision error of jts)
|
53 | *
|
||
54 | * Revision 1.2.2.1 2007/07/12 09:28:45 azabala
|
||
55 | 12556 | azabala | * optimizations in dissolution of buffered features (we dont use strategies to avoid reading of geometries already processed)
|
56 | *
|
||
57 | * Revision 1.2 2006/07/21 11:06:06 azabala
|
||
58 | 6497 | azabala | * fixed bug 604: empty dist field in buffered dissolved features
|
59 | *
|
||
60 | * Revision 1.1 2006/06/20 18:20:45 azabala
|
||
61 | 5918 | azabala | * first version in cvs
|
62 | *
|
||
63 | * Revision 1.1 2006/05/24 21:11:14 azabala
|
||
64 | * primera version en cvs despues de refactoring orientado a crear un framework extensible de geoprocessing
|
||
65 | *
|
||
66 | *
|
||
67 | */
|
||
68 | package com.iver.cit.gvsig.geoprocess.impl.dissolve.fmap; |
||
69 | |||
70 | 6497 | azabala | import java.awt.geom.Rectangle2D; |
71 | import java.util.List; |
||
72 | import java.util.Stack; |
||
73 | |||
74 | 12556 | azabala | import org.cresques.cts.ICoordTrans; |
75 | |||
76 | 5918 | azabala | import com.hardcode.gdbms.engine.data.driver.DriverException; |
77 | 6497 | azabala | import com.hardcode.gdbms.engine.values.DoubleValue; |
78 | import com.hardcode.gdbms.engine.values.Value; |
||
79 | import com.hardcode.gdbms.engine.values.ValueFactory; |
||
80 | 5918 | azabala | import com.iver.cit.gvsig.fmap.core.IGeometry; |
81 | 12556 | azabala | import com.iver.cit.gvsig.fmap.drivers.DriverAttributes; |
82 | import com.iver.cit.gvsig.fmap.drivers.DriverIOException; |
||
83 | import com.iver.cit.gvsig.fmap.layers.ReadableVectorial; |
||
84 | 6497 | azabala | import com.iver.cit.gvsig.fmap.operations.strategies.VisitException; |
85 | 5918 | azabala | import com.iver.cit.gvsig.geoprocess.core.fmap.FeatureProcessor; |
86 | 6497 | azabala | import com.iver.cit.gvsig.geoprocess.core.fmap.XTypes; |
87 | 12556 | azabala | import com.iver.utiles.swing.threads.CancellableMonitorable; |
88 | 5918 | azabala | import com.vividsolutions.jts.geom.Geometry; |
89 | 12556 | azabala | import com.vividsolutions.jts.geom.GeometryCollection; |
90 | import com.vividsolutions.jts.geom.GeometryFactory; |
||
91 | 12916 | azabala | import com.vividsolutions.jts.geom.PrecisionModel; |
92 | 12556 | azabala | import com.vividsolutions.jts.precision.EnhancedPrecisionOp; |
93 | 12916 | azabala | import com.vividsolutions.jts.precision.SimpleGeometryPrecisionReducer; |
94 | 5918 | azabala | |
95 | /**
|
||
96 | * <p>
|
||
97 | * This Visitor generates a dissolve of input layer based in adjacency criteria:
|
||
98 | * it dissolves two polygons, if and only if they are adjacent.
|
||
99 | * </p>
|
||
100 | * TODO: To dissolve buffers from radial rings create a DissolveVisitor
|
||
101 | * to compare FROM-TO Fields.
|
||
102 | *
|
||
103 | * @author azabala
|
||
104 | *
|
||
105 | */
|
||
106 | public class AdjacencyDissolveVisitor extends DissolveVisitor { |
||
107 | 6497 | azabala | |
108 | /**
|
||
109 | * Reference to the buffer distance of the visited buffered feature.
|
||
110 | */
|
||
111 | private DoubleValue currentBufferDistance = null; |
||
112 | |||
113 | 12556 | azabala | /**
|
114 | * FIXME REFACTOR THIS!!!!
|
||
115 | * This is a workaround to avoid the use of strategies
|
||
116 | * and allow the cancelation
|
||
117 | *
|
||
118 | * To optimize disolution of buffers, we need to avoid the reading
|
||
119 | * of geometries that also has been processed. Strategies cant do this
|
||
120 | *
|
||
121 | */
|
||
122 | CancellableMonitorable cancelMonitor = null;
|
||
123 | |||
124 | // FIXME Probe to optimize the union of the features
|
||
125 | //(buffer + dissolve when applies to almost all features of the layer
|
||
126 | //is very inefficient
|
||
127 | private Geometry geometry;
|
||
128 | |||
129 | |||
130 | 5918 | azabala | public AdjacencyDissolveVisitor(String dissolveField, |
131 | FeatureProcessor processor) { |
||
132 | super(dissolveField, processor);
|
||
133 | } |
||
134 | 6497 | azabala | |
135 | 12556 | azabala | //FIXME REFACTOR THIS!!!
|
136 | public void setCancelMonitor(CancellableMonitorable cancelMonitor){ |
||
137 | this.cancelMonitor = cancelMonitor;
|
||
138 | } |
||
139 | |||
140 | 5918 | azabala | protected boolean verifyIfDissolve(DissolvedFeature f1, DissolvedFeature f2) { |
141 | Geometry geo1 = f1.getJtsGeometry(); |
||
142 | Geometry geo2 = f2.getJtsGeometry(); |
||
143 | return geo1.intersects(geo2);
|
||
144 | } |
||
145 | |||
146 | /**
|
||
147 | * Creates a new IFeature with util info for dissolve geoprocess
|
||
148 | * (it ignore non numerical values, etc)
|
||
149 | *
|
||
150 | * @param g
|
||
151 | * @param index
|
||
152 | * @return
|
||
153 | * @throws DriverException
|
||
154 | */
|
||
155 | protected DissolvedFeature createFeature(IGeometry g, int index) |
||
156 | throws DriverException {
|
||
157 | 6497 | azabala | DissolvedFeature solution = new DissolvedFeature(g, null, index); |
158 | 5918 | azabala | return solution;
|
159 | } |
||
160 | 6497 | azabala | |
161 | /**
|
||
162 | * We overwrite this method because we are not interested in save sumarization
|
||
163 | * function values with dissolved features.
|
||
164 | * Instead, we want to add buffer distance like an attribute of them.
|
||
165 | */
|
||
166 | public void visit(IGeometry g, int index) throws VisitException { |
||
167 | if(g == null) |
||
168 | return;
|
||
169 | if(g.getGeometryType() != XTypes.POLYGON &&
|
||
170 | g.getGeometryType() != XTypes.MULTI) |
||
171 | return;
|
||
172 | if (!dissolvedGeometries.get(index)) {
|
||
173 | try {
|
||
174 | int fieldIndex = recordset.getFieldIndexByName("DIST"); |
||
175 | currentBufferDistance = (DoubleValue) recordset.getFieldValue(index, fieldIndex); |
||
176 | // if we havent dissolved this feature
|
||
177 | Stack toDissol = new Stack();// stack for adjacent features |
||
178 | DissolvedFeature feature = createFeature(g, index); |
||
179 | toDissol.push(feature); |
||
180 | 12556 | azabala | |
181 | // ArrayList geometries = new ArrayList();
|
||
182 | |||
183 | Value[] values = dissolveGeometries(toDissol/*, geometries*/); |
||
184 | |||
185 | // Geometry geometry = union(geometries);
|
||
186 | |||
187 | 6497 | azabala | Value[] valuesWithFID = new Value[values.length + 1]; |
188 | System.arraycopy(values, 0, valuesWithFID, 1, values.length); |
||
189 | valuesWithFID[0] = ValueFactory.createValue(fid);
|
||
190 | DissolvedFeature dissolved = new DissolvedFeature(null,valuesWithFID, fid/*index*/); |
||
191 | dissolved.setJtsGeometry(geometry); |
||
192 | this.featureProcessor.processFeature(dissolved);
|
||
193 | fid++; |
||
194 | resetFunctions(); |
||
195 | 12927 | azabala | geometry = null;
|
196 | 6497 | azabala | } catch (DriverException e) {
|
197 | throw new VisitException( |
||
198 | "Error al procesar las geometrias a fusionar durante dissolve");
|
||
199 | } catch (com.iver.cit.gvsig.fmap.DriverException e) {
|
||
200 | throw new VisitException( |
||
201 | "Error al procesar las geometrias a fusionar durante dissolve");
|
||
202 | } |
||
203 | }// if
|
||
204 | } |
||
205 | |||
206 | /**
|
||
207 | * We overwrite this method to ignore sumarization values and to
|
||
208 | * add buffer distance to the attributes of the result features.
|
||
209 | */
|
||
210 | 12556 | azabala | protected Value[] dissolveGeometries(Stack toDissol/*, |
211 | List geometries*/) throws com.iver.cit.gvsig.fmap.DriverException, |
||
212 | 6497 | azabala | VisitException { |
213 | 5918 | azabala | |
214 | 6497 | azabala | IndividualGeometryDissolveVisitor visitor = null;
|
215 | DissolvedFeature feature = null;
|
||
216 | while (toDissol.size() != 0) { |
||
217 | feature = (DissolvedFeature) toDissol.pop(); |
||
218 | 12556 | azabala | |
219 | |||
220 | 6497 | azabala | // flags this idx (to not to process in future)
|
221 | dissolvedGeometries.set(feature.getIndex()); |
||
222 | 12556 | azabala | |
223 | 6497 | azabala | if (visitor == null) { |
224 | visitor = new IndividualGeometryDissolveVisitor(feature,
|
||
225 | dissolvedGeometries, toDissol, |
||
226 | numericField_sumarizeFunction); |
||
227 | visitor.setDissolveField(this.dissolveField);
|
||
228 | } else {
|
||
229 | visitor.setProcessedFeature(feature); |
||
230 | } |
||
231 | 12556 | azabala | |
232 | 6497 | azabala | Rectangle2D bounds = feature.getGeometry().getBounds2D();
|
233 | double xmin = bounds.getMinX();
|
||
234 | double ymin = bounds.getMinY();
|
||
235 | double xmax = bounds.getMaxX();
|
||
236 | double ymax = bounds.getMaxY();
|
||
237 | double magnify = 15d; |
||
238 | Rectangle2D query = new Rectangle2D.Double(xmin - magnify, ymin |
||
239 | - magnify, (xmax - xmin) + magnify, (ymax - ymin) + magnify); |
||
240 | 12556 | azabala | |
241 | if (dissolvedLayer.getISpatialIndex() == null) { |
||
242 | strategy.process(visitor, query); |
||
243 | }else{
|
||
244 | process(visitor, query); |
||
245 | } |
||
246 | |||
247 | 6497 | azabala | //al final de toda la pila de llamadas recursivas,
|
248 | //geometries tendr? todas las geometrias que debemos dissolver
|
||
249 | 12556 | azabala | // geometries.add(feature.getJtsGeometry());
|
250 | |||
251 | if(geometry == null){ |
||
252 | geometry = feature.getJtsGeometry(); |
||
253 | }else{
|
||
254 | GeometryFactory factory = geometry.getFactory(); |
||
255 | Geometry[] geoms = new Geometry[]{geometry, feature.getJtsGeometry()}; |
||
256 | GeometryCollection collection = factory.createGeometryCollection(geoms); |
||
257 | 12916 | azabala | try{
|
258 | geometry = EnhancedPrecisionOp.buffer(collection, 0d);
|
||
259 | }catch(Throwable t){ |
||
260 | PrecisionModel precision = new PrecisionModel(1000); |
||
261 | SimpleGeometryPrecisionReducer reducer = new SimpleGeometryPrecisionReducer(precision);
|
||
262 | geometry = reducer.reduce(collection); |
||
263 | geometry = EnhancedPrecisionOp.buffer(geometry, 0d);
|
||
264 | } |
||
265 | 12556 | azabala | } |
266 | |||
267 | |||
268 | |||
269 | 6497 | azabala | }// while
|
270 | Value[] values = new Value[1]; |
||
271 | values[0] = currentBufferDistance;
|
||
272 | return values;
|
||
273 | } |
||
274 | |||
275 | 12556 | azabala | void process(IndividualGeometryDissolveVisitor visitor, Rectangle2D query){ |
276 | if (visitor.start(dissolvedLayer)) {
|
||
277 | ReadableVectorial va = dissolvedLayer.getSource(); |
||
278 | ICoordTrans ct = dissolvedLayer.getCoordTrans(); |
||
279 | List lstRecs = dissolvedLayer.getISpatialIndex().query(query);
|
||
280 | Integer idRec;
|
||
281 | int index;
|
||
282 | try {
|
||
283 | va.start(); |
||
284 | DriverAttributes attr = va.getDriverAttributes(); |
||
285 | boolean bMustClone = false; |
||
286 | if (attr != null) { |
||
287 | if (attr.isLoadedInMemory()) {
|
||
288 | bMustClone = attr.isLoadedInMemory(); |
||
289 | } |
||
290 | } |
||
291 | |||
292 | for (int i = 0; i < lstRecs.size(); i++) { |
||
293 | if(cancelMonitor != null){ |
||
294 | if(cancelMonitor.isCanceled())
|
||
295 | return;
|
||
296 | } |
||
297 | idRec = (Integer) lstRecs.get(i);
|
||
298 | index = idRec.intValue(); |
||
299 | if(getDissolvedGeometries().get(index))
|
||
300 | continue;
|
||
301 | |||
302 | IGeometry geom = va.getShape(index); |
||
303 | if (geom == null)// azabala |
||
304 | continue;
|
||
305 | if (ct != null) { |
||
306 | if (bMustClone)
|
||
307 | geom = geom.cloneGeometry(); |
||
308 | geom.reProject(ct); |
||
309 | } |
||
310 | if (geom.intersects(query))
|
||
311 | visitor.visit(geom, index); |
||
312 | }// for
|
||
313 | va.stop(); |
||
314 | } catch (DriverIOException e) {
|
||
315 | // TODO Auto-generated catch block
|
||
316 | e.printStackTrace(); |
||
317 | } catch (VisitException e) {
|
||
318 | // TODO Auto-generated catch block
|
||
319 | e.printStackTrace(); |
||
320 | } |
||
321 | }// if visitor.start
|
||
322 | |||
323 | visitor.stop(dissolvedLayer); |
||
324 | } |
||
325 | 6497 | azabala | |
326 | |||
327 | |||
328 | 12556 | azabala | |
329 | 6497 | azabala | |
330 | 5918 | azabala | } |