svn-gvsig-desktop / trunk / extensions / extGeoprocessingExtensions / src / com / iver / cit / gvsig / geoprocess / impl / topology / lineclean / fmap / LineCleanVisitor.java @ 33358
History | View | Annotate | Download (27.8 KB)
1 |
/*
|
---|---|
2 |
* Created on 10-oct-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: LineCleanVisitor.java 13881 2007-09-19 16:22:04Z jaume $
|
47 |
* $Log$
|
48 |
* Revision 1.4 2007-09-19 16:09:14 jaume
|
49 |
* removed unnecessary imports
|
50 |
*
|
51 |
* Revision 1.3 2007/07/12 11:10:24 azabala
|
52 |
* bug 2617 solved (clean fails with multilinestring geometries)
|
53 |
*
|
54 |
* Revision 1.2 2007/03/06 16:48:14 caballero
|
55 |
* Exceptions
|
56 |
*
|
57 |
* Revision 1.1 2006/12/21 17:23:27 azabala
|
58 |
* *** empty log message ***
|
59 |
*
|
60 |
* Revision 1.1 2006/12/04 19:42:23 azabala
|
61 |
* *** empty log message ***
|
62 |
*
|
63 |
* Revision 1.7 2006/11/14 18:34:16 azabala
|
64 |
* *** empty log message ***
|
65 |
*
|
66 |
* Revision 1.6 2006/11/14 18:01:09 azabala
|
67 |
* removed system.out.println
|
68 |
*
|
69 |
* Revision 1.5 2006/11/13 20:41:08 azabala
|
70 |
* *** empty log message ***
|
71 |
*
|
72 |
* Revision 1.4 2006/10/19 16:06:48 azabala
|
73 |
* *** empty log message ***
|
74 |
*
|
75 |
* Revision 1.3 2006/10/17 18:27:24 azabala
|
76 |
* *** empty log message ***
|
77 |
*
|
78 |
* Revision 1.1 2006/10/10 18:50:17 azabala
|
79 |
* First version in CVS
|
80 |
*
|
81 |
*
|
82 |
*/
|
83 |
package com.iver.cit.gvsig.geoprocess.impl.topology.lineclean.fmap; |
84 |
|
85 |
import java.util.ArrayList; |
86 |
import java.util.Arrays; |
87 |
import java.util.Collections; |
88 |
import java.util.Comparator; |
89 |
import java.util.Iterator; |
90 |
|
91 |
import com.hardcode.gdbms.driver.exceptions.ReadDriverException; |
92 |
import com.hardcode.gdbms.engine.values.Value; |
93 |
import com.hardcode.gdbms.engine.values.ValueFactory; |
94 |
import com.iver.cit.gvsig.exceptions.visitors.ProcessVisitorException; |
95 |
import com.iver.cit.gvsig.exceptions.visitors.StartVisitorException; |
96 |
import com.iver.cit.gvsig.exceptions.visitors.StopWriterVisitorException; |
97 |
import com.iver.cit.gvsig.exceptions.visitors.VisitorException; |
98 |
import com.iver.cit.gvsig.fmap.core.IFeature; |
99 |
import com.iver.cit.gvsig.fmap.core.IGeometry; |
100 |
import com.iver.cit.gvsig.fmap.core.v02.FConverter; |
101 |
import com.iver.cit.gvsig.fmap.drivers.FieldDescription; |
102 |
import com.iver.cit.gvsig.fmap.drivers.ILayerDefinition; |
103 |
import com.iver.cit.gvsig.fmap.layers.FBitSet; |
104 |
import com.iver.cit.gvsig.fmap.layers.FLayer; |
105 |
import com.iver.cit.gvsig.fmap.layers.FLyrVect; |
106 |
import com.iver.cit.gvsig.fmap.layers.SelectableDataSource; |
107 |
import com.iver.cit.gvsig.fmap.layers.layerOperations.AlphanumericData; |
108 |
import com.iver.cit.gvsig.fmap.layers.layerOperations.VectorialData; |
109 |
import com.iver.cit.gvsig.fmap.operations.strategies.FeatureVisitor; |
110 |
import com.iver.cit.gvsig.fmap.operations.strategies.Strategy; |
111 |
import com.iver.cit.gvsig.fmap.operations.strategies.StrategyManager; |
112 |
import com.iver.cit.gvsig.geoprocess.core.fmap.FeatureFactory; |
113 |
import com.iver.cit.gvsig.geoprocess.core.fmap.FeaturePersisterProcessor2; |
114 |
import com.iver.cit.gvsig.geoprocess.core.fmap.FeatureProcessor; |
115 |
import com.iver.cit.gvsig.geoprocess.core.fmap.XTypes; |
116 |
import com.iver.cit.gvsig.util.SnappingCoordinateMap; |
117 |
import com.vividsolutions.jts.geom.Coordinate; |
118 |
import com.vividsolutions.jts.geom.Geometry; |
119 |
import com.vividsolutions.jts.geom.GeometryCollection; |
120 |
import com.vividsolutions.jts.geom.GeometryFactory; |
121 |
import com.vividsolutions.jts.geom.LineString; |
122 |
import com.vividsolutions.jts.geom.MultiLineString; |
123 |
import com.vividsolutions.jts.geom.MultiPoint; |
124 |
import com.vividsolutions.jts.geom.Point; |
125 |
import com.vividsolutions.jts.geomgraph.Node; |
126 |
import com.vividsolutions.jts.geomgraph.NodeFactory; |
127 |
import com.vividsolutions.jts.geomgraph.SnappingNodeMap; |
128 |
import com.vividsolutions.jts.linearref.LengthIndexedLine; |
129 |
import com.vividsolutions.jts.linearref.LinearLocation; |
130 |
import com.vividsolutions.jts.linearref.LocationIndexedLine; |
131 |
import com.vividsolutions.jts.operation.overlay.SnappingOverlayOperation; |
132 |
|
133 |
/**
|
134 |
* <p>
|
135 |
* This visitor operates with features whose geometries are lines. <br>
|
136 |
* For each visited feature, it looks for features in its proximity (spatial
|
137 |
* query). If these features hasnt been processed, it intersects the visited
|
138 |
* feature with all of the neighbour features. If intersection points are not
|
139 |
* nodes (end points), it ignores them. split the
|
140 |
* </p>
|
141 |
*
|
142 |
* @author azabala
|
143 |
*/
|
144 |
public class LineCleanVisitor implements FeatureVisitor { |
145 |
|
146 |
/**
|
147 |
* Recordset of the layer we are working with
|
148 |
*/
|
149 |
protected SelectableDataSource recordset;
|
150 |
|
151 |
/**
|
152 |
* Layer which we are cleaning
|
153 |
*/
|
154 |
protected FLyrVect layerToClean;
|
155 |
|
156 |
/**
|
157 |
* marks if we are going to clean only layer selection
|
158 |
*/
|
159 |
protected boolean cleanOnlySelection; |
160 |
|
161 |
/*
|
162 |
* TODO Meter esto en preferencias
|
163 |
*/
|
164 |
public final static double DEFAULT_SNAP = 0.1; |
165 |
|
166 |
protected double snapTolerance = DEFAULT_SNAP; |
167 |
|
168 |
/**
|
169 |
* It marks all processed features (to ignore them in future intersections)
|
170 |
*/
|
171 |
protected FBitSet processedFeatures;
|
172 |
|
173 |
/**
|
174 |
* Strategy of the layer we are working with.
|
175 |
*/
|
176 |
protected Strategy strategy;
|
177 |
|
178 |
/**
|
179 |
* Saves features resulting of cleaning process
|
180 |
*/
|
181 |
protected FeatureProcessor featureProcessor;
|
182 |
|
183 |
protected ILayerDefinition layerDefinition;
|
184 |
|
185 |
/**
|
186 |
* Saves pseudonodes found
|
187 |
*/
|
188 |
protected FeatureProcessor intersectProcessor;
|
189 |
|
190 |
protected ILayerDefinition intersectDefinition;
|
191 |
|
192 |
/**
|
193 |
* Counter of new features
|
194 |
*/
|
195 |
int fid = 0; |
196 |
|
197 |
/**
|
198 |
* It caches all written pseudonodes, to avoid writing the same pseudonode
|
199 |
* twice.
|
200 |
*
|
201 |
*/
|
202 |
SnappingCoordinateMap snapCoordMap; |
203 |
|
204 |
/**
|
205 |
* Constructor.
|
206 |
*
|
207 |
* @param processor
|
208 |
* @param intersectsProcessor
|
209 |
* @param cleanOnlySelection
|
210 |
* @param layerDefinition
|
211 |
* @param intersectDefinition
|
212 |
* @param firstLayer
|
213 |
* @param source
|
214 |
* @param snapCoordMap
|
215 |
*/
|
216 |
public LineCleanVisitor(FeatureProcessor processor,
|
217 |
FeaturePersisterProcessor2 intersectsProcessor, |
218 |
boolean cleanOnlySelection, ILayerDefinition layerDefinition,
|
219 |
ILayerDefinition intersectDefinition, FLyrVect firstLayer, |
220 |
SelectableDataSource source, SnappingCoordinateMap snapCoordMap) { |
221 |
this.featureProcessor = processor;
|
222 |
this.cleanOnlySelection = cleanOnlySelection;
|
223 |
processedFeatures = new FBitSet();
|
224 |
this.layerDefinition = layerDefinition;
|
225 |
this.intersectProcessor = intersectsProcessor;
|
226 |
this.intersectDefinition = intersectDefinition;
|
227 |
this.layerToClean = firstLayer;
|
228 |
this.recordset = source;
|
229 |
this.strategy = StrategyManager.getStrategy(layerToClean);
|
230 |
this.snapCoordMap = snapCoordMap;
|
231 |
} |
232 |
|
233 |
public void setLayerDefinition(ILayerDefinition layerDefinition) { |
234 |
this.layerDefinition = layerDefinition;
|
235 |
} |
236 |
|
237 |
private boolean checkForLineGeometry(Geometry geometry) { |
238 |
if (geometry instanceof LineString) |
239 |
return true; |
240 |
if (geometry instanceof MultiLineString) |
241 |
return true; |
242 |
if (geometry instanceof GeometryCollection) { |
243 |
GeometryCollection col = (GeometryCollection) geometry; |
244 |
for (int i = 0; i < col.getNumGeometries(); i++) { |
245 |
if (!checkForLineGeometry(col.getGeometryN(i)))
|
246 |
return false; |
247 |
} |
248 |
return true; |
249 |
} |
250 |
return false; |
251 |
} |
252 |
|
253 |
public void visit(IGeometry g, final int index) throws VisitorException, |
254 |
StopWriterVisitorException, ProcessVisitorException { |
255 |
// first, we check it isnt a null geometry and the geometry type
|
256 |
// is correct
|
257 |
if (g == null) |
258 |
return;
|
259 |
int geometryType = g.getGeometryType();
|
260 |
if (geometryType != XTypes.ARC && geometryType != XTypes.LINE
|
261 |
&& geometryType != XTypes.MULTI) |
262 |
return;
|
263 |
|
264 |
// after that, if we are going to clean only selected features, we
|
265 |
// check if this feature is selected
|
266 |
if (cleanOnlySelection) {
|
267 |
try {
|
268 |
if (!layerToClean.getRecordset().getSelection().get(index))
|
269 |
return;
|
270 |
} catch (ReadDriverException e) {
|
271 |
throw new ProcessVisitorException(recordset.getName(), e, |
272 |
"Error verificando seleccion en CLEAN");
|
273 |
} |
274 |
}// if cleanOnly
|
275 |
|
276 |
final Geometry jtsGeo = g.toJTSGeometry();
|
277 |
|
278 |
// we check if jts geometry is a line (or a line collection)
|
279 |
if (!checkForLineGeometry(jtsGeo))
|
280 |
return;
|
281 |
|
282 |
final SnappingNodeMap nodes = new SnappingNodeMap(new NodeFactory(), |
283 |
snapTolerance); |
284 |
/*
|
285 |
* Se nos plantea una problematica. Tenemos dos features: A y B, y he
|
286 |
* calculado la interseccion de A y B. Ahora, hay dos alternativas: -a)
|
287 |
* nunca mas calcular esta intersecci?n, pero almacenar su resultado en
|
288 |
* SnappingNodeMap. As?, en una segunda pasada, con todos los "Nodos"
|
289 |
* calculados, podr?amos fragmentar las lineas de forma individual.
|
290 |
* PROBLEMA: SnappingNodeMap ir?a creciendo, almacenando todos los nodos
|
291 |
* de una capa....(si se apoya sobre un IndexedShpDriver, no tendr?a por
|
292 |
* qu?)
|
293 |
*
|
294 |
*
|
295 |
* -b) Calcular la intersecci?n en los dos sentidos: A int B, y luego al
|
296 |
* procesar B, B int A. En este caso, pasamos ol?mpicamente del bitset
|
297 |
*
|
298 |
* De momento, por simplicidad, seguimos la alternativa -b)
|
299 |
*/
|
300 |
|
301 |
final boolean onlySelection = cleanOnlySelection; |
302 |
try {
|
303 |
strategy.process(new FeatureVisitor() {
|
304 |
|
305 |
SnappingOverlayOperation overlayOp = null;
|
306 |
|
307 |
/**
|
308 |
* From a given geometry, it returns its nodes (coordinate for a
|
309 |
* point, extreme coordinates for a line, first coordinate for a
|
310 |
* polygon)
|
311 |
*/
|
312 |
private Coordinate[] getNodesFor(Geometry processedGeometry) { |
313 |
Coordinate[] geomNodes = null; |
314 |
if (processedGeometry instanceof LineString) { |
315 |
LineString line = (LineString) processedGeometry; |
316 |
geomNodes = new Coordinate[2]; |
317 |
geomNodes[0] = line.getCoordinateN(0); |
318 |
geomNodes[1] = line
|
319 |
.getCoordinateN(line.getNumPoints() - 1);
|
320 |
} else if (processedGeometry instanceof MultiLineString) { |
321 |
MultiLineString lines = (MultiLineString) processedGeometry; |
322 |
int numLines = lines.getNumGeometries();
|
323 |
geomNodes = new Coordinate[2 * numLines]; |
324 |
int index = 0; |
325 |
for (int i = 0; i < numLines; i++) { |
326 |
LineString line = (LineString) lines |
327 |
.getGeometryN(i); |
328 |
geomNodes[index] = line.getCoordinateN(0);
|
329 |
index++; |
330 |
geomNodes[index] = line.getCoordinateN(line |
331 |
.getNumPoints() - 1);
|
332 |
index++; |
333 |
} |
334 |
} else if (processedGeometry instanceof GeometryCollection) { |
335 |
GeometryCollection col = (GeometryCollection) processedGeometry; |
336 |
ArrayList coordinates = new ArrayList(); |
337 |
for (int i = 0; i < col.getNumGeometries(); i++) { |
338 |
Geometry geom = col.getGeometryN(i); |
339 |
Coordinate[] newNodes = getNodesFor(geom);
|
340 |
coordinates.addAll(Arrays.asList(newNodes));
|
341 |
} |
342 |
} |
343 |
// else {
|
344 |
// System.out
|
345 |
// .println("Este proceso solo debe trabajar con lineas");
|
346 |
// System.out.println(processedGeometry.getGeometryType());
|
347 |
// }
|
348 |
return geomNodes;
|
349 |
} |
350 |
|
351 |
/**
|
352 |
* Checks if a coordinate is on a node of a given set of nodes
|
353 |
*
|
354 |
* @param coord
|
355 |
* @param nodes
|
356 |
* @return
|
357 |
*/
|
358 |
private boolean checkIsNode(Coordinate coord, Coordinate[] nodes) { |
359 |
for (int i = 0; i < nodes.length; i++) { |
360 |
if (coord.distance(nodes[i]) <= snapTolerance)
|
361 |
return true; |
362 |
} |
363 |
return false; |
364 |
} |
365 |
|
366 |
/**
|
367 |
* From a given geometry, and the intersection of this geometry
|
368 |
* with another geometry, it creates a new node with these
|
369 |
* intersections if its points are not coincident with the nodes
|
370 |
* of the original goemetry.
|
371 |
*
|
372 |
* @throws VisitorException
|
373 |
*
|
374 |
*/
|
375 |
private void processIntersections( |
376 |
com.vividsolutions.jts.geomgraph.SnappingNodeMap nodes, |
377 |
Geometry processedGeometry, Geometry intersections, |
378 |
int fid1, int fid2) throws VisitorException { |
379 |
|
380 |
Coordinate[] geomNodes = getNodesFor(processedGeometry);
|
381 |
if (intersections instanceof Point) { |
382 |
Point p = (Point) intersections; |
383 |
Coordinate coord = p.getCoordinate(); |
384 |
if (!checkIsNode(coord, geomNodes)) {
|
385 |
nodes.addNode(coord); |
386 |
|
387 |
/*
|
388 |
* We are computing intersections twice: A
|
389 |
* intersection B and B intersection A. This is
|
390 |
* simpler than manage caches. With this logic, we
|
391 |
* avoid to write the same pseudonode twice
|
392 |
*
|
393 |
*/
|
394 |
if (snapCoordMap.containsKey(coord))
|
395 |
return;
|
396 |
else {
|
397 |
snapCoordMap.put(coord, coord); |
398 |
IFeature feature = createIntersectFeature( |
399 |
coord, fid1, fid2); |
400 |
intersectProcessor.processFeature(feature); |
401 |
} |
402 |
} |
403 |
} else if (intersections instanceof MultiPoint) { |
404 |
MultiPoint points = (MultiPoint) intersections; |
405 |
for (int i = 0; i < points.getNumGeometries(); i++) { |
406 |
Coordinate coord = ((Point) points.getGeometryN(i))
|
407 |
.getCoordinate(); |
408 |
if (!checkIsNode(coord, geomNodes)) {
|
409 |
nodes.addNode(coord); |
410 |
if (snapCoordMap.containsKey(coord))
|
411 |
return;
|
412 |
else {
|
413 |
snapCoordMap.put(coord, coord); |
414 |
IFeature feature = createIntersectFeature( |
415 |
coord, fid1, fid2); |
416 |
intersectProcessor.processFeature(feature); |
417 |
} |
418 |
} |
419 |
} |
420 |
} else if (intersections instanceof LineString) { |
421 |
LineString line = (LineString) intersections; |
422 |
int numPoints = line.getCoordinates().length;
|
423 |
Coordinate coord1 = line.getCoordinateN(0);
|
424 |
Coordinate coord2 = line.getCoordinateN(numPoints - 1);
|
425 |
if (!checkIsNode(coord1, geomNodes)) {
|
426 |
nodes.addNode(coord1); |
427 |
if (snapCoordMap.containsKey(coord1))
|
428 |
return;
|
429 |
else {
|
430 |
snapCoordMap.put(coord1, coord1); |
431 |
IFeature feature = createIntersectFeature( |
432 |
coord1, fid1, fid2); |
433 |
intersectProcessor.processFeature(feature); |
434 |
} |
435 |
} |
436 |
if (!checkIsNode(coord2, geomNodes)) {
|
437 |
nodes.addNode(coord2); |
438 |
if (snapCoordMap.containsKey(coord2))
|
439 |
return;
|
440 |
else {
|
441 |
snapCoordMap.put(coord2, coord2); |
442 |
IFeature feature = createIntersectFeature( |
443 |
coord2, fid1, fid2); |
444 |
intersectProcessor.processFeature(feature); |
445 |
} |
446 |
} |
447 |
} else if (intersections instanceof GeometryCollection) { |
448 |
GeometryCollection col = (GeometryCollection) intersections; |
449 |
for (int i = 0; i < col.getNumGeometries(); i++) { |
450 |
|
451 |
// El tema est? en que aqu? el calculo de los nodos
|
452 |
// de la geometria intersectada se repite cada vez
|
453 |
// revisar, pues MultiLineString puede ser un
|
454 |
// resultado habitual
|
455 |
processIntersections(nodes, processedGeometry, col |
456 |
.getGeometryN(i), fid1, fid2); |
457 |
} |
458 |
} |
459 |
// else if (intersections instanceof Polygon) {
|
460 |
// System.out
|
461 |
// .println("Un poligono interseccion de 2 lineas???");
|
462 |
// }// else
|
463 |
|
464 |
} |
465 |
|
466 |
public void visit(IGeometry g2, int indexOverlay) |
467 |
throws VisitorException, StopWriterVisitorException,
|
468 |
ProcessVisitorException { |
469 |
|
470 |
if (g2 == null) |
471 |
return;
|
472 |
|
473 |
if (index == indexOverlay)
|
474 |
return;
|
475 |
|
476 |
if (onlySelection) {
|
477 |
try {
|
478 |
if (!layerToClean.getRecordset().getSelection()
|
479 |
.get(indexOverlay)) |
480 |
return;
|
481 |
} catch (ReadDriverException e) {
|
482 |
throw new ProcessVisitorException(recordset |
483 |
.getName(), e, |
484 |
"Error verificando seleccion en clean");
|
485 |
}// geometry g is not selected
|
486 |
}// if onlySelection
|
487 |
|
488 |
int geometryType = g2.getGeometryType();
|
489 |
if (geometryType != XTypes.ARC
|
490 |
&& geometryType != XTypes.LINE |
491 |
&& geometryType != XTypes.MULTI) |
492 |
return;
|
493 |
|
494 |
/*
|
495 |
* TODO De momento no vamos a tener en cuenta que la
|
496 |
* interseccion ya ha sido calculada... (Ver comentario al
|
497 |
* instanciar SnappingNodeMap) // ya ha sido tratado
|
498 |
* if(processedFeatures.get(indexOverlay)) return;
|
499 |
*/
|
500 |
Geometry jtsGeo2 = g2.toJTSGeometry(); |
501 |
if (!checkForLineGeometry(jtsGeo2))
|
502 |
return;
|
503 |
|
504 |
if (overlayOp == null) |
505 |
overlayOp = new SnappingOverlayOperation(jtsGeo,
|
506 |
jtsGeo2, snapTolerance); |
507 |
else {
|
508 |
overlayOp.setSecondGeometry(jtsGeo2); |
509 |
} |
510 |
|
511 |
Geometry intersections = overlayOp |
512 |
.getResultGeometry(SnappingOverlayOperation.INTERSECTION); |
513 |
|
514 |
processIntersections(nodes, jtsGeo, intersections, index, |
515 |
indexOverlay); |
516 |
|
517 |
// IFeature cleanedFeature;
|
518 |
// try {
|
519 |
// cleanedFeature = createFeature(newGeoJts,
|
520 |
// index, indexOverlay);
|
521 |
// } catch (DriverException e) {
|
522 |
// throw new VisitException(
|
523 |
// "Error al crear el feature resultante del CLEAN");
|
524 |
// }
|
525 |
// featureProcessor.processFeature(cleanedFeature);
|
526 |
|
527 |
} |
528 |
|
529 |
public String getProcessDescription() { |
530 |
return "Computing intersections of a polygon with its adjacents"; |
531 |
} |
532 |
|
533 |
public void stop(FLayer layer) |
534 |
throws StopWriterVisitorException, VisitorException {
|
535 |
} |
536 |
|
537 |
public boolean start(FLayer layer) throws StartVisitorException { |
538 |
return true; |
539 |
} |
540 |
}, g.getBounds2D()); |
541 |
// At this point, nodes variable (SnappingNodeMap)
|
542 |
// has all intersections of the visited feature with the rest of
|
543 |
// features of the layer
|
544 |
|
545 |
// It computes linear distance of a point on the given jtsGeo linear
|
546 |
// geometry
|
547 |
boolean rightGeometry = true; |
548 |
if (nodes.values().size() > 0) { |
549 |
|
550 |
LengthIndexedLine lengthLine = new LengthIndexedLine(jtsGeo);
|
551 |
Iterator nodesIt = nodes.iterator();
|
552 |
ArrayList nodeIntersections = new ArrayList(); |
553 |
while (nodesIt.hasNext()) {
|
554 |
Node node = (Node) nodesIt.next(); |
555 |
Coordinate coord = node.getCoordinate(); |
556 |
double lengthOfNode = lengthLine.indexOf(coord);
|
557 |
LineIntersection inters = new LineIntersection();
|
558 |
inters.coordinate = coord; |
559 |
inters.lenght = lengthOfNode; |
560 |
nodeIntersections.add(inters); |
561 |
} |
562 |
|
563 |
if (nodeIntersections.size() > 0) { |
564 |
// We sort the intersections by distance along the line
|
565 |
// (dynamic
|
566 |
// segmentation)
|
567 |
rightGeometry = false;
|
568 |
Collections.sort(nodeIntersections, new Comparator() { |
569 |
public int compare(Object arg0, Object arg1) { |
570 |
LineIntersection l1 = (LineIntersection) arg0; |
571 |
LineIntersection l2 = (LineIntersection) arg1; |
572 |
if (l1.lenght > l2.lenght)
|
573 |
return 1; |
574 |
else if (l1.lenght < l2.lenght) |
575 |
return -1; |
576 |
else
|
577 |
return 0; |
578 |
} |
579 |
}); |
580 |
|
581 |
LinearLocation lastLocation = null;
|
582 |
LineIntersection lastIntersection = null;
|
583 |
LocationIndexedLine indexedLine = new LocationIndexedLine(
|
584 |
jtsGeo); |
585 |
for (int i = 0; i < nodeIntersections.size(); i++) { |
586 |
Geometry solution = null;
|
587 |
LineIntersection li = (LineIntersection) nodeIntersections |
588 |
.get(i); |
589 |
|
590 |
LinearLocation location = indexedLine |
591 |
.indexOf(li.coordinate);// es posible que esto
|
592 |
// est? mal por no
|
593 |
// pasarle una longitud.
|
594 |
// REVISAR
|
595 |
if (lastLocation == null) { |
596 |
LinearLocation from = new LinearLocation(0, 0d); |
597 |
|
598 |
// solution = splitLineString(jtsGeo, from, location,
|
599 |
// null, li);
|
600 |
//
|
601 |
|
602 |
solution = indexedLine.extractLine(from, location); |
603 |
|
604 |
|
605 |
lastLocation = location; |
606 |
lastIntersection = li; |
607 |
/*
|
608 |
* Construimos una linea desde el primer punto hasta
|
609 |
* el punto contenido en LineIntersection, con todos
|
610 |
* los puntos intermedios de la linea.
|
611 |
*
|
612 |
*
|
613 |
*
|
614 |
*/
|
615 |
} else {
|
616 |
// Construimos una linea entre lastIntersection y la
|
617 |
// intersection
|
618 |
// actual
|
619 |
LinearLocation locationFrom = lastLocation; |
620 |
|
621 |
// solution = splitLineString(jtsGeo, locationFrom,
|
622 |
// location, lastIntersection, li);
|
623 |
|
624 |
solution = indexedLine.extractLine(locationFrom, location); |
625 |
lastLocation = location; |
626 |
lastIntersection = li; |
627 |
|
628 |
} |
629 |
|
630 |
IFeature feature = createFeature(solution, index); |
631 |
featureProcessor.processFeature(feature); |
632 |
// TODO Podriamos guardar los puntos de interseccion
|
633 |
// para
|
634 |
// mostrar al usuario que puntos eran pseudonodos
|
635 |
}// for
|
636 |
|
637 |
// a?adimos el ultimo segmento
|
638 |
// Coordinate[] geomCoords = jtsGeo.getCoordinates();
|
639 |
// ArrayList coordinates = new ArrayList();
|
640 |
// coordinates.add(lastIntersection.coordinate);
|
641 |
// int startIndex = lastLocation.getSegmentIndex() + 1;
|
642 |
// for (int i = startIndex; i < geomCoords.length; i++) {
|
643 |
// coordinates.add(geomCoords[i]);
|
644 |
// }
|
645 |
// Coordinate[] solutionCoords = new Coordinate[coordinates
|
646 |
// .size()];
|
647 |
// coordinates.toArray(solutionCoords);
|
648 |
// IFeature lastFeature = createFeature(new GeometryFactory()
|
649 |
// .createLineString(solutionCoords), index);
|
650 |
LinearLocation endLocation = new LinearLocation();
|
651 |
endLocation.setToEnd(jtsGeo); |
652 |
Geometry geo = indexedLine.extractLine(lastLocation, endLocation); |
653 |
IFeature lastFeature = createFeature(geo, index); |
654 |
featureProcessor.processFeature(lastFeature); |
655 |
|
656 |
} |
657 |
} |
658 |
if(rightGeometry){
|
659 |
IFeature feature = createFeature(g, index); |
660 |
featureProcessor.processFeature(feature); |
661 |
} |
662 |
|
663 |
|
664 |
} catch (ReadDriverException e) {
|
665 |
throw new ProcessVisitorException(recordset.getName(), e, |
666 |
"Error buscando los overlays que intersectan con un feature");
|
667 |
} |
668 |
} |
669 |
|
670 |
|
671 |
|
672 |
|
673 |
|
674 |
|
675 |
|
676 |
//Dada una linea, una localizacion de partida (from), una localizaci?n de llegada (to), y dos puntos de interseccion (from) devuelve la linea entre from y to
|
677 |
private Geometry splitLineString(Geometry linearGeometry,
|
678 |
LinearLocation from, LinearLocation to, LineIntersection fromInt, |
679 |
LineIntersection toInt) { |
680 |
Coordinate[] geomCoords = linearGeometry.getCoordinates();
|
681 |
ArrayList coordinates = new ArrayList(); |
682 |
if (fromInt != null) |
683 |
coordinates.add(fromInt.coordinate); |
684 |
int startIndex = from.getSegmentIndex();
|
685 |
/*
|
686 |
* segmentIndex siempre referencia al punto inmediatamente anterior del
|
687 |
* lineString. Nos interesa sumar 1, a no ser que sea el primer punto
|
688 |
* del linestring
|
689 |
*/
|
690 |
if (startIndex != 0) |
691 |
startIndex++; |
692 |
|
693 |
for (int i = startIndex; i <= to.getSegmentIndex(); i++) { |
694 |
coordinates.add(geomCoords[i]); |
695 |
} |
696 |
coordinates.add(toInt.coordinate); |
697 |
Coordinate[] solutionCoords = new Coordinate[coordinates.size()]; |
698 |
coordinates.toArray(solutionCoords); |
699 |
return new GeometryFactory().createLineString(solutionCoords); |
700 |
|
701 |
} |
702 |
|
703 |
class LineIntersection { |
704 |
Coordinate coordinate; |
705 |
|
706 |
double lenght;
|
707 |
} |
708 |
|
709 |
public String getProcessDescription() { |
710 |
return "Cleaning lines of a vectorial line layer"; |
711 |
} |
712 |
|
713 |
public void stop(FLayer layer) throws StopWriterVisitorException, |
714 |
VisitorException { |
715 |
this.featureProcessor.finish();
|
716 |
this.intersectProcessor.finish();
|
717 |
} |
718 |
|
719 |
public boolean start(FLayer layer) throws StartVisitorException { |
720 |
if (layer instanceof AlphanumericData && layer instanceof VectorialData) { |
721 |
try {
|
722 |
layerToClean = (FLyrVect) layer; |
723 |
recordset = ((AlphanumericData) layer).getRecordset(); |
724 |
strategy = StrategyManager.getStrategy(layerToClean); |
725 |
featureProcessor.start(); |
726 |
intersectProcessor.start(); |
727 |
} catch (ReadDriverException e) {
|
728 |
return false; |
729 |
} |
730 |
return true; |
731 |
} |
732 |
return false; |
733 |
} |
734 |
|
735 |
private IFeature createFeature(Geometry jtsGeometry, int firstLayerIndex) |
736 |
throws ReadDriverException {
|
737 |
IFeature solution = null;
|
738 |
IGeometry cleanedGeometry = FConverter.jts_to_igeometry(jtsGeometry); |
739 |
FieldDescription[] fields = layerDefinition.getFieldsDesc();
|
740 |
int numFields = fields.length;
|
741 |
Value[] featureAttr = new Value[fields.length]; |
742 |
for (int indexField = 0; indexField < numFields; indexField++) { |
743 |
// for each field of firstRs
|
744 |
String fieldName = recordset.getFieldName(indexField);
|
745 |
for (int j = 0; j < fields.length; j++) { |
746 |
if (fieldName.equalsIgnoreCase(fields[j].getFieldName())) {
|
747 |
featureAttr[j] = recordset.getFieldValue(firstLayerIndex, |
748 |
indexField); |
749 |
break;
|
750 |
}// if
|
751 |
}// for
|
752 |
}// for
|
753 |
// now we put null values
|
754 |
for (int i = 0; i < featureAttr.length; i++) { |
755 |
if (featureAttr[i] == null) |
756 |
featureAttr[i] = ValueFactory.createNullValue(); |
757 |
} |
758 |
solution = FeatureFactory.createFeature(featureAttr, cleanedGeometry); |
759 |
return solution;
|
760 |
} |
761 |
|
762 |
private IFeature createIntersectFeature(Coordinate coord, int fid1, int fid2) { |
763 |
IFeature solution = null;
|
764 |
Point point = FConverter.geomFactory.createPoint(coord);
|
765 |
IGeometry cleanedGeometry = FConverter.jts_to_igeometry(point); |
766 |
Value[] values = new Value[2]; |
767 |
values[0] = ValueFactory.createValue(fid1);
|
768 |
values[1] = ValueFactory.createValue(fid2);
|
769 |
solution = FeatureFactory.createFeature(values, cleanedGeometry); |
770 |
return solution;
|
771 |
} |
772 |
|
773 |
private IFeature createFeature(IGeometry g, int firstLayerIndex) |
774 |
throws ReadDriverException {
|
775 |
IFeature solution = null;
|
776 |
FieldDescription[] fields = layerDefinition.getFieldsDesc();
|
777 |
int numFields = fields.length;
|
778 |
Value[] featureAttr = new Value[fields.length]; |
779 |
for (int indexField = 0; indexField < numFields; indexField++) { |
780 |
// for each field of firstRs
|
781 |
String fieldName = recordset.getFieldName(indexField);
|
782 |
for (int j = 0; j < fields.length; j++) { |
783 |
if (fieldName.equalsIgnoreCase(fields[j].getFieldName())) {
|
784 |
featureAttr[j] = recordset.getFieldValue(firstLayerIndex, |
785 |
indexField); |
786 |
break;
|
787 |
}// if
|
788 |
}// for
|
789 |
}// for
|
790 |
// now we put null values
|
791 |
for (int i = 0; i < featureAttr.length; i++) { |
792 |
if (featureAttr[i] == null) |
793 |
featureAttr[i] = ValueFactory.createNullValue(); |
794 |
} |
795 |
solution = FeatureFactory.createFeature(featureAttr, g); |
796 |
return solution;
|
797 |
} |
798 |
|
799 |
// public static void main(String[] args) {
|
800 |
// DriverManager dm = new DriverManager();
|
801 |
// dm.setValidation(new DriverValidation() {
|
802 |
// public boolean validate(Driver d) {
|
803 |
// return ((d instanceof ObjectDriver)
|
804 |
// || (d instanceof FileDriver) || (d instanceof DBDriver));
|
805 |
// }
|
806 |
// });
|
807 |
// dm.loadDrivers(new File(
|
808 |
// "../_fwAndami/gvSIG/extensiones/com.iver.cit.gvsig/drivers"));
|
809 |
// LayerFactory
|
810 |
// .setDriversPath("../_fwAndami/gvSIG/extensiones/com.iver.cit.gvsig/drivers");
|
811 |
//
|
812 |
// // Setup del factory de DataSources
|
813 |
// DataSourceFactory dsf = LayerFactory.getDataSourceFactory();
|
814 |
// dsf.setDriverManager(dm);
|
815 |
//
|
816 |
// // Setup de las tablas
|
817 |
// // dsf.addFileDataSource("gdbms dbf driver", "nodes", "c:/nodes.dbf");
|
818 |
// // dsf.addFileDataSource("gdbms dbf driver", "edges", "c:/edges.dbf");
|
819 |
//
|
820 |
// IProjection prj = CRSFactory.getCRS("EPSG:23030");
|
821 |
// File shpFile = new File("C:/JUMP/datos/cauces_gv.shp");
|
822 |
// try {
|
823 |
// FLyrVect lyr = (FLyrVect) LayerFactory.createLayer("Ejes",
|
824 |
// "gvSIG shp driver", shpFile, prj);
|
825 |
// System.out.println(lyr.getSource().getShapeCount());
|
826 |
//
|
827 |
// LayerDefinition definition = new LayerDefinition();
|
828 |
// FieldDescription cauNom = new FieldDescription();
|
829 |
// cauNom.setFieldName("CAUNOM");
|
830 |
// cauNom.setFieldType(XTypes.CHAR);
|
831 |
// cauNom.setFieldLength(10);
|
832 |
// cauNom.setFieldDecimalCount(0);
|
833 |
// definition.setFieldsDesc(new FieldDescription[]{cauNom});
|
834 |
// definition.setShapeType(XTypes.LINE);
|
835 |
//
|
836 |
//
|
837 |
//
|
838 |
//
|
839 |
// // LineCleanVisitor visitor = new LineCleanVisitor(
|
840 |
// // new FeatureProcessor() {
|
841 |
// //
|
842 |
// // public void processFeature(IRow feature) {
|
843 |
// // // TODO Auto-generated method stub
|
844 |
// //
|
845 |
// // }
|
846 |
// //
|
847 |
// // public void finish() {
|
848 |
// // // TODO Auto-generated method stub
|
849 |
// //
|
850 |
// // }
|
851 |
// //
|
852 |
// // public void start() throws EditionException {
|
853 |
// // // TODO Auto-generated method stub
|
854 |
// //
|
855 |
// // }
|
856 |
// // }, false, definition);
|
857 |
// Strategy str = StrategyManager.getStrategy(lyr);
|
858 |
// // str.process(visitor);
|
859 |
//
|
860 |
// // } catch (com.iver.cit.gvsig.fmap.DriverException e) {
|
861 |
// // // TODO Auto-generated catch block
|
862 |
// // e.printStackTrace();
|
863 |
// // } catch (DriverIOException e) {
|
864 |
// // // TODO Auto-generated catch block
|
865 |
// // e.printStackTrace();
|
866 |
// // } catch (VisitException e) {
|
867 |
// // // TODO Auto-generated catch block
|
868 |
// // e.printStackTrace();
|
869 |
// // }
|
870 |
// }
|
871 |
|
872 |
} |