Merge pull request #97 from ntruchsess/NogoPolygons

Nogo polygons / polylines
This commit is contained in:
abrensch 2018-03-07 17:53:10 +01:00 committed by GitHub
commit 45495d8692
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 833 additions and 21 deletions

View file

@ -32,5 +32,10 @@
<artifactId>brouter-expressions</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,461 @@
/**********************************************************************************************
Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
The following methods are based on work of Dan Sunday published at:
http://geomalgorithms.com/a03-_inclusion.html
cn_PnPoly, wn_PnPoly, inSegment, intersect2D_2Segments
**********************************************************************************************/
package btools.router;
import java.util.ArrayList;
import java.util.List;
public class OsmNogoPolygon extends OsmNodeNamed
{
public final static class Point
{
public final int y;
public final int x;
Point(final int lon, final int lat)
{
x = lon;
y = lat;
}
}
public final List<Point> points = new ArrayList<Point>();
public final boolean isClosed;
public OsmNogoPolygon(boolean closed)
{
this.isClosed = closed;
this.isNogo = true;
this.name = "";
}
public final void addVertex(int lon, int lat)
{
points.add(new Point(lon, lat));
}
private final static double coslat(double lat)
{
final double l = (lat - 90000000) * 0.00000001234134; // 0.01234134 = Pi/(sqrt(2)*180)
final double l2 = l*l;
final double l4 = l2*l2;
// final double l6 = l4*l2;
return 1.- l2 + l4 / 6.; // - l6 / 90;
}
/**
* calcBoundingCircle is inspired by the algorithm described on
* http://geomalgorithms.com/a08-_containers.html
* (fast computation of bounding circly in c). It is not as fast (the original
* algorithm runs in linear time), as it may do more iterations but it takes
* into account the coslat-factor being used for the linear approximation that
* is also used in other places of brouter does change when moving the centerpoint
* with each iteration.
* This is done to ensure the calculated radius being used
* in RoutingContext.calcDistance will actually contain the whole polygon.
*
* For reasonable distributed vertices the implemented algorithm runs in O(n*ln(n)).
* As this is only run once on initialization of OsmNogoPolygon this methods
* overall usage of cpu is neglegible in comparism to the cpu-usage of the
* actual routing algoritm.
*/
public void calcBoundingCircle()
{
int cxmin, cxmax, cymin, cymax;
cxmin = cymin = Integer.MAX_VALUE;
cxmax = cymax = Integer.MIN_VALUE;
// first calculate a starting center point as center of boundingbox
for (int i = 0; i < points.size(); i++)
{
final Point p = points.get(i);
if (p.x < cxmin)
{
cxmin = p.x;
}
else if (p.x > cxmax)
{
cxmax = p.x;
}
if (p.y < cymin)
{
cymin = p.y;
}
else if (p.y > cymax)
{
cymax = p.y;
}
}
double cx = (cxmax+cxmin) / 2.0; // center of circle
double cy = (cymax+cymin) / 2.0;
double ccoslat = coslat(cy); // cosin at latitude of center
double rad = 0; // radius
double rad2 = 0; // radius squared;
double dpx = 0; // x-xomponent of vector from center to point
double dpy = 0; // y-component
double dmax2 = 0; // squared lenght of vector from center to point
int i_max = -1;
do
{ // now identify the point outside of the circle that has the greatest distance
for (int i = 0; i < points.size();i++)
{
final Point p = points.get(i);
final double dpix = (p.x - cx) * ccoslat;
final double dpiy = p.y-cy;
final double dist2 = dpix * dpix + dpiy * dpiy;
if (dist2 <= rad2)
{
continue;
}
if (dist2 > dmax2)
{
dmax2 = dist2; // new maximum distance found
dpx = dpix;
dpy = dpiy;
i_max = i;
}
}
if (i_max < 0)
{
break; // leave loop when no point outside the circle is found any more.
}
final double dist = Math.sqrt(dmax2);
final double dd = 0.5 * (dist - rad) / dist;
cx = cx + dd * dpx; // shift center toward point
cy = cy + dd * dpy;
ccoslat = coslat(cy);
final Point p = points.get(i_max); // calculate new radius to just include this point
final double dpix = (p.x - cx) * ccoslat;
final double dpiy = p.y-cy;
dmax2 = rad2 = dpix * dpix + dpiy * dpiy;
rad = Math.sqrt(rad2);
i_max = -1;
}
while (true);
ilon = (int) Math.round(cx);
ilat = (int) Math.round(cy);
dpx = cx - ilon; // rounding error
dpy = cy - ilat;
// compensate rounding error of center-point
radius = (rad + Math.sqrt(dpx * dpx + dpy * dpy)) * 0.000001;
return;
}
/**
* tests whether a segment defined by lon and lat of two points does either
* intersect the polygon or any of the endpoints (or both) are enclosed by
* the polygon. For this test the winding-number algorithm is
* being used. That means a point being within an overlapping region of the
* polygon is also taken as being 'inside' the polygon.
*
* @param lon0 longitude of start point
* @param lat0 latitude of start point
* @param lon1 longitude of end point
* @param lat1 latitude of start point
* @return true if segment or any of it's points are 'inside' of polygon
*/
public boolean intersects(int lon0, int lat0, int lon1, int lat1)
{
final Point p0 = new Point (lon0,lat0);
final Point p1 = new Point (lon1,lat1);
int i_last = points.size()-1;
Point p2 = points.get(isClosed ? i_last : 0 );
for (int i = isClosed ? 0 : 1 ; i <= i_last; i++)
{
Point p3 = points.get(i);
// does it intersect with at least one of the polygon's segments?
if (intersect2D_2Segments(p0,p1,p2,p3) > 0)
{
return true;
}
p2 = p3;
}
return false;
}
public boolean isOnPolyline( long px, long py )
{
int i_last = points.size()-1;
Point p1 = points.get(0);
for (int i = 1 ; i <= i_last; i++)
{
final Point p2 = points.get(i);
if (OsmNogoPolygon.isOnLine(px,py,p1.x,p1.y,p2.x,p2.y))
{
return true;
}
p1 = p2;
}
return false;
}
public static boolean isOnLine( long px, long py, long p0x, long p0y, long p1x, long p1y )
{
final double v10x = px-p0x;
final double v10y = py-p0y;
final double v12x = p1x-p0x;
final double v12y = p1y-p0y;
if ( v10x == 0 ) // P0->P1 vertical?
{
if ( v10y == 0 ) // P0 == P1?
{
return true;
}
if ( v12x != 0 ) // P1->P2 not vertical?
{
return false;
}
return ( v12y / v10y ) >= 1; // P1->P2 at least as long as P1->P0?
}
if ( v10y == 0 ) // P0->P1 horizontal?
{
if ( v12y != 0 ) // P1->P2 not horizontal?
{
return false;
}
// if ( P10x == 0 ) // P0 == P1? already tested
return ( v12x / v10x ) >= 1; // P1->P2 at least as long as P1->P0?
}
final double kx = v12x / v10x;
if ( kx < 1 )
{
return false;
}
return kx == v12y / v10y;
}
/* 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
this code, and cannot be held liable for any real or imagined damage
resulting from its use. Users of this code must verify correctness for
their application. */
/**
* winding number test for a point in a polygon
*
* @param p a point
* @param v list of vertex points forming a polygon. This polygon
* is implicitly closed connecting the last and first point.
* @return the winding number (=0 only when P is outside)
*/
public boolean isWithin(final long px, final long py)
{
int wn = 0; // the winding number counter
// loop through all edges of the polygon
final int i_last = points.size()-1;
final Point p0 = points.get(isClosed ? i_last : 0);
long p0x = p0.x; // need to use long to avoid overflow in products
long p0y = p0.y;
for (int i = isClosed ? 0 : 1; i <= i_last; i++) // edge from v[i] to v[i+1]
{
final Point p1 = points.get(i);
final long p1x = p1.x;
final long p1y = p1.y;
if (OsmNogoPolygon.isOnLine(px, py, p0x, p0y, p1x, p1y))
{
return true;
}
if (p0y <= py) // start y <= p.y
{
if (p1y > py) // an upward crossing
{ // p left of edge
if (((p1x - p0x) * (py - p0y) - (px - p0x) * (p1y - p0y)) > 0)
{
++wn; // have a valid up intersect
}
}
}
else // start y > p.y (no test needed)
{
if (p1y <= py) // a downward crossing
{ // p right of edge
if (((p1x - p0x) * (py - p0y) - (px - p0x) * (p1y - p0y)) < 0)
{
--wn; // have a valid down intersect
}
}
}
p0x = p1x;
p0y = p1y;
}
return wn != 0;
}
/* 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
this code, and cannot be held liable for any real or imagined damage
resulting from its use. Users of this code must verify correctness for
their application. */
/**
* inSegment(): determine if a point is inside a segment
*
* @param p a point
* @param seg_p0 starting point of segment
* @param seg_p1 ending point of segment
* @return 1 = P is inside S
* 0 = P is not inside S
*/
private static boolean inSegment( final Point p, final Point seg_p0, final Point seg_p1)
{
final int sp0x = seg_p0.x;
final int sp1x = seg_p1.x;
if (sp0x != sp1x) // S is not vertical
{
final int px = p.x;
if (sp0x <= px && px <= sp1x)
{
return true;
}
if (sp0x >= px && px >= sp1x)
{
return true;
}
}
else // S is vertical, so test y coordinate
{
final int sp0y = seg_p0.y;
final int sp1y = seg_p1.y;
final int py = p.y;
if (sp0y <= py && py <= sp1y)
{
return true;
}
if (sp0y >= py && py >= sp1y)
{
return true;
}
}
return false;
}
/* 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
this code, and cannot be held liable for any real or imagined damage
resulting from its use. Users of this code must verify correctness for
their application. */
/**
* intersect2D_2Segments(): find the 2D intersection of 2 finite segments
* @param s1p0 start point of segment 1
* @param s1p1 end point of segment 1
* @param s2p0 start point of segment 2
* @param s2p1 end point of segment 2
* @return 0=disjoint (no intersect)
* 1=intersect in unique point I0
* 2=overlap in segment from I0 to I1
*/
private static int intersect2D_2Segments( final Point s1p0, final Point s1p1, final Point s2p0, final Point s2p1 )
{
final long ux = s1p1.x - s1p0.x; // vector u = S1P1-S1P0 (segment 1)
final long uy = s1p1.y - s1p0.y;
final long vx = s2p1.x - s2p0.x; // vector v = S2P1-S2P0 (segment 2)
final long vy = s2p1.y - s2p0.y;
final long wx = s1p0.x - s2p0.x; // vector w = S1P0-S2P0 (from start of segment 2 to start of segment 1
final long wy = s1p0.y - s2p0.y;
final double d = ux * vy - uy * vx;
// test if they are parallel (includes either being a point)
if (d == 0) // S1 and S2 are parallel
{
if ((ux * wy - uy * wx) != 0 || (vx * wy - vy * wx) != 0)
{
return 0; // they are NOT collinear
}
// they are collinear or degenerate
// check if they are degenerate points
final boolean du = ((ux == 0) && (uy == 0));
final boolean dv = ((vx == 0) && (vy == 0));
if (du && dv) // both segments are points
{
return (wx == 0 && wy == 0) ? 0 : 1; // return 0 if they are distinct points
}
if (du) // S1 is a single point
{
return inSegment(s1p0, s2p0, s2p1) ? 1 : 0; // is it part of S2?
}
if (dv) // S2 a single point
{
return inSegment(s2p0, s1p0, s1p1) ? 1 : 0; // is it part of S1?
}
// they are collinear segments - get overlap (or not)
double t0, t1; // endpoints of S1 in eqn for S2
final int w2x = s1p1.x - s2p0.x; // vector w2 = S1P1-S2P0 (from start of segment 2 to end of segment 1)
final int w2y = s1p1.y - s2p0.y;
if (vx != 0)
{
t0 = wx / vx;
t1 = w2x / vx;
}
else
{
t0 = wy / vy;
t1 = w2y / vy;
}
if (t0 > t1) // must have t0 smaller than t1
{
final double t=t0; // swap if not
t0=t1;
t1=t;
}
if (t0 > 1 || t1 < 0)
{
return 0; // NO overlap
}
t0 = t0<0? 0 : t0; // clip to min 0
t1 = t1>1? 1 : t1; // clip to max 1
return (t0 == t1) ? 1 : 2; // return 1 if intersect is a point
}
// the segments are skew and may intersect in a point
// get the intersect parameter for S1
final double sI = (vx * wy - vy * wx) / d;
if (sI < 0 || sI > 1) // no intersect with S1
{
return 0;
}
// get the intersect parameter for S2
final double tI = (ux * wy - uy * wx) / d;
return (tI < 0 || tI > 1) ? 0 : 1; // return 0 if no intersect with S2
}
}

View file

@ -192,6 +192,10 @@ public final class RoutingContext
{
for( OsmNodeNamed nogo : nogos )
{
if (nogo instanceof OsmNogoPolygon)
{
continue;
}
String s = nogo.name;
int idx = s.indexOf( ' ' );
if ( idx > 0 ) s = s.substring( 0 , idx );
@ -215,7 +219,11 @@ public final class RoutingContext
boolean goodGuy = true;
for( OsmNodeNamed wp : waypoints )
{
if ( wp.calcDistance( nogo ) < radiusInMeter )
if ( wp.calcDistance( nogo ) < radiusInMeter
&& (!(nogo instanceof OsmNogoPolygon)
|| (((OsmNogoPolygon)nogo).isClosed
? ((OsmNogoPolygon)nogo).isWithin(wp.ilon, wp.ilat)
: ((OsmNogoPolygon)nogo).isOnPolyline(wp.ilon, wp.ilat))))
{
goodGuy = false;
break;
@ -294,7 +302,14 @@ public final class RoutingContext
radius = Math.sqrt( s1 < s2 ? r12 : r22 );
if ( radius > nogo.radius ) continue; // 20m ^ 2
}
if ( nogo.isNogo ) nogomatch = true;
if ( nogo.isNogo )
{
if (!(nogo instanceof OsmNogoPolygon)
|| ((OsmNogoPolygon)nogo).intersects(lon1, lat1, lon2, lat2))
{
nogomatch = true;
}
}
else
{
shortestmatch = true;

View file

@ -0,0 +1,153 @@
/**********************************************************************************************
Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**********************************************************************************************/
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.router.OsmNogoPolygon.Point;
public class OsmNogoPolygonTest {
static final int offset_x = 11000000;
static final int offset_y = 50000000;
static OsmNogoPolygon polygon;
static OsmNogoPolygon polyline;
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) {
return (int)( ( lon + 180. ) *1000000. + 0.5)+offset_x; // see ServerHandler.readPosition()
}
static int toOsmLat(double lat) {
return (int)( ( lat + 90. ) *1000000. + 0.5)+offset_y;
}
static double coslat(int lat) // see RoutingContext.calcDistance()
{
final double l = (lat - 90000000) * 0.00000001234134; // 0.01234134 = Pi/(sqrt(2)*180)
final double l2 = l*l;
final double l4 = l2*l2;
// final double l6 = l4*l2;
return 1.- l2 + l4 / 6.; // - l6 / 90;
}
@BeforeClass
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]));
}
polyline = new OsmNogoPolygon(false);
for (int i = 0; i<lons.length; i++) {
polyline.addVertex(toOsmLon(lons[i]),toOsmLat(lats[i]));
}
}
@AfterClass
public static void tearDown() throws Exception {
}
@Test
public void testCalcBoundingCircle() {
polygon.calcBoundingCircle();
double r = polygon.radius;
for (int i=0; i<lons.length; i++) {
double py = toOsmLat(lats[i]);
double dpx = (toOsmLon(lons[i]) - polygon.ilon) * coslat(polygon.ilat);
double dpy = py - polygon.ilat;
double r1 = Math.sqrt(dpx * dpx + dpy * dpy) * 0.000001;
double diff = r-r1;
assertTrue("i: "+i+" r("+r+") >= r1("+r1+")", diff >= 0);
}
polyline.calcBoundingCircle();
r = polyline.radius;
for (int i=0; i<lons.length; i++) {
double py = toOsmLat(lats[i]);
double dpx = (toOsmLon(lons[i]) - polyline.ilon) * coslat(polyline.ilat);
double dpy = py - polyline.ilat;
double r1 = Math.sqrt(dpx * dpx + dpy * dpy) * 0.000001;
double diff = r-r1;
assertTrue("i: "+i+" r("+r+") >= r1("+r1+")", diff >= 0);
}
}
@Test
public void testIsWithin() {
double[] plons = { 0.0, 0.5, 1.0, -1.5, -0.5, 1.0, 1.0, 0.5, 0.5, 0.5, };
double[] plats = { 0.0, 1.5, 0.0, 0.5, -1.5, -1.0, -0.1, -0.1, 0.0, 0.1, };
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])));
}
}
@Test
public void testIntersectsPolygon() {
double[] p0lons = { 0.0, 1.0, -0.5, 0.5, 0.7, 0.7, 0.7, -1.5, -1.5, 0.0 };
double[] p0lats = { 0.0, 0.0, 0.5, 0.5, 0.5, 0.05, 0.05, -1.5, 0.2, 0.0 };
double[] p1lons = { 0.0, 1.0, 0.5, 1.0, 0.7, 0.7, 0.7, -0.5, -0.2, 0.5 };
double[] p1lats = { 0.0, 0.0, 0.5, 0.5, -0.5, -0.5, -0.05, -0.5, 1.5, -1.5 };
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])));
}
}
@Test
public void testIntersectsPolyline() {
double[] p0lons = { 0.0, 1.0, -0.5, 0.5, 0.7, 0.7, 0.7, -1.5, -1.5, 0.0 };
double[] p0lats = { 0.0, 0.0, 0.5, 0.5, 0.5, 0.05, 0.05, -1.5, 0.2, 0.0 };
double[] p1lons = { 0.0, 1.0, 0.5, 1.0, 0.7, 0.7, 0.7, -0.5, -0.2, 0.5 };
double[] p1lats = { 0.0, 0.0, 0.5, 0.5, -0.5, -0.5, -0.05, -0.5, 1.5, -1.5 };
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])));
}
}
@Test
public void testBelongsToLine() {
assertTrue(OsmNogoPolygon.isOnLine(10,10, 10,10, 10,20));
assertTrue(OsmNogoPolygon.isOnLine(10,10, 10,10, 20,10));
assertTrue(OsmNogoPolygon.isOnLine(10,10, 20,10, 10,10));
assertTrue(OsmNogoPolygon.isOnLine(10,10, 10,20, 10,10));
assertTrue(OsmNogoPolygon.isOnLine(10,15, 10,10, 10,20));
assertTrue(OsmNogoPolygon.isOnLine(15,10, 10,10, 20,10));
assertTrue(OsmNogoPolygon.isOnLine(10,10, 10,10, 20,30));
assertTrue(OsmNogoPolygon.isOnLine(20,30, 10,10, 20,30));
assertTrue(OsmNogoPolygon.isOnLine(15,20, 10,10, 20,30));
assertFalse(OsmNogoPolygon.isOnLine(11,11, 10,10, 10,20));
assertFalse(OsmNogoPolygon.isOnLine(11,11, 10,10, 20,10));
assertFalse(OsmNogoPolygon.isOnLine(15,21, 10,10, 20,30));
assertFalse(OsmNogoPolygon.isOnLine(15,19, 10,10, 20,30));
assertFalse(OsmNogoPolygon.isOnLine(0,-10, 10,10, 20,30));
assertFalse(OsmNogoPolygon.isOnLine(30,50, 10,10, 20,30));
}
}

View file

@ -32,6 +32,8 @@ import btools.expressions.BExpressionContextWay;
import btools.expressions.BExpressionMetaData;
import btools.mapaccess.OsmNode;
import btools.router.OsmNodeNamed;
import btools.router.OsmNogoPolygon;
import btools.router.OsmNogoPolygon.Point;
import btools.router.OsmTrack;
import btools.router.RoutingContext;
import btools.router.RoutingEngine;
@ -518,7 +520,7 @@ public class BRouterView extends View
scaleLon = scaleLat * coslat;
startTime = System.currentTimeMillis();
rc.prepareNogoPoints( nogoList );
RoutingContext.prepareNogoPoints( nogoList );
rc.nogopoints = nogoList;
rc.memoryclass = memoryClass;
@ -641,6 +643,41 @@ public class BRouterView extends View
}
}
private void paintLine( Canvas canvas, final int ilon0, final int ilat0, final int ilon1, final int ilat1, final Paint paint )
{
final int lon0 = ilon0 - centerLon;
final int lat0 = ilat0 - centerLat;
final int lon1 = ilon1 - centerLon;
final int lat1 = ilat1 - centerLat;
final int x0 = imgw / 2 + (int) ( scaleLon * lon0 );
final int y0 = imgh / 2 - (int) ( scaleLat * lat0 );
final int x1 = imgw / 2 + (int) ( scaleLon * lon1 );
final int y1 = imgh / 2 - (int) ( scaleLat * lat1 );
canvas.drawLine( (float) x0, (float) y0, (float) x1, (float) y1, paint );
}
private void paintPolygon( Canvas canvas, OsmNogoPolygon p, int minradius )
{
final int ir = (int) ( p.radius * 1000000. * scaleLat );
if ( ir > minradius )
{
Paint paint = new Paint();
paint.setColor( Color.RED );
paint.setStyle( Paint.Style.STROKE );
Point p0 = p.isClosed ? p.points.get(p.points.size()-1) : null;
for ( final Point p1 : p.points )
{
if (p0 != null)
{
paintLine( canvas, p0.x, p0.y, p1.x, p1.y, paint );
}
p0 = p1;
}
}
}
@Override
protected void onSizeChanged( int w, int h, int oldw, int oldh )
{
@ -824,9 +861,16 @@ public class BRouterView extends View
for ( int ngi = 0; ngi < nogoList.size(); ngi++ )
{
OsmNodeNamed n = nogoList.get( ngi );
if (n instanceof OsmNogoPolygon)
{
paintPolygon( canvas, (OsmNogoPolygon)n, 4 );
}
else
{
int color = 0xff0000;
paintCircle( canvas, n, color, 4 );
}
}
Paint paint = new Paint();
paint.setColor( Color.WHITE );

View file

@ -67,7 +67,7 @@ public class BRouterWorker
}
readNogos( params ); // add interface provided nogos
rc.prepareNogoPoints( nogoList );
RoutingContext.prepareNogoPoints( nogoList );
rc.nogopoints = nogoList;
waypoints = readPositions(params);

View file

@ -3,9 +3,15 @@ package btools.routingapp;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import btools.router.OsmNodeNamed;
import btools.router.OsmNogoPolygon;
/**
* Read coordinates from a gpx-file
@ -65,6 +71,13 @@ public class CoordinateReaderOsmAnd extends CoordinateReader
{
_readPointmap( osmandDir + "/favourites.gpx" );
}
try
{
_readNogoLines( basedir+tracksdir );
}
catch( IOException ioe )
{
}
}
private void _readPointmap( String filename ) throws Exception
@ -107,4 +120,71 @@ public class CoordinateReaderOsmAnd extends CoordinateReader
}
br.close();
}
private void _readNogoLines( String dirname ) throws IOException
{
File dir = new File( dirname );
if (dir.exists() && dir.isDirectory())
{
for (final File file : dir.listFiles())
{
final String name = file.getName();
if (name.startsWith("nogo") && name.endsWith(".gpx"))
{
try
{
_readNogoLine(file);
}
catch (Exception e)
{
}
}
}
}
}
private void _readNogoLine( File file ) throws Exception
{
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(false);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(new FileReader(file));
OsmNogoPolygon nogo = new OsmNogoPolygon(false);
int eventType = xpp.getEventType();
int numSeg = 0;
while (eventType != XmlPullParser.END_DOCUMENT) {
switch(eventType) {
case XmlPullParser.START_TAG: {
if (xpp.getName().equals("trkpt")) {
final String lon = xpp.getAttributeValue(null,"lon");
final String lat = xpp.getAttributeValue(null,"lat");
if (lon != null && lat != null) {
nogo.addVertex(
(int)( ( Double.parseDouble(lon) + 180. ) *1000000. + 0.5),
(int)( ( Double.parseDouble(lat) + 90. ) *1000000. + 0.5));
}
}
break;
}
case XmlPullParser.END_TAG: {
if (xpp.getName().equals("trkseg")) {
nogo.calcBoundingCircle();
final String name = file.getName();
nogo.name = name.substring(0, name.length()-4);
if (numSeg > 0)
{
nogo.name += Integer.toString(numSeg+1);
}
numSeg++;
checkAddPoint( "(one-for-all)", nogo );
}
break;
}
}
eventType = xpp.next();
}
}
}

View file

@ -88,7 +88,7 @@ public class BRouter
}
System.exit(0);
}
System.out.println("BRouter 1.4.9 / 24092017 / abrensch");
System.out.println("BRouter 1.4.10 / 26022018 / abrensch+ntruchsess");
if ( args.length < 6 )
{
System.out.println("Find routes in an OSM map");

View file

@ -157,7 +157,7 @@ public class RouteServer extends Thread
public static void main(String[] args) throws Exception
{
System.out.println("BRouter 1.4.9 / 24092017");
System.out.println("BRouter 1.4.10 / 26022018 abrensch+ntruchsess");
if ( args.length != 5 && args.length != 6)
{
System.out.println("serve BRouter protocol");

View file

@ -1,6 +1,7 @@
package btools.server.request;
import btools.router.OsmNodeNamed;
import btools.router.OsmNogoPolygon;
import btools.router.OsmTrack;
import btools.router.RoutingContext;
import btools.server.ServiceContext;
@ -55,12 +56,23 @@ public class ServerHandler extends RequestHandler {
rc.setAlternativeIdx(Integer.parseInt(params.get( "alternativeidx" )));
List<OsmNodeNamed> nogoList = readNogoList();
List<OsmNodeNamed> nogoPolygonsList = readNogoPolygons();
if ( nogoList != null )
{
rc.prepareNogoPoints( nogoList );
RoutingContext.prepareNogoPoints( nogoList );
rc.nogopoints = nogoList;
}
if (rc.nogopoints == null)
{
rc.nogopoints = nogoPolygonsList;
}
else if ( nogoPolygonsList != null )
{
rc.nogopoints.addAll(nogoPolygonsList);
}
return rc;
}
@ -225,4 +237,41 @@ public class ServerHandler extends RequestHandler {
n.isNogo = true;
return n;
}
private List<OsmNodeNamed> readNogoPolygons()
{
List<OsmNodeNamed> result = new ArrayList<OsmNodeNamed>();
parseNogoPolygons( params.get("polylines"), result, false );
parseNogoPolygons( params.get("polygons"), result, true );
return result.size() > 0 ? result : null;
}
private static void parseNogoPolygons(String polygons, List<OsmNodeNamed> result, boolean closed )
{
if ( polygons != null )
{
String[] polygonList = polygons.split("\\|");
for (int i = 0; i < polygonList.length; i++)
{
String[] lonLatList = polygonList[i].split(",");
if ( lonLatList.length > 1 )
{
OsmNogoPolygon polygon = new OsmNogoPolygon(closed);
for (int j = 0; j < lonLatList.length-1;)
{
String slon = lonLatList[j++];
String slat = lonLatList[j++];
int lon = (int)( ( Double.parseDouble(slon) + 180. ) *1000000. + 0.5);
int lat = (int)( ( Double.parseDouble(slat) + 90. ) *1000000. + 0.5);
polygon.addVertex(lon, lat);
}
if ( polygon.points.size() > 0 )
{
polygon.calcBoundingCircle();
result.add(polygon);
}
}
}
}
}
}

View file

@ -28,6 +28,11 @@
<name>Arndt Brenschede</name>
<email>Arndt.Brenschede@web.de</email>
</developer>
<developer>
<id>norbert.truchsess</id>
<name>Norbert Truchsess</name>
<email>norbert.truchsess@t-online.de</email>
</developer>
</developers>
<properties>
@ -146,7 +151,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>