Revision 13591

View differences:

trunk/libraries/libTopology/src/org/gvsig/jts/RobustLocationIndexedLine.java
1
/*
2
 * Created on 09-sep-2007
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
* Revision 1.1  2007-09-09 11:44:09  azabala
49
* Improvements to JTS (robustness problems)
50
*
51
*
52
*/
53
package org.gvsig.jts;
54

  
55
import com.vividsolutions.jts.geom.Coordinate;
56
import com.vividsolutions.jts.geom.Geometry;
57
import com.vividsolutions.jts.geom.LineSegment;
58
import com.vividsolutions.jts.geom.PrecisionModel;
59
import com.vividsolutions.jts.linearref.LinearIterator;
60
import com.vividsolutions.jts.linearref.LinearLocation;
61
import com.vividsolutions.jts.linearref.LocationIndexedLine;
62

  
63
public class RobustLocationIndexedLine extends LocationIndexedLine {
64

  
65
	
66
	private Geometry linearGeom;
67
	
68
	
69
	public RobustLocationIndexedLine(Geometry arg0) {
70
		super(arg0);
71
		this.linearGeom = arg0;
72
	}
73
	
74
	 public LinearLocation indexOf(Coordinate pt)
75
	  {
76
	    return indexOfFromStart(pt, null);
77
	  }
78
	 
79
//	 These methods are needed because JTS LocationIndexedLine doesnt have an
80
		// indexOfAlter
81
		// method and LocationIndexPoint, which makes all these computations is not
82
		// a public class
83
		// report it to JTS project
84

  
85
		/*
86
		 * M.Davids has said to me that he has added these methods to JTS (1.9
87
		 * version).
88
		 * 
89
		 * TODO REMOVE THESE METHODS WITH JTS 1.9
90
		 */
91

  
92
		public  LinearLocation indexOfAfter(LocationIndexedLine indexedLine, 
93
										Coordinate inputPt, 
94
										LinearLocation minIndex) {
95
			if (minIndex == null)
96
				return indexedLine.indexOf(inputPt);
97
			LinearLocation endLoc = LinearLocation.getEndLocation(linearGeom);
98
			if (endLoc.compareTo(minIndex) <= 0)
99
				return endLoc;
100

  
101
			LinearLocation closestAfter = indexOfFromStart(inputPt, minIndex);
102
			return closestAfter;
103
		}
104

  
105
	
106
	
107
	private LinearLocation indexOfFromStart(Coordinate inputPt, LinearLocation minIndex)
108
	  {
109
	    double minDistance = Double.MAX_VALUE;
110
	    int minComponentIndex = 0;
111
	    int minSegmentIndex = 0;
112
	    double minFrac = -1.0;
113

  
114
	    LineSegment seg = new LineSegment();
115
	    for (LinearIterator it = new LinearIterator(linearGeom);
116
	         it.hasNext(); it.next()) {
117
	      if (! it.isEndOfLine()) {
118
	        seg.p0 = it.getSegmentStart();
119
	        seg.p1 = it.getSegmentEnd();
120
	        double segDistance = seg.distance(inputPt);
121
	        
122
	        /*
123
	         * Changes to LocationIndexedLine to avoid robustness problems
124
	         * */
125
	        PrecisionModel pm = linearGeom.getPrecisionModel();
126
	        segDistance = pm.makePrecise(segDistance);
127
	        
128
	        double segFrac = segmentFraction(seg, inputPt);
129

  
130
	        int candidateComponentIndex = it.getComponentIndex();
131
	        int candidateSegmentIndex = it.getVertexIndex();
132
	        
133
	        
134
	        if (segDistance < minDistance) {
135
	          // ensure after minLocation, if any
136
	          if (minIndex == null ||
137
	              minIndex.compareLocationValues(
138
	              candidateComponentIndex, candidateSegmentIndex, segFrac)
139
	              < 0
140
	              ) {
141
	            // otherwise, save this as new minimum
142
	            minComponentIndex = candidateComponentIndex;
143
	            minSegmentIndex = candidateSegmentIndex;
144
	            minFrac = segFrac;
145
	            minDistance = segDistance;
146
	          }
147
	        }
148
	      }
149
	    }
150
	    LinearLocation loc = new LinearLocation(minComponentIndex, minSegmentIndex, minFrac);
151
	    return loc;
152
	  }
153
	
154
	public static double segmentFraction(
155
		      LineSegment seg,
156
		      Coordinate inputPt)
157
		  {
158
		    double segFrac = seg.projectionFactor(inputPt);
159
		    if (segFrac < 0.0)
160
		      segFrac = 0.0;
161
		    else if (segFrac > 1.0)
162
		      segFrac = 1.0;
163
		    return segFrac;
164
		  }
165

  
166
}
167

  
0 168

  
trunk/libraries/libTopology/src/org/gvsig/jts/GeometrySnapper.java
10 10
import com.vividsolutions.jts.geom.Geometry;
11 11
import com.vividsolutions.jts.geom.GeometryFactory;
12 12
import com.vividsolutions.jts.geom.LineString;
13
import com.vividsolutions.jts.geom.LinearRing;
14
import com.vividsolutions.jts.geom.Point;
15
import com.vividsolutions.jts.geom.Polygon;
13 16

  
14 17
/**
15
 * Moves coordinates (in a given tolerance) to force them to coincide with coordinates
18
 * Moves coordinates of geometries (in a given tolerance) 
19
 * to force them to coincide with coordinates other geometries 
16 20
 * in its proximity (the snap tolerance)
21
 * 
17 22
 */
18 23
public class GeometrySnapper {
19 24

  
......
21 26
	
22 27
	private GeometryFactory geomFactory = new GeometryFactory();
23 28

  
29
	
24 30
	public GeometrySnapper(double snapTolerance) {
25 31
		this.snapTolerance = snapTolerance;
26 32
	}
......
33 39
		Coordinate coordinate;
34 40
	}
35 41

  
36
	
37
	public Geometry[] snap(LineString[] geoms){
42
	/**
43
	 * Snaps the coordinates of many geometries with the same weight
44
	 * (all coordinates must move)
45
	 * @param geoms
46
	 * @return
47
	 */
48
	public Geometry[] snap(Geometry[] geoms){
38 49
		int weight[] = new int[geoms.length];
39 50
		for(int i = 0; i < geoms.length; i++){
40 51
			weight[i] = 1;
......
43 54
	}
44 55
	
45 56
	/**
46
	 * Snaps all the coordinates of the given LineStrings.
57
	 * Snaps all the coordinates of the given geometries
58
	 * .
47 59
	 * If many coords are in the same distance tolerance radius, it applies a weighted
48
	 * average. If one geometry's weight is 0, it will move to the rest coordinates.
60
	 * average. If one geometry's weight is 0, it wont participate in the average.
49 61
	 * 
50
	 * TODO Generalize LineString to Geometry. It will allow to work with Point, Lines and
51
	 * Polygons (as an outer LineString and many holes).
52
	 * To do that, a geometry will originate a snapped geometry of the same type than
53
	 * the original.
62
	 * @param geoms geometries whose coordinates we want to snap
63
	 * @param weights weight of each geometry in the computation of the weighted average
54 64
	 * 
55 65
	 * */
56
	public Geometry[] snap(LineString[] geoms, int[] weights) {
66
	public Geometry[] snap(Geometry[] geoms, int[] weights) {
57 67
		SnappingCoordinateMap coordinateMap = new SnappingCoordinateMap(snapTolerance);
58
		LineString[] solution = new LineString[geoms.length];
68
		
69
		Geometry[] solution = new Geometry[geoms.length];
59 70
		for(int i = 0; i < geoms.length; i++){
60 71
			Geometry geom = geoms[i];
61 72
			Coordinate[] coords = geom.getCoordinates();
......
97 108
			}//for j
98 109
			
99 110
			Coordinate[] newPts = coordList.toCoordinateArray();
100
			solution[i] = geomFactory.createLineString(newPts);
111
			solution[i] = createGeometry(newPts, geom);
101 112
		}//for i
102 113
		return solution;
103 114
	}
104 115
	
116
	/**
117
	 * Creates a geometry of the same type as geom with newPts coordinates.
118
	 * geom mustn be a GeometryCollection (MultiPolygon, etc.)
119
	 * @param newPts
120
	 * @param geom
121
	 * @return
122
	 */
105 123
	
124
	//TODO See how to manage the snap of polygon holes
125
	
126
	private Geometry createGeometry(Coordinate[] newPts, Geometry geom) {
127
		Geometry solution = null;
128
		if(geom instanceof Point){
129
			if(newPts.length == 1)
130
				return geomFactory.createPoint(newPts[0]);
131
			else{
132
				solution = geomFactory.createMultiPoint(newPts);
133
			}
134
		}else if(geom instanceof LineString){
135
			solution = geomFactory.createLineString(newPts);
136
		}else if(geom instanceof Polygon){
137
			LinearRing linearRing = geomFactory.createLinearRing(newPts);
138
			solution =  geomFactory.createPolygon(linearRing, null);
139
		}
140
		return solution;
141
	}
142

  
106 143
	public Coordinate snapAverage(List coordinates, int[] weights){
107 144
		List snapList = new ArrayList();
108 145
		for(int i = 0; i < coordinates.size(); i++){
......
176 213
	 * @return
177 214
	 */
178 215

  
179
	public Coordinate[] snapTo(Coordinate[] srcPts, boolean isClosed,
180
			Coordinate[] snapPts) {
216
	private Coordinate[] snapTo(Coordinate[] srcPts, 
217
							boolean isClosed,
218
							Coordinate[] snapPts) {
181 219

  
182 220
		CoordinateList coordList = new CoordinateList(srcPts);
183 221
		int coordinateCount = coordList.size();
trunk/libraries/libTopology/src/org/gvsig/jts/LineStringSelfIntersectionChecker.java
6 6

  
7 7
import com.iver.cit.gvsig.util.SnappingCoordinateMap;
8 8
import com.vividsolutions.jts.algorithm.RobustLineIntersector;
9
import com.vividsolutions.jts.algorithms.SnapCGAlgorithms;
9 10
import com.vividsolutions.jts.geom.CoordinateArrays;
10 11
import com.vividsolutions.jts.geom.GeometryFactory;
11 12
import com.vividsolutions.jts.geom.LineString;
......
86 87
	//TODO Add snap tolerance concept
87 88
	
88 89
	public boolean isProper(Coordinate coordinate){
89
		if(lineString instanceof LinearRing)
90
		if(lineString instanceof LinearRing)//TODO INTRODUCE SNAP
90 91
			return coordinate.equals2D(lineString.getCoordinateN(0));
91
		else
92
			return graph.isBoundaryNode(0, coordinate);
92
		else{
93
			boolean solution =  graph.isBoundaryNode(0, coordinate);
94
			if(!solution){
95
				//one more try: see the coordinates of the extremes
96
				//this is needed becase the labeling process for closed linestring
97
				//dont gives us the desired results
98
				if(SnapCGAlgorithms.snapEquals2D(coordinate, lineString.getCoordinateN(0), snapTolerance) || 
99
						SnapCGAlgorithms.snapEquals2D(coordinate, lineString.getCoordinateN(lineString.getNumPoints() - 1), snapTolerance)){
100
					solution = true;
101
				}//if
102
			}//if
103
			return solution;
104
		}//else
93 105
	}
94 106
	
95 107
	
trunk/libraries/libTopology/src/org/gvsig/jts/LineStringSplitter.java
5 5
import java.util.Collection;
6 6
import java.util.Collections;
7 7
import java.util.Comparator;
8
import java.util.HashMap;
8 9
import java.util.Iterator;
9 10
import java.util.List;
10 11

  
......
13 14
import com.vividsolutions.jts.geom.LineSegment;
14 15
import com.vividsolutions.jts.geom.LineString;
15 16
import com.vividsolutions.jts.geom.Polygon;
16
import com.vividsolutions.jts.linearref.LengthIndexedLine;
17 17
import com.vividsolutions.jts.linearref.LinearIterator;
18 18
import com.vividsolutions.jts.linearref.LinearLocation;
19 19
import com.vividsolutions.jts.linearref.LocationIndexedLine;
......
71 71
		for(int i = 0; i < lineStrings.length; i++){
72 72
			LineString geom = lineStrings[i];
73 73
			if(GeometrySnapper.isClosed(geom, snapTolerance)){
74
				closedLineStrings.add(lineStrings[i]);
74
				closedLineStrings.add(geom);
75 75
			}else{
76
				unclosedLineStrings.add(lineStrings[i]);
76
				unclosedLineStrings.add(geom);
77 77
			}
78 78
		}
79 79
		
......
114 114
			Coordinate[] splitPoints) {
115 115
		
116 116
		ArrayList lineStringList = new ArrayList();
117
		LengthIndexedLine lengthLine = new LengthIndexedLine(lineString);
117
		RobustLengthIndexedLine lengthLine = new RobustLengthIndexedLine(lineString);
118 118
		ArrayList nodeIntersections = new ArrayList();
119 119
		double linearReferencingIndex = 0d;
120 120
		for (int i = 0; i < splitPoints.length; i++) {
......
147 147

  
148 148
		LinearLocation lastLocation = null;
149 149
		LineIntersection lastIntersection = null;
150
		LocationIndexedLine indexedLine = new LocationIndexedLine(lineString);
150
		RobustLocationIndexedLine indexedLine = new RobustLocationIndexedLine(lineString);
151 151
		for (int i = 0; i < nodeIntersections.size(); i++) {
152 152
			Geometry geometry = null;
153 153
			LineIntersection li = (LineIntersection) nodeIntersections.get(i);
154 154
			// LinearLocation location = indexedLine.indexOf(li.coordinate);
155
			LinearLocation location = indexOfAfter(indexedLine, lineString,
155
			LinearLocation location = indexedLine.indexOfAfter(indexedLine,
156 156
					li.coordinate, lastLocation);
157 157

  
158 158
			if (lastLocation == null) {
......
191 191
	
192 192
	private static LineString[] splitSimple(LineString lineString, Coordinate[] points) {
193 193
		LineString[] splittedLS = null;
194
		LengthIndexedLine lengthLine = new LengthIndexedLine(lineString);
194
		RobustLengthIndexedLine lengthLine = new RobustLengthIndexedLine(lineString);
195
		/*
196
		 * LenghtIndexedLine indexOfAlter method returns the index of a line greater than the specified index.
197
		 * For this reason, we must save in a cache the last computed index for a given coord, and pass
198
		 * this precomputed index to the indexOfAlter method
199
		 * */
200
		HashMap coordsIndex = new HashMap();
195 201
		ArrayList nodeIntersections = new ArrayList();
196
		double linearDistance = 0d;
197 202
		for (int i = 0; i < points.length; i++) {
198 203
			Coordinate coord = points[i];
199
			double lengthOfNode = lengthLine
200
					.indexOfAfter(coord, linearDistance);
201
			linearDistance = lengthOfNode;
202
			LineIntersection inters = new LineIntersection();
204
			Double index = (Double) coordsIndex.get(coord);
205
			double indexD = 0d;
206
			if(index != null)
207
				indexD = index.doubleValue();
208
			double computedIndex = lengthLine.indexOfAfter(coord, indexD);
209
			coordsIndex.put(coord, new Double(computedIndex));
210
					LineIntersection inters = new LineIntersection();
203 211
			inters.coordinate = coord;
204
			inters.lenght = lengthOfNode;
212
			inters.lenght = computedIndex;
205 213
			nodeIntersections.add(inters);
206 214
		}// for
207 215

  
......
223 231

  
224 232
		LinearLocation lastLocation = null;
225 233
		LineIntersection lastIntersection = null;
226
		LocationIndexedLine indexedLine = new LocationIndexedLine(lineString);
234
		RobustLocationIndexedLine indexedLine = new RobustLocationIndexedLine(lineString);
227 235
		ArrayList splittedLsList = new ArrayList();
228 236
		for (int i = 0; i < nodeIntersections.size(); i++) {
229 237
			Geometry solution = null;
230 238
			LineIntersection li = (LineIntersection) nodeIntersections.get(i);
231
			LinearLocation location = indexOfAfter(indexedLine, lineString,
239
			LinearLocation location = indexedLine.indexOfAfter(indexedLine,
232 240
					li.coordinate, lastLocation);
233 241
			if (lastLocation == null) {
234 242
				LinearLocation from = new LinearLocation(0, 0d);
......
254 262

  
255 263
	}
256 264

  
257
	/*
258
	 * FIXME: Este algoritmo (duplicar las intersecciones).
259
	 * 
260
	 * Probar con:
261
	 * 
262
	 * LINESTRING (-16801 780, -19541 2631, -19133 6356, -15839 7702, -14157
263
	 * 6284, -15503 5972, -15503 6765, -14085 7318, -11969 3929, -16945 1861,
264
	 * -19734 635, -20190 -1143)
265
	 * 
266
	 * 
267
	 * 
268
	 */
269 265
	/**
270 266
	 * to propper work, LineStringSplitter needs coordinates to split a line. in
271 267
	 * a self intersected line case, we must to repeat self interesections
......
291 287
		if (splitPoints.length < 1) {
292 288
			return new LineString[] { lineString };
293 289
		}
290
		
294 291
		Coordinate[] duplicatedSelfIntersections = duplicateSelfIntersections(splitPoints);
295 292
		//TODO Create a test case for a linestring not closed for precision reasons
296 293
		//but closed with a given snap tolerance
......
314 311
	
315 312
	
316 313
	
317
	// These methods are needed because JTS LocationIndexedLine doesnt have an
318
	// indexOfAlter
319
	// method and LocationIndexPoint, which makes all these computations is not
320
	// a public class
321
	// report it to JTS project
314
	
322 315

  
323
	/*
324
	 * M.Davids has said to me that he has added these methods to JTS (1.9
325
	 * version).
326
	 * 
327
	 * TODO REMOVE THESE METHODS WITH JTS 1.9
328
	 */
316
//	private static LinearLocation indexOfFromStart(Coordinate inputPt,
317
//			LineString linearGeom, LinearLocation minIndex) {
318
//		double minDistance = Double.MAX_VALUE;
319
//		int minComponentIndex = 0;
320
//		int minSegmentIndex = 0;
321
//		double minFrac = -1.0;
322
//
323
//		LineSegment seg = new LineSegment();
324
//		for (LinearIterator it = new LinearIterator(linearGeom); it.hasNext(); it
325
//				.next()) {
326
//			if (!it.isEndOfLine()) {
327
//				seg.p0 = it.getSegmentStart();
328
//				seg.p1 = it.getSegmentEnd();
329
//				double segDistance = seg.distance(inputPt);
330
//				double segFrac = segmentFraction(seg, inputPt);
331
//
332
//				int candidateComponentIndex = it.getComponentIndex();
333
//				int candidateSegmentIndex = it.getVertexIndex();
334
//				if (segDistance < minDistance) {
335
//					// ensure after minLocation, if any
336
//					if (minIndex == null
337
//							|| minIndex.compareLocationValues(
338
//									candidateComponentIndex,
339
//									candidateSegmentIndex, segFrac) < 0) {
340
//						// otherwise, save this as new minimum
341
//						minComponentIndex = candidateComponentIndex;
342
//						minSegmentIndex = candidateSegmentIndex;
343
//						minFrac = segFrac;
344
//						minDistance = segDistance;
345
//					}
346
//				}
347
//			}
348
//		}
349
//		LinearLocation loc = new LinearLocation(minComponentIndex,
350
//				minSegmentIndex, minFrac);
351
//		return loc;
352
//	}
329 353

  
330
	public static LinearLocation indexOfAfter(LocationIndexedLine indexedLine,
331
			LineString lineString, Coordinate inputPt, LinearLocation minIndex) {
332
		if (minIndex == null)
333
			return indexedLine.indexOf(inputPt);
334
		LinearLocation endLoc = LinearLocation.getEndLocation(lineString);
335
		if (endLoc.compareTo(minIndex) <= 0)
336
			return endLoc;
354
//	private static double segmentFraction(LineSegment seg, Coordinate inputPt) {
355
//		double segFrac = seg.projectionFactor(inputPt);
356
//		if (segFrac < 0.0)
357
//			segFrac = 0.0;
358
//		else if (segFrac > 1.0)
359
//			segFrac = 1.0;
360
//		return segFrac;
361
//	}
337 362

  
338
		LinearLocation closestAfter = indexOfFromStart(inputPt, lineString,
339
				minIndex);
340
		return closestAfter;
341
	}
342

  
343
	private static LinearLocation indexOfFromStart(Coordinate inputPt,
344
			LineString linearGeom, LinearLocation minIndex) {
345
		double minDistance = Double.MAX_VALUE;
346
		int minComponentIndex = 0;
347
		int minSegmentIndex = 0;
348
		double minFrac = -1.0;
349

  
350
		LineSegment seg = new LineSegment();
351
		for (LinearIterator it = new LinearIterator(linearGeom); it.hasNext(); it
352
				.next()) {
353
			if (!it.isEndOfLine()) {
354
				seg.p0 = it.getSegmentStart();
355
				seg.p1 = it.getSegmentEnd();
356
				double segDistance = seg.distance(inputPt);
357
				double segFrac = segmentFraction(seg, inputPt);
358

  
359
				int candidateComponentIndex = it.getComponentIndex();
360
				int candidateSegmentIndex = it.getVertexIndex();
361
				if (segDistance < minDistance) {
362
					// ensure after minLocation, if any
363
					if (minIndex == null
364
							|| minIndex.compareLocationValues(
365
									candidateComponentIndex,
366
									candidateSegmentIndex, segFrac) < 0) {
367
						// otherwise, save this as new minimum
368
						minComponentIndex = candidateComponentIndex;
369
						minSegmentIndex = candidateSegmentIndex;
370
						minFrac = segFrac;
371
						minDistance = segDistance;
372
					}
373
				}
374
			}
375
		}
376
		LinearLocation loc = new LinearLocation(minComponentIndex,
377
				minSegmentIndex, minFrac);
378
		return loc;
379
	}
380

  
381
	private static double segmentFraction(LineSegment seg, Coordinate inputPt) {
382
		double segFrac = seg.projectionFactor(inputPt);
383
		if (segFrac < 0.0)
384
			segFrac = 0.0;
385
		else if (segFrac > 1.0)
386
			segFrac = 1.0;
387
		return segFrac;
388
	}
389

  
390 363
}
trunk/libraries/libTopology/src/org/gvsig/jts/GeometryCracker.java
44 44
	/*
45 45
	 * This code is extracted from the class LineStringSnapper of JTS 
46 46
	 * */
47
	public Coordinate[] crackTo(Coordinate[] srcPts, Coordinate[] snapPts) {
47
	private Coordinate[] crackTo(Coordinate[] srcPts, Coordinate[] snapPts) {
48 48
		CoordinateList coordList = new CoordinateList(srcPts);
49 49
		crackSegments(coordList, snapPts);
50 50
		Coordinate[] newPts = coordList.toCoordinateArray();
trunk/libraries/libTopology/src/org/gvsig/jts/RobustLengthIndexedLine.java
1
/*
2
 * Created on 07-sep-2007
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
 * Revision 1.1  2007-09-09 11:44:09  azabala
49
 * Improvements to JTS (robustness problems)
50
 *
51
 *
52
 */
53
package org.gvsig.jts;
54

  
55
import com.vividsolutions.jts.geom.Coordinate;
56
import com.vividsolutions.jts.geom.Geometry;
57
import com.vividsolutions.jts.geom.LineSegment;
58
import com.vividsolutions.jts.geom.PrecisionModel;
59
import com.vividsolutions.jts.linearref.LengthIndexedLine;
60
import com.vividsolutions.jts.linearref.LinearIterator;
61

  
62
/**
63
 * Implementation of LengthIndexedLine to avoid robustness problems.
64
 * 
65
 * TODO If JTS official implementation of LenghtIndexedLine solve the problem
66
 * that has been already reported about precission robustness, DELETE THIS CLASS
67
 * 
68
 * @author azabala
69
 * 
70
 */
71
public class RobustLengthIndexedLine extends LengthIndexedLine {
72

  
73
	/**
74
	 * Superclass has no methods to expose linearGeom, and is private, so we
75
	 * need to mantain a reference here
76
	 */
77
	private Geometry linearGeom;
78

  
79
	public RobustLengthIndexedLine(Geometry arg0) {
80
		super(arg0);
81
		this.linearGeom = arg0;
82
		
83
	}
84

  
85
	public double indexOf(Coordinate pt) {
86
		return indexOfFromStart(pt, -1);
87
	}
88

  
89
	public double indexOfAfter(Coordinate pt, double minIndex) {
90
		if (minIndex < 0.0)
91
			return indexOf(pt);
92
		double endIndex = linearGeom.getLength();
93
		if (endIndex < minIndex)
94
			return endIndex;
95
		double closestAfter = indexOfFromStart(pt, minIndex);
96
		return closestAfter;
97
	}
98

  
99
	/**
100
	 * Return the first index ocurrence of the given coordinate grater than
101
	 * minIndex.
102
	 */
103

  
104
	private double indexOfFromStart(Coordinate inputPt, double minIndex) {
105
		double minDistance = Double.MAX_VALUE;
106
		double ptMeasure = minIndex;
107
		double segmentStartMeasure = 0.0;
108
		LineSegment seg = new LineSegment();
109
		LinearIterator it = new LinearIterator(linearGeom);
110
		while (it.hasNext()) {
111
			if (!it.isEndOfLine()) {
112
				seg.p0 = it.getSegmentStart();
113
				seg.p1 = it.getSegmentEnd();
114
				double segDistance = seg.distance(inputPt);
115
/*
116
 * these two lines of code are the only novelties respect to LenghtIndexedLine
117
 */
118
				PrecisionModel pm = linearGeom.getPrecisionModel();
119
				segDistance = pm.makePrecise(segDistance);
120
/*
121
 * FIXME Remove them if JTS solve the problem
122
 */
123
				double segMeasureToPt = segmentNearestMeasure(seg, inputPt,
124
						segmentStartMeasure);
125

  
126
				if (segDistance < minDistance && segMeasureToPt > minIndex) {
127
					ptMeasure = segMeasureToPt;
128
					minDistance = segDistance;
129
				}
130
				segmentStartMeasure += seg.getLength();
131
			}
132
			it.next();
133
		}
134
		return ptMeasure;
135
	}
136

  
137
	private double segmentNearestMeasure(LineSegment seg, Coordinate inputPt,
138
			double segmentStartMeasure) {
139
		// found new minimum, so compute location distance of point
140
		double projFactor = seg.projectionFactor(inputPt);
141
		if (projFactor <= 0.0)
142
			return segmentStartMeasure;
143
		if (projFactor <= 1.0)
144
			return segmentStartMeasure + projFactor * seg.getLength();
145
		// projFactor > 1.0
146
		return segmentStartMeasure + seg.getLength();
147
	}
148

  
149
}
0 150

  

Also available in: Unified diff