Make nogo weight proportional to nogo distance

Compute the nogo cost as proportional to the length of the segment
inside the nogo area.
This commit is contained in:
Phyks (Lucas Verney) 2018-12-03 00:34:21 +01:00
parent 3479fd7323
commit 2591f22348
7 changed files with 347 additions and 34 deletions

View file

@ -0,0 +1,117 @@
package btools.router;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import btools.util.CheapRulerSingleton;
public class OsmNodeNamedTest {
static int toOsmLon(double lon) {
return (int)( ( lon + 180. ) / CheapRulerSingleton.ILATLNG_TO_LATLNG + 0.5);
}
static int toOsmLat(double lat) {
return (int)( ( lat + 90. ) / CheapRulerSingleton.ILATLNG_TO_LATLNG + 0.5);
}
@Test
public void testDistanceWithinRadius() {
// Segment ends
int lon1, lat1, lon2, lat2;
// Circle definition
OsmNodeNamed node = new OsmNodeNamed();
// Center
node.ilon = toOsmLon(2.334243);
node.ilat = toOsmLat(48.824017);
// Radius
node.radius = 30 / 110984.;
// Check distance within radius is correctly computed if the segment passes through the center
lon1 = toOsmLon(2.332559);
lat1 = toOsmLat(48.823822);
lon2 = toOsmLon(2.335018);
lat2 = toOsmLat(48.824105);
double totalSegmentLength = CheapRulerSingleton.distance(lon1, lat1, lon2, lat2);
assertEquals(
"Works for segment aligned with the nogo center",
2 * node.radius * 110984.,
node.distanceWithinRadius(lon1, lat1, lon2, lat2, totalSegmentLength),
0.01 * (2 * node.radius * 110984.)
);
// Check distance within radius is correctly computed for a given circle
node.ilon = toOsmLon(2.33438);
node.ilat = toOsmLat(48.824275);
assertEquals(
"Works for a segment with no particular properties",
27.5,
node.distanceWithinRadius(lon1, lat1, lon2, lat2, totalSegmentLength),
0.1 * 27.5
);
// Check distance within radius is the same if we reverse start and end point
assertEquals(
"Works if we switch firs and last point",
node.distanceWithinRadius(lon2, lat2, lon1, lat1, totalSegmentLength),
node.distanceWithinRadius(lon1, lat1, lon2, lat2, totalSegmentLength),
0.01
);
// Check distance within radius is correctly computed if a point is inside the circle
lon2 = toOsmLon(2.334495);
lat2 = toOsmLat(48.824045);
totalSegmentLength = CheapRulerSingleton.distance(lon1, lat1, lon2, lat2);
assertEquals(
"Works if last point is within the circle",
17,
node.distanceWithinRadius(lon1, lat1, lon2, lat2, totalSegmentLength),
0.1 * 17
);
lon1 = toOsmLon(2.334495);
lat1 = toOsmLat(48.824045);
lon2 = toOsmLon(2.335018);
lat2 = toOsmLat(48.824105);
totalSegmentLength = CheapRulerSingleton.distance(lon1, lat1, lon2, lat2);
assertEquals(
"Works if first point is within the circle",
9,
node.distanceWithinRadius(lon1, lat1, lon2, lat2, totalSegmentLength),
0.1 * 9
);
lon1 = toOsmLon(2.33427);
lat1 = toOsmLat(48.82402);
lon2 = toOsmLon(2.334587);
lat2 = toOsmLat(48.824061);
totalSegmentLength = CheapRulerSingleton.distance(lon1, lat1, lon2, lat2);
assertEquals(
"Works if both points are within the circle",
25,
node.distanceWithinRadius(lon1, lat1, lon2, lat2, totalSegmentLength),
0.1 * 25
);
// Check distance within radius is correctly computed if both points are on
// the same side of the center.
// Note: the only such case possible is with one point outside and one
// point within the circle, as we expect the segment to have a non-empty
// intersection with the circle.
lon1 = toOsmLon(2.332559);
lat1 = toOsmLat(48.823822);
lon2 = toOsmLon(2.33431);
lat2 = toOsmLat(48.824027);
totalSegmentLength = CheapRulerSingleton.distance(lon1, lat1, lon2, lat2);
assertEquals(
"Works if both points are on the same side of the circle center",
5,
node.distanceWithinRadius(lon1, lat1, lon2, lat2, totalSegmentLength),
0.1 * 5
);
}
}

View file

@ -30,8 +30,8 @@ import btools.util.CheapRulerSingleton;
public class OsmNogoPolygonTest {
static final int offset_x = 11000000;
static final int offset_y = 50000000;
static final int OFFSET_X = 11000000;
static final int OFFSET_Y = 50000000;
static OsmNogoPolygon polygon;
static OsmNogoPolygon polyline;
@ -39,11 +39,11 @@ public class OsmNogoPolygonTest {
static final double[] lons = { 1.0, 1.0, 0.5, 0.5, 1.0, 1.0, -1.1, -1.0 };
static final double[] lats = { -1.0, -0.1, -0.1, 0.1, 0.1, 1.0, 1.1, -1.0 };
static int toOsmLon(double lon) {
static int toOsmLon(double lon, int offset_x) {
return (int)( ( lon + 180. ) *1000000. + 0.5)+offset_x; // see ServerHandler.readPosition()
}
static int toOsmLat(double lat) {
static int toOsmLat(double lat, int offset_y) {
return (int)( ( lat + 90. ) *1000000. + 0.5)+offset_y;
}
@ -51,11 +51,11 @@ public class OsmNogoPolygonTest {
public static void setUp() throws Exception {
polygon = new OsmNogoPolygon(true);
for (int i = 0; i<lons.length; i++) {
polygon.addVertex(toOsmLon(lons[i]),toOsmLat(lats[i]));
polygon.addVertex(toOsmLon(lons[i], OFFSET_X),toOsmLat(lats[i], OFFSET_Y));
}
polyline = new OsmNogoPolygon(false);
for (int i = 0; i<lons.length; i++) {
polyline.addVertex(toOsmLon(lons[i]),toOsmLat(lats[i]));
polyline.addVertex(toOsmLon(lons[i], OFFSET_X),toOsmLat(lats[i], OFFSET_Y));
}
}
@ -72,8 +72,8 @@ public class OsmNogoPolygonTest {
polygon.calcBoundingCircle();
double r = polygon.radius;
for (int i=0; i<lons.length; i++) {
double dpx = (toOsmLon(lons[i]) - polygon.ilon) * dlon2m;
double dpy = (toOsmLon(lats[i]) - polygon.ilon) * dlat2m;
double dpx = (toOsmLon(lons[i], OFFSET_X) - polygon.ilon) * dlon2m;
double dpy = (toOsmLat(lats[i], OFFSET_Y) - polygon.ilat) * dlat2m;
double r1 = Math.sqrt(dpx * dpx + dpy * dpy);
double diff = r-r1;
assertTrue("i: "+i+" r("+r+") >= r1("+r1+")", diff >= 0);
@ -81,8 +81,8 @@ public class OsmNogoPolygonTest {
polyline.calcBoundingCircle();
r = polyline.radius;
for (int i=0; i<lons.length; i++) {
double dpx = (toOsmLon(lons[i]) - polyline.ilon) * dlon2m;
double dpy = (toOsmLon(lats[i]) - polyline.ilon) * dlat2m;
double dpx = (toOsmLon(lons[i], OFFSET_X) - polyline.ilon) * dlon2m;
double dpy = (toOsmLat(lats[i], OFFSET_Y) - polyline.ilat) * dlat2m;
double r1 = Math.sqrt(dpx * dpx + dpy * dpy);
double diff = r-r1;
assertTrue("i: "+i+" r("+r+") >= r1("+r1+")", diff >= 0);
@ -96,7 +96,7 @@ public class OsmNogoPolygonTest {
boolean[] within = { true, false, false, false, false, true, true, true, true, true, };
for (int i=0; i<plons.length; i++) {
assertEquals("("+plons[i]+","+plats[i]+")",within[i],polygon.isWithin(toOsmLon(plons[i]), toOsmLat(plats[i])));
assertEquals("("+plons[i]+","+plats[i]+")",within[i],polygon.isWithin(toOsmLon(plons[i], OFFSET_X), toOsmLat(plats[i], OFFSET_Y)));
}
}
@ -109,7 +109,7 @@ public class OsmNogoPolygonTest {
boolean[] within = { false, false, false, true, true, true, false, true, true, true };
for (int i=0; i<p0lons.length; i++) {
assertEquals("("+p0lons[i]+","+p0lats[i]+")-("+p1lons[i]+","+p1lats[i]+")",within[i],polygon.intersects(toOsmLon(p0lons[i]), toOsmLat(p0lats[i]), toOsmLon(p1lons[i]), toOsmLat(p1lats[i])));
assertEquals("("+p0lons[i]+","+p0lats[i]+")-("+p1lons[i]+","+p1lats[i]+")",within[i],polygon.intersects(toOsmLon(p0lons[i], OFFSET_X), toOsmLat(p0lats[i], OFFSET_Y), toOsmLon(p1lons[i], OFFSET_X), toOsmLat(p1lats[i], OFFSET_Y)));
}
}
@ -122,7 +122,7 @@ public class OsmNogoPolygonTest {
boolean[] within = { false, false, false, true, true, true, false, true, true, false };
for (int i=0; i<p0lons.length; i++) {
assertEquals("("+p0lons[i]+","+p0lats[i]+")-("+p1lons[i]+","+p1lats[i]+")",within[i],polyline.intersects(toOsmLon(p0lons[i]), toOsmLat(p0lats[i]), toOsmLon(p1lons[i]), toOsmLat(p1lats[i])));
assertEquals("("+p0lons[i]+","+p0lats[i]+")-("+p1lons[i]+","+p1lats[i]+")",within[i],polyline.intersects(toOsmLon(p0lons[i], OFFSET_X), toOsmLat(p0lats[i], OFFSET_Y), toOsmLon(p1lons[i], OFFSET_X), toOsmLat(p1lats[i], OFFSET_Y)));
}
}
@ -144,4 +144,57 @@ public class OsmNogoPolygonTest {
assertFalse(OsmNogoPolygon.isOnLine(0,-10, 10,10, 20,30));
assertFalse(OsmNogoPolygon.isOnLine(30,50, 10,10, 20,30));
}
@Test
public void testDistanceWithinPolygon() {
// Testing polygon
final double[] lons = { 2.333523, 2.333432, 2.333833, 2.333983, 2.334815, 2.334766, 2.333523 };
final double[] lats = { 48.823778, 48.824091, 48.82389, 48.824165, 48.824232, 48.82384, 48.823778 };
OsmNogoPolygon polygon = new OsmNogoPolygon(true);
for (int i = 0; i < lons.length; i++) {
polygon.addVertex(toOsmLon(lons[i], 0), toOsmLat(lats[i], 0));
}
// Check with a segment with a single intersection with the polygon
int lon1 = toOsmLon(2.33308732509613, 0);
int lat1 = toOsmLat(48.8238790443901, 0);
int lon2 = toOsmLon(2.33378201723099, 0);
int lat2 = toOsmLat(48.8239585098974, 0);
assertEquals(
"Should give the correct length for a segment with a single intersection",
17.5,
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * 17.5
);
// Check with a segment crossing multiple times the polygon
lon2 = toOsmLon(2.33488172292709, 0);
lat2 = toOsmLat(48.8240891862353, 0);
assertEquals(
"Should give the correct length for a segment with multiple intersections",
85,
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * 85
);
// Check that it works when a point is within the polygon
lon2 = toOsmLon(2.33433187007904, 0);
lat2 = toOsmLat(48.8240238480664, 0);
assertEquals(
"Should give the correct length when last point is within the polygon",
50,
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * 50
);
lon1 = toOsmLon(2.33433187007904, 0);
lat1 = toOsmLat(48.8240238480664, 0);
lon2 = toOsmLon(2.33488172292709, 0);
lat2 = toOsmLat(48.8240891862353, 0);
assertEquals(
"Should give the correct length when first point is within the polygon",
35,
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * 35
);
}
}