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

@ -6,6 +6,7 @@
package btools.router;
import btools.mapaccess.OsmNode;
import btools.util.CheapRulerSingleton;
public class OsmNodeNamed extends OsmNode
{
@ -24,6 +25,55 @@ public class OsmNodeNamed extends OsmNode
}
}
public double distanceWithinRadius(int lon1, int lat1, int lon2, int lat2, double totalSegmentLength) {
double[] lonlat2m = CheapRulerSingleton.getLonLatToMeterScales( (lat1 + lat2) >> 1 );
double realRadius = radius * 110984.;
boolean isFirstPointWithinCircle = CheapRulerSingleton.distance(lon1, lat1, ilon, ilat) < realRadius;
boolean isLastPointWithinCircle = CheapRulerSingleton.distance(lon2, lat2, ilon, ilat) < realRadius;
// First point is within the circle
if (isFirstPointWithinCircle) {
// Last point is within the circle
if (isLastPointWithinCircle) {
return totalSegmentLength;
}
// Last point is not within the circle
// Just swap points and go on with first first point not within the
// circle now.
// Swap longitudes
int tmp = lon2;
lon2 = lon1;
lon1 = tmp;
// Swap latitudes
tmp = lat2;
lat2 = lat1;
lat1 = tmp;
// Fix boolean values
isLastPointWithinCircle = isFirstPointWithinCircle;
isFirstPointWithinCircle = false;
}
// Distance between the initial point and projection of center of
// the circle on the current segment.
double initialToProject = (
(lon2 - lon1) * (ilon - lon1) * lonlat2m[0] * lonlat2m[0]
+ (lat2 - lat1) * (ilat - lat1) * lonlat2m[1] * lonlat2m[1]
) / totalSegmentLength;
// Distance between the initial point and the center of the circle.
double initialToCenter = CheapRulerSingleton.distance(ilon, ilat, lon1, lat1);
// Half length of the segment within the circle
double halfDistanceWithin = Math.sqrt(
realRadius*realRadius - (
initialToCenter*initialToCenter -
initialToProject*initialToProject
)
);
// Last point is within the circle
if (isLastPointWithinCircle) {
return halfDistanceWithin + (totalSegmentLength - initialToProject);
}
return 2 * halfDistanceWithin;
}
public static OsmNodeNamed decodeNogo( String s )
{
OsmNodeNamed n = new OsmNodeNamed();

View file

@ -297,6 +297,90 @@ public class OsmNogoPolygon extends OsmNodeNamed
return wn != 0;
}
/**
* Compute the length of the segment within the polygon.
*
* @param lon1 Integer longitude of the first point of the segment.
* @param lat1 Integer latitude of the first point of the segment.
* @param lon2 Integer longitude of the last point of the segment.
* @param lat2 Integer latitude of the last point of the segment.
*
* @return The length, in meters, of the portion of the segment which is
* included in the polygon.
*/
public double distanceWithinPolygon(int lon1, int lat1, int lon2, int lat2) {
double distance = 0.;
// Extremities of the segments
final Point p1 = new Point (lon1, lat1);
final Point p2 = new Point (lon2, lat2);
Point previousIntersectionOnSegment = null;
if (isWithin(lon1, lat1))
{
// Start point of the segment is within the polygon, this is the first
// "intersection".
previousIntersectionOnSegment = p1;
}
// Loop over edges of the polygon to find intersections
int i_last = points.size() - 1;
for (int i = (isClosed ? 0 : 1), j = (isClosed ? i_last : 0); i <= i_last; j = i++)
{
Point edgePoint1 = points.get(j);
Point edgePoint2 = points.get(i);
int intersectsEdge = intersect2D_2Segments(p1, p2, edgePoint1, edgePoint2);
if (intersectsEdge == 1)
{
// Intersects in a single point
// Let's find this intersection point
int xdiffSegment = lon1 - lon2;
int xdiffEdge = edgePoint1.x - edgePoint2.x;
int ydiffSegment = lat1 - lat2;
int ydiffEdge = edgePoint1.y - edgePoint2.y;
int div = xdiffSegment * ydiffEdge - xdiffEdge * ydiffSegment;
long dSegment = (long) lon1 * (long) lat2 - (long) lon2 * (long) lat1;
long dEdge = (long) edgePoint1.x * (long) edgePoint2.y - (long) edgePoint2.x * (long) edgePoint1.y;
// Coordinates of the intersection
Point intersection = new Point(
(int) ((dSegment * xdiffEdge - dEdge * xdiffSegment) / div),
(int) ((dSegment * ydiffEdge - dEdge * ydiffSegment) / div)
);
if (
previousIntersectionOnSegment != null
&& isWithin(
(intersection.x + previousIntersectionOnSegment.x) >> 1,
(intersection.y + previousIntersectionOnSegment.y) >> 1
)
) {
// There was a previous match within the polygon and this part of the
// segment is within the polygon.
distance += CheapRulerSingleton.distance(
previousIntersectionOnSegment.x, previousIntersectionOnSegment.y,
intersection.x, intersection.y
);
}
previousIntersectionOnSegment = intersection;
}
else if (intersectsEdge == 2) {
// Segment and edge overlaps
distance += CheapRulerSingleton.distance(lon1, lat1, lon2, lat2);
}
}
if (
previousIntersectionOnSegment != null
&& isWithin(lon2, lat2)
) {
// Last point is within the polygon, add the remaining missing distance.
distance += CheapRulerSingleton.distance(
previousIntersectionOnSegment.x, previousIntersectionOnSegment.y,
lon2, lat2
);
}
return distance;
}
/* Copyright 2001 softSurfer, 2012 Dan Sunday, 2018 Norbert Truchsess
This code may be freely used and modified for any purpose providing that
this copyright notice is included with it. SoftSurfer makes no warranty for

View file

@ -143,7 +143,7 @@ abstract class OsmPath implements OsmLinkHolder
boolean recordTransferNodes = detailMode || rc.countTraffic;
rc.nogomatch = null;
rc.nogoCost = 0.;
// extract the 3 positions of the first section
int lon0 = origin.originLon;
@ -425,13 +425,13 @@ abstract class OsmPath implements OsmLinkHolder
originElement.message = message;
}
}
if ( rc.nogomatch != null )
if ( rc.nogoCost < 0)
{
if ( Double.isNaN(rc.nogomatch.nogoWeight) ) {
cost = -1;
} else {
cost += rc.nogomatch.nogoWeight;
}
cost = -1;
}
else
{
cost += rc.nogoCost;
}
return;
}
@ -464,14 +464,14 @@ abstract class OsmPath implements OsmLinkHolder
}
// check for nogo-matches (after the *actual* start of segment)
if ( rc.nogomatch != null )
if ( rc.nogoCost < 0)
{
if ( Double.isNaN(rc.nogomatch.nogoWeight) ) {
cost = -1;
return;
} else {
cost += rc.nogomatch.nogoWeight;
}
cost = -1;
return;
}
else
{
cost += rc.nogoCost;
}
// add target-node costs

View file

@ -194,7 +194,7 @@ public final class RoutingContext
public boolean startDirectionValid;
private double cosangle;
public OsmNodeNamed nogomatch = null;
public double nogoCost = 0.;
public boolean isEndpoint = false;
public boolean shortestmatch = false;
@ -344,10 +344,19 @@ public final class RoutingContext
}
if ( nogo.isNogo )
{
if (!(nogo instanceof OsmNogoPolygon)
|| ((OsmNogoPolygon)nogo).intersects(lon1, lat1, lon2, lat2))
if (Double.isNaN(nogo.nogoWeight))
{
nogomatch = nogo;
// Nogo is default nogo (ignore completely)
nogoCost = -1;
}
else if (!(nogo instanceof OsmNogoPolygon)) {
// nogo is a circle, compute distance within the circle
nogoCost = nogo.distanceWithinRadius(lon1, lat1, lon2, lat2, d) * nogo.nogoWeight;
}
else if (((OsmNogoPolygon)nogo).intersects(lon1, lat1, lon2, lat2))
{
// nogo is a polygon, compute distance within the polygon
nogoCost = ((OsmNogoPolygon)nogo).distanceWithinPolygon(lon1, lat1, lon2, lat2) * nogo.nogoWeight;
}
}
else
@ -388,7 +397,7 @@ public final class RoutingContext
}
else
{
nogomatch = null;
nogoCost = 0.;
lon1 = ilonshortest;
lat1 = ilatshortest;
}