svn-gvsig-desktop / trunk / libraries / libTopology / src / org / gvsig / topology / errorfixes / ExtendDangleToNearestVertexFix.java @ 25630
History | View | Annotate | Download (9.58 KB)
1 | 20238 | azabala | /*
|
---|---|---|---|
2 | * Created on 10-abr-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 | */
|
||
49 | package org.gvsig.topology.errorfixes; |
||
50 | |||
51 | import java.awt.geom.Rectangle2D; |
||
52 | import java.util.ArrayList; |
||
53 | import java.util.List; |
||
54 | 25630 | azabala | import java.util.Map; |
55 | 20238 | azabala | |
56 | import org.gvsig.exceptions.BaseException; |
||
57 | import org.gvsig.fmap.core.FLyrUtil; |
||
58 | 23039 | azabala | import org.gvsig.fmap.core.NewFConverter; |
59 | 20238 | azabala | import org.gvsig.jts.JtsUtil; |
60 | import org.gvsig.topology.Messages; |
||
61 | import org.gvsig.topology.TopologyError; |
||
62 | 20401 | azabala | import org.gvsig.util.GNumberParameter; |
63 | import org.gvsig.util.GParameter; |
||
64 | 20238 | azabala | |
65 | import com.hardcode.gdbms.driver.exceptions.ReadDriverException; |
||
66 | import com.iver.cit.gvsig.drivers.featureiterators.FeatureListIntIterator; |
||
67 | import com.iver.cit.gvsig.fmap.core.FGeometry; |
||
68 | import com.iver.cit.gvsig.fmap.core.FPoint2D; |
||
69 | import com.iver.cit.gvsig.fmap.core.IFeature; |
||
70 | import com.iver.cit.gvsig.fmap.core.IGeometry; |
||
71 | import com.iver.cit.gvsig.fmap.layers.FLyrVect; |
||
72 | import com.iver.cit.gvsig.fmap.spatialindex.INearestNeighbourFinder; |
||
73 | import com.vividsolutions.jts.algorithms.SnapCGAlgorithms; |
||
74 | import com.vividsolutions.jts.geom.Coordinate; |
||
75 | import com.vividsolutions.jts.geom.Geometry; |
||
76 | import com.vividsolutions.jts.geom.GeometryCollection; |
||
77 | import com.vividsolutions.jts.geom.LineString; |
||
78 | 25630 | azabala | import com.vividsolutions.jts.geom.Point; |
79 | 20238 | azabala | import com.vividsolutions.jts.geom.util.LinearComponentExtracter; |
80 | import com.vividsolutions.jts.geom.util.GeometryEditor.CoordinateOperation; |
||
81 | import com.vividsolutions.jts.operation.distance.DistanceOp; |
||
82 | |||
83 | /**
|
||
84 | * From a given 'must not have dangles' topology error, extends
|
||
85 | * the dangling segment until it touchs another line in the specified distance
|
||
86 | * radius.
|
||
87 | * @author Alvaro Zabala
|
||
88 | *
|
||
89 | */
|
||
90 | 20401 | azabala | public class ExtendDangleToNearestVertexFix extends AbstractTopologyErrorFix implements ITopologyErrorFixWithParameters{ |
91 | 20238 | azabala | |
92 | 23039 | azabala | public double searchRadius; |
93 | 20238 | azabala | |
94 | public ExtendDangleToNearestVertexFix(double searchRadius){ |
||
95 | super();
|
||
96 | this.searchRadius = searchRadius;
|
||
97 | } |
||
98 | |||
99 | public ExtendDangleToNearestVertexFix() {
|
||
100 | } |
||
101 | |||
102 | 23039 | azabala | public List<IFeature>[] fixAlgorithm(TopologyError error) throws BaseException { |
103 | 20238 | azabala | FLyrVect originLyr = error.getOriginLayer(); |
104 | double clusterTolerance = error.getTopology().getClusterTolerance();
|
||
105 | FGeometry errorGeometry = (FGeometry) error.getGeometry(); |
||
106 | FPoint2D dangle = (FPoint2D) errorGeometry.getInternalShape(); |
||
107 | 25630 | azabala | Coordinate jtsCoord = new Coordinate(dangle.getX(), dangle.getY());
|
108 | Point jtsDangle = JtsUtil.GEOMETRY_FACTORY.createPoint(jtsCoord);
|
||
109 | 20238 | azabala | IFeature originFeature = error.getFeature1(); |
110 | |||
111 | IFeature nearestFeature = getNearestFeature(dangle, originLyr, originFeature); |
||
112 | |||
113 | if(nearestFeature != null){ |
||
114 | 23039 | azabala | Geometry nearestJts = NewFConverter.toJtsGeometry(nearestFeature.getGeometry()); |
115 | Geometry originalJts = NewFConverter.toJtsGeometry(originFeature.getGeometry()); |
||
116 | 20238 | azabala | |
117 | 25630 | azabala | Coordinate closestPoint = getClosestPoint(jtsDangle, nearestJts); |
118 | double distance = DistanceOp.distance(jtsDangle, nearestJts);
|
||
119 | 20238 | azabala | |
120 | if(distance <= searchRadius){
|
||
121 | 25630 | azabala | Geometry editedGeometry = extendGeometry(originalJts, jtsDangle.getCoordinate(), closestPoint, clusterTolerance); |
122 | 20238 | azabala | if(editedGeometry != null){ |
123 | 23039 | azabala | IGeometry newGeom = NewFConverter.toFMap(editedGeometry); |
124 | 20238 | azabala | |
125 | originFeature.setGeometry(newGeom); |
||
126 | 23039 | azabala | List<IFeature> editedFeatures = new ArrayList<IFeature>(); |
127 | editedFeatures.add(originFeature); |
||
128 | return (List<IFeature>[]) new List[]{editedFeatures}; |
||
129 | 20238 | azabala | }//if editedGeometry
|
130 | 25630 | azabala | }else{
|
131 | BaseException exception = new BaseException(){
|
||
132 | public String getFormatString(){ |
||
133 | return Messages.getText("Geometry_not_found_in_radius_search"); |
||
134 | } |
||
135 | @Override
|
||
136 | protected Map values() { |
||
137 | // TODO Auto-generated method stub
|
||
138 | return null; |
||
139 | }}; |
||
140 | throw exception;
|
||
141 | } |
||
142 | 20238 | azabala | }//if nearest feature
|
143 | return null; |
||
144 | } |
||
145 | |||
146 | |||
147 | protected Coordinate getClosestPoint(Geometry original, Geometry nearestGeometry){
|
||
148 | return DistanceOp.closestPoints(original, nearestGeometry)[1]; |
||
149 | } |
||
150 | |||
151 | private Geometry extendGeometry(Geometry g, Coordinate dangle, final Coordinate closestPoint, double clusterTolerance){ |
||
152 | |||
153 | List<LineString> geometries2process = new ArrayList<LineString>(); |
||
154 | if (g instanceof LineString) |
||
155 | geometries2process.add((LineString) g); |
||
156 | else if (g instanceof GeometryCollection) { |
||
157 | GeometryCollection geomCol = (GeometryCollection) g; |
||
158 | List lines = LinearComponentExtracter.getLines(geomCol);
|
||
159 | geometries2process.addAll(lines); |
||
160 | } |
||
161 | |||
162 | for(int i = 0; i < geometries2process.size(); i++){ |
||
163 | LineString lineString = geometries2process.get(i); |
||
164 | if(JtsUtil.isEndPoint(lineString, dangle, clusterTolerance)){
|
||
165 | int numPoints = lineString.getNumPoints();
|
||
166 | Coordinate start = lineString.getCoordinateN(0);
|
||
167 | Coordinate end = lineString.getCoordinateN(numPoints - 1);
|
||
168 | Geometry editedGeometry = null;
|
||
169 | if(SnapCGAlgorithms.snapEquals2D(dangle, start, clusterTolerance)){
|
||
170 | editedGeometry = JtsUtil.GEOMETRY_EDITOR.edit(lineString, new CoordinateOperation(){
|
||
171 | public Coordinate[] edit(Coordinate[] coordinates, Geometry geometry) { |
||
172 | Coordinate[] newCoordinates = new Coordinate[coordinates.length + 1]; |
||
173 | System.arraycopy(coordinates, 0, newCoordinates, 1, coordinates.length); |
||
174 | newCoordinates[0] = closestPoint;
|
||
175 | return newCoordinates;
|
||
176 | }}); |
||
177 | |||
178 | }else{
|
||
179 | editedGeometry = JtsUtil.GEOMETRY_EDITOR.edit(lineString, new CoordinateOperation(){
|
||
180 | public Coordinate[] edit(Coordinate[] coordinates, Geometry geometry) { |
||
181 | Coordinate[] newCoordinates = new Coordinate[coordinates.length + 1]; |
||
182 | System.arraycopy(coordinates, 0, newCoordinates, 0, coordinates.length); |
||
183 | newCoordinates[coordinates.length] = closestPoint; |
||
184 | return newCoordinates;
|
||
185 | }}); |
||
186 | } |
||
187 | return editedGeometry;
|
||
188 | }//if isEndPoint
|
||
189 | }//for
|
||
190 | //at this point we havent found a linestring end point for the dangle error
|
||
191 | //TODO launch inconsistent exception?
|
||
192 | return null; |
||
193 | } |
||
194 | |||
195 | |||
196 | |||
197 | private IFeature getNearestFeature(FPoint2D dangle, FLyrVect originLyr, IFeature originFeature) throws ReadDriverException{ |
||
198 | IGeometry originalGeometry = originFeature.getGeometry(); |
||
199 | 23039 | azabala | Geometry originalJts = NewFConverter.toJtsGeometry(originalGeometry); |
200 | 20238 | azabala | |
201 | INearestNeighbourFinder nnFinder = |
||
202 | FLyrUtil.getNearestNeighbourFinder(originLyr); |
||
203 | |||
204 | int numberOfNearest = 2; |
||
205 | Rectangle2D dangleRect = new Rectangle2D.Double(dangle.getX(), dangle.getY(), 1, 1); |
||
206 | // List nearestIndexes = nnFinder.
|
||
207 | // findNNearest(numberOfNearest, new Point2D.Double(dangle.getX(), dangle.getY()));
|
||
208 | List nearestIndexes = nnFinder.findNNearest(numberOfNearest, dangleRect);
|
||
209 | |||
210 | //we look for the nearest neighbour to the dangle, excepting the originFeature
|
||
211 | //if the distance to the point is lesser than the search radius, we snap it
|
||
212 | double nearestDistance = Double.MAX_VALUE; |
||
213 | |||
214 | FeatureListIntIterator it = new FeatureListIntIterator(nearestIndexes, originLyr.getSource() );
|
||
215 | IFeature nearestFeature = null;
|
||
216 | 25630 | azabala | Point jtsDangle = JtsUtil.GEOMETRY_FACTORY.createPoint(new Coordinate(dangle.getX(), dangle.getY())); |
217 | 20238 | azabala | while(it.hasNext()){
|
218 | IFeature feature = it.next(); |
||
219 | if(feature.getID().equalsIgnoreCase(originFeature.getID()))
|
||
220 | continue;
|
||
221 | IGeometry igeometry = feature.getGeometry(); |
||
222 | Geometry jtsGeo = igeometry.toJTSGeometry(); |
||
223 | 25630 | azabala | double dist = jtsGeo.distance(jtsDangle);
|
224 | // double dist = originalJts.distance(jtsGeo);
|
||
225 | 20238 | azabala | if (dist <= nearestDistance) {
|
226 | // by adding <=, we follow the convention that
|
||
227 | // if two features are at the same distance, take
|
||
228 | // the last as nearest neighbour
|
||
229 | nearestDistance = dist; |
||
230 | nearestFeature = feature; |
||
231 | }// if
|
||
232 | }//while
|
||
233 | return nearestFeature;
|
||
234 | } |
||
235 | |||
236 | public String getEditionDescription() { |
||
237 | return Messages.getText("EXTEND_DANGLE_FIX"); |
||
238 | } |
||
239 | |||
240 | public double getSearchRadius() { |
||
241 | return searchRadius;
|
||
242 | } |
||
243 | |||
244 | public void setSearchRadius(double searchRadius) { |
||
245 | this.searchRadius = searchRadius;
|
||
246 | } |
||
247 | 20401 | azabala | |
248 | |||
249 | public GParameter[] getParameters() { |
||
250 | GParameter[] parameters = new GParameter[1]; |
||
251 | parameters[0] =
|
||
252 | new GNumberParameter("searchRadius", new Double(0d), this, false); |
||
253 | return parameters;
|
||
254 | } |
||
255 | |||
256 | public void setParameterValue(String paramName, Object value) { |
||
257 | if(paramName.equals("searchRadius")){ |
||
258 | if(value.getClass().isAssignableFrom(Number.class)){ |
||
259 | this.searchRadius = ((Number)value).doubleValue(); |
||
260 | } |
||
261 | } |
||
262 | } |
||
263 | 21257 | azabala | |
264 | public void initialize(TopologyError error) { |
||
265 | } |
||
266 | 20238 | azabala | } |