Skip to content

Commit 551faf9

Browse files
author
Peter
committed
fixing cross boundary edge case graphhopper#667
1 parent 4092e13 commit 551faf9

File tree

9 files changed

+152
-223
lines changed

9 files changed

+152
-223
lines changed

core/src/main/java/com/graphhopper/reader/OSMReader.java

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -194,30 +194,24 @@ void preProcess( File osmFile )
194194
+ getNodeMap().getMemoryUsage() + "MB) " + Helper.getMemInfo());
195195
}
196196
}
197-
} else
197+
} else if (item.isType(OSMElement.RELATION))
198198
{
199-
if (item.isType(OSMElement.RELATION))
200-
{
201-
final OSMRelation relation = (OSMRelation) item;
202-
if (!relation.isMetaRelation() && relation.hasTag("type", "route"))
203-
prepareWaysWithRelationInfo(relation);
199+
final OSMRelation relation = (OSMRelation) item;
200+
if (!relation.isMetaRelation() && relation.hasTag("type", "route"))
201+
prepareWaysWithRelationInfo(relation);
204202

205-
if (relation.hasTag("type", "restriction"))
206-
prepareRestrictionRelation(relation);
203+
if (relation.hasTag("type", "restriction"))
204+
prepareRestrictionRelation(relation);
207205

208-
if (++tmpRelationCounter % 50000 == 0)
209-
{
210-
logger.info(nf(tmpRelationCounter) + " (preprocess), osmWayMap:" + nf(getRelFlagsMap().size())
211-
+ " " + Helper.getMemInfo());
212-
}
213-
} else
206+
if (++tmpRelationCounter % 50000 == 0)
214207
{
215-
if (item.isType(OSMElement.FILEHEADER))
216-
{
217-
final OSMFileHeader fileHeader = (OSMFileHeader) item;
218-
osmDataDate = Helper.createFormatter().parse(fileHeader.getTag("timestamp"));
219-
}
208+
logger.info(nf(tmpRelationCounter) + " (preprocess), osmWayMap:" + nf(getRelFlagsMap().size())
209+
+ " " + Helper.getMemInfo());
220210
}
211+
} else if (item.isType(OSMElement.FILEHEADER))
212+
{
213+
final OSMFileHeader fileHeader = (OSMFileHeader) item;
214+
osmDataDate = Helper.createFormatter().parse(fileHeader.getTag("timestamp"));
221215
}
222216

223217
}
@@ -791,10 +785,12 @@ EdgeIteratorState addEdge( int fromIndex, int toIndex, PointList pointList, long
791785
if (pointList.is3D())
792786
{
793787
ele = pointList.getElevation(i);
794-
towerNodeDistance += distCalc3D.calcDist(prevLat, prevLon, prevEle, lat, lon, ele);
788+
if (!distCalc.isCrossBoundary(lon, prevLon))
789+
towerNodeDistance += distCalc3D.calcDist(prevLat, prevLon, prevEle, lat, lon, ele);
795790
prevEle = ele;
796-
} else
791+
} else if (!distCalc.isCrossBoundary(lon, prevLon))
797792
towerNodeDistance += distCalc.calcDist(prevLat, prevLon, lat, lon);
793+
798794
prevLat = lat;
799795
prevLon = lon;
800796
if (nodes > 2 && i < nodes - 1)
@@ -870,13 +866,10 @@ private int handlePillarNode( int tmpNode, long osmId, PointList pointList, bool
870866
// convert pillarNode type to towerNode, make pillar values invalid
871867
pillarInfo.setNode(tmpNode, Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE);
872868
tmpNode = addTowerNode(osmId, lat, lon, ele);
873-
} else
874-
{
875-
if (pointList.is3D())
876-
pointList.add(lat, lon, ele);
877-
else
878-
pointList.add(lat, lon);
879-
}
869+
} else if (pointList.is3D())
870+
pointList.add(lat, lon, ele);
871+
else
872+
pointList.add(lat, lon);
880873

881874
return (int) tmpNode;
882875
}

core/src/main/java/com/graphhopper/storage/index/BresenhamLine.java

Lines changed: 5 additions & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -30,92 +30,12 @@
3030
*/
3131
public class BresenhamLine
3232
{
33-
public static void calcPoints( int y1, int x1, int y2, int x2,
34-
PointEmitter emitter )
33+
public static void calcPoints( int y1, int x1, int y2, int x2, PointEmitter emitter )
3534
{
3635
bresenham(y1, x1, y2, x2, emitter);
3736
}
3837

39-
public static void voxelTraversal( double y1, double x1, double y2, double x2,
40-
PointEmitter emitter )
41-
{
42-
// edge case
43-
x1 = fix(x1);
44-
y1 = fix(y1);
45-
x2 = fix(x2);
46-
y2 = fix(y2);
47-
48-
int x = (int) x1, y = (int) y1;
49-
int endX = (int) x2, endY = (int) y2;
50-
51-
// deltaX and Y is how far we have to move in ray direction until we find a new cell in x or y direction
52-
// y = u + t * v, where u=(x1,x2) and v=(stepX,stepY) is the direction vector
53-
final double gridCellWidth = 1, gridCellHeight = 1;
54-
55-
double deltaX = gridCellWidth / Math.abs(x2 - x1);
56-
int stepX = (int) Math.signum(x2 - x1);
57-
double tmp = frac(x1 / gridCellWidth);
58-
double maxX = deltaX * (1.0 - tmp);
59-
60-
double deltaY = gridCellHeight / Math.abs(y2 - y1);
61-
int stepY = (int) Math.signum(y2 - y1);
62-
tmp = frac(y1 / gridCellHeight);
63-
double maxY = deltaY * (1.0 - tmp);
64-
65-
boolean reachedY = false, reachedX = false;
66-
67-
emitter.set(y, x);
68-
// trace primary ray
69-
while (!(reachedX && reachedY))
70-
{
71-
if (maxX < maxY)
72-
{
73-
maxX += deltaX;
74-
x += stepX;
75-
} else
76-
{
77-
maxY += deltaY;
78-
y += stepY;
79-
}
80-
81-
emitter.set(y, x);
82-
83-
if (stepX > 0.0)
84-
{
85-
if (x >= endX)
86-
reachedX = true;
87-
88-
} else if (x <= endX)
89-
{
90-
reachedX = true;
91-
}
92-
93-
if (stepY > 0.0)
94-
{
95-
if (y >= endY)
96-
reachedY = true;
97-
98-
} else if (y <= endY)
99-
{
100-
reachedY = true;
101-
}
102-
}
103-
}
104-
105-
static final double fix( double val )
106-
{
107-
if (frac(val) == 0)
108-
return val + 0.1;
109-
return val;
110-
}
111-
112-
static final double frac( double val )
113-
{
114-
return val - (int) val;
115-
}
116-
117-
public static void bresenham( int y1, int x1, int y2, int x2,
118-
PointEmitter emitter )
38+
public static void bresenham( int y1, int x1, int y2, int x2, PointEmitter emitter )
11939
{
12040
boolean latIncreasing = y1 < y2;
12141
boolean lonIncreasing = x1 < x2;
@@ -144,111 +64,15 @@ public static void bresenham( int y1, int x1, int y2, int x2,
14464
}
14565
}
14666

147-
public static void xiaolinWu( double y1, double x1, double y2, double x2,
148-
PointEmitter emitter )
149-
{
150-
double dx = x2 - x1;
151-
double dy = y2 - y1;
152-
153-
if (Math.abs(dx) > Math.abs(dy))
154-
{
155-
if (x2 < x1)
156-
{
157-
// algo only handles rightwards so swap
158-
double tmp = x1;
159-
x1 = x2;
160-
x2 = tmp;
161-
tmp = y1;
162-
y1 = y2;
163-
y2 = tmp;
164-
}
165-
166-
double gradient = dy / dx;
167-
// orig: round
168-
int xend = (int) (x1);
169-
double yend = y1 + gradient * (xend - x1);
170-
int xpxl1 = xend;
171-
int ypxl1 = (int) yend;
172-
173-
// first endpoint
174-
emitter.set(ypxl1, xpxl1);
175-
emitter.set(ypxl1 + 1, xpxl1);
176-
double intery = yend + gradient;
177-
178-
// orig: round
179-
xend = (int) (x2);
180-
yend = y2 + gradient * (xend - x2);
181-
int xpxl2 = xend;
182-
int ypxl2 = (int) yend;
183-
184-
// second endpoint
185-
emitter.set(ypxl2, xpxl2);
186-
emitter.set(ypxl2 + 1, xpxl2);
187-
188-
// all the points between the endpoints
189-
for (int x = xpxl1 + 1; x <= xpxl2 - 1; ++x)
190-
{
191-
emitter.set((int) intery, x);
192-
emitter.set((int) intery + 1, x);
193-
intery += gradient;
194-
}
195-
} else
196-
{
197-
if (y2 < y1)
198-
{
199-
// algo only handles topwards so swap
200-
double tmp = x1;
201-
x1 = x2;
202-
x2 = tmp;
203-
tmp = y1;
204-
y1 = y2;
205-
y2 = tmp;
206-
}
207-
208-
double gradient = dx / dy;
209-
// orig: round
210-
int yend = (int) (y1);
211-
double xend = x1 + gradient * (yend - y1);
212-
int ypxl1 = yend;
213-
int xpxl1 = (int) xend;
214-
215-
// first endpoint
216-
emitter.set(ypxl1, xpxl1);
217-
emitter.set(ypxl1 + 1, xpxl1);
218-
double interx = xend + gradient;
219-
220-
// orig: round
221-
yend = (int) (y2);
222-
xend = x2 + gradient * (yend - y2);
223-
int ypxl2 = yend;
224-
int xpxl2 = (int) xend;
225-
226-
// second endpoint
227-
emitter.set(ypxl2, xpxl2);
228-
emitter.set(ypxl2 + 1, xpxl2);
229-
230-
// all the points between the endpoints
231-
for (int y = ypxl1 + 1; y <= ypxl2 - 1; ++y)
232-
{
233-
emitter.set(y, (int) interx);
234-
emitter.set(y, (int) interx + 1);
235-
interx += gradient;
236-
}
237-
}
238-
}
239-
67+
/**
68+
* Calls the Bresenham algorithm but make it working for double values
69+
*/
24070
public static void calcPoints( final double lat1, final double lon1,
24171
final double lat2, final double lon2,
24272
final PointEmitter emitter,
24373
final double offsetLat, final double offsetLon,
24474
final double deltaLat, final double deltaLon )
24575
{
246-
// double y1 = (lat1 - offsetLat) / deltaLat;
247-
// double x1 = (lon1 - offsetLon) / deltaLon;
248-
// double y2 = (lat2 - offsetLat) / deltaLat;
249-
// double x2 = (lon2 - offsetLon) / deltaLon;
250-
// for xiaolinWu or calcPoints
251-
25276
// round to make results of bresenham closer to correct solution
25377
int y1 = (int) ((lat1 - offsetLat) / deltaLat);
25478
int x1 = (int) ((lon1 - offsetLon) / deltaLon);

core/src/main/java/com/graphhopper/storage/index/LocationIndexTree.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -431,9 +431,13 @@ public void set( double lat, double lon )
431431
addNode(root, nodeA, 0, keyPart, key);
432432
}
433433
};
434-
BresenhamLine.calcPoints(lat1, lon1, lat2, lon2, pointEmitter,
435-
graph.getBounds().minLat, graph.getBounds().minLon,
436-
deltaLat, deltaLon);
434+
435+
if (!distCalc.isCrossBoundary(lon1, lon2))
436+
{
437+
BresenhamLine.calcPoints(lat1, lon1, lat2, lon2, pointEmitter,
438+
graph.getBounds().minLat, graph.getBounds().minLon,
439+
deltaLat, deltaLon);
440+
}
437441
}
438442

439443
void addNode( InMemEntry entry, int nodeId, int depth, long keyPart, long key )
@@ -922,6 +926,13 @@ protected boolean checkAdjacent( EdgeIteratorState currEdge )
922926
double wayLat = pointList.getLatitude(pointIndex);
923927
double wayLon = pointList.getLongitude(pointIndex);
924928
QueryResult.Position pos = QueryResult.Position.EDGE;
929+
if (distCalc.isCrossBoundary(tmpLon, wayLon))
930+
{
931+
tmpLat = wayLat;
932+
tmpLon = wayLon;
933+
continue;
934+
}
935+
925936
if (distCalc.validEdgeDistance(queryLat, queryLon, tmpLat, tmpLon, wayLat, wayLon))
926937
{
927938
tmpNormedDist = distCalc.calcNormalizedEdgeDistance(queryLat, queryLon,

core/src/main/java/com/graphhopper/util/DistanceCalc.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public interface DistanceCalc
6363
* r
6464
* .
6565
* a-------b
66-
*
66+
* <p>
6767
* case 2:
6868
* r
6969
* .
@@ -91,4 +91,10 @@ boolean validEdgeDistance( double r_lat_deg, double r_lon_deg,
9191
GHPoint calcCrossingPointToEdge( double r_lat_deg, double r_lon_deg,
9292
double a_lat_deg, double a_lon_deg,
9393
double b_lat_deg, double b_lon_deg );
94+
95+
/**
96+
* Simple heuristic to detect if the specified two points are crossing the boundary +-180°. See
97+
* #667
98+
*/
99+
boolean isCrossBoundary( double lon1, double lon2 );
94100
}

core/src/main/java/com/graphhopper/util/DistanceCalcEarth.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ else if (factor < 0)
164164
return calcNormalizedDist(c_lat, c_lon / shrinkFactor, r_lat_deg, r_lon_deg);
165165
}
166166

167-
private double calcShrinkFactor(double a_lat_deg, double b_lat_deg) {
167+
private double calcShrinkFactor( double a_lat_deg, double b_lat_deg )
168+
{
168169
return cos(toRadians((a_lat_deg + b_lat_deg) / 2));
169170
}
170171

@@ -235,6 +236,12 @@ public boolean validEdgeDistance( double r_lat_deg, double r_lon_deg,
235236
return ab_ar > 0 && ab_rb > 0;
236237
}
237238

239+
@Override
240+
public boolean isCrossBoundary( double lon1, double lon2 )
241+
{
242+
return Math.abs(lon1 - lon2) > 300;
243+
}
244+
238245
@Override
239246
public String toString()
240247
{

core/src/test/java/com/graphhopper/reader/OSMReaderTest.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.graphhopper.reader.dem.SRTMProvider;
4141
import com.graphhopper.routing.util.*;
4242
import com.graphhopper.storage.*;
43+
import com.graphhopper.storage.index.QueryResult;
4344
import com.graphhopper.util.EdgeExplorer;
4445
import com.graphhopper.util.EdgeIterator;
4546
import com.graphhopper.util.EdgeIteratorState;
@@ -279,7 +280,7 @@ public void testOneWay()
279280
{
280281
GraphHopper hopper = new GraphHopperTest(file2).importOrLoad();
281282
GraphHopperStorage graph = hopper.getGraphHopperStorage();
282-
283+
283284
assertEquals("2014-01-02T01:10:14Z", graph.getProperties().get("osmreader.data.date"));
284285

285286
int n20 = AbstractGraphStorageTester.getIdOf(graph, 52.0);
@@ -836,4 +837,21 @@ public void testDataDateWithinPBF()
836837

837838
assertEquals("2014-01-02T00:10:14Z", graph.getProperties().get("osmreader.data.date"));
838839
}
840+
841+
@Test
842+
public void testCrossBoundary_issue667()
843+
{
844+
GraphHopper hopper = new GraphHopperTest("test-osm-waterway.xml").importOrLoad();
845+
QueryResult qr = hopper.getLocationIndex().findClosest(0.1, 179.5, EdgeFilter.ALL_EDGES);
846+
assertTrue(qr.isValid());
847+
assertEquals(0.1, qr.getSnappedPoint().lat, 0.1);
848+
assertEquals(179.5, qr.getSnappedPoint().lon, 0.1);
849+
assertEquals(11, qr.getClosestEdge().getDistance() / 1000, 1);
850+
851+
qr = hopper.getLocationIndex().findClosest(0.1, -179.6, EdgeFilter.ALL_EDGES);
852+
assertTrue(qr.isValid());
853+
assertEquals(0.1, qr.getSnappedPoint().lat, 0.1);
854+
assertEquals(-179.6, qr.getSnappedPoint().lon, 0.1);
855+
assertEquals(56, qr.getClosestEdge().getDistance() / 1000, 1);
856+
}
839857
}

0 commit comments

Comments
 (0)