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:
parent
3479fd7323
commit
2591f22348
7 changed files with 347 additions and 34 deletions
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue