diff --git a/brouter-core/pom.xml b/brouter-core/pom.xml index 86be86c..1212461 100644 --- a/brouter-core/pom.xml +++ b/brouter-core/pom.xml @@ -32,5 +32,10 @@ brouter-expressions ${project.version} + + junit + junit + test + diff --git a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java new file mode 100644 index 0000000..f6ad5ef --- /dev/null +++ b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java @@ -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 . + + 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 points = new ArrayList(); + + 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 + } +} diff --git a/brouter-core/src/main/java/btools/router/RoutingContext.java b/brouter-core/src/main/java/btools/router/RoutingContext.java index 0ae2641..5c28da5 100644 --- a/brouter-core/src/main/java/btools/router/RoutingContext.java +++ b/brouter-core/src/main/java/btools/router/RoutingContext.java @@ -192,16 +192,20 @@ public final class RoutingContext { for( OsmNodeNamed nogo : nogos ) { - String s = nogo.name; - int idx = s.indexOf( ' ' ); - if ( idx > 0 ) s = s.substring( 0 , idx ); - int ir = 20; // default radius - if ( s.length() > 4 ) - { - try { ir = Integer.parseInt( s.substring( 4 ) ); } - catch( Exception e ) { /* ignore */ } - } - nogo.radius = ir / 110984.; // 6378000. / 57.3; + if (nogo instanceof OsmNogoPolygon) + { + continue; + } + String s = nogo.name; + int idx = s.indexOf( ' ' ); + if ( idx > 0 ) s = s.substring( 0 , idx ); + int ir = 20; // default radius + if ( s.length() > 4 ) + { + try { ir = Integer.parseInt( s.substring( 4 ) ); } + catch( Exception e ) { /* ignore */ } + } + nogo.radius = ir / 110984.; // 6378000. / 57.3; } } @@ -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; diff --git a/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java b/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java new file mode 100644 index 0000000..59f7fef --- /dev/null +++ b/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java @@ -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 . + +**********************************************************************************************/ +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= r1("+r1+")", diff >= 0); + } + polyline.calcBoundingCircle(); + r = polyline.radius; + for (int i=0; i= 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 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,8 +861,15 @@ public class BRouterView extends View for ( int ngi = 0; ngi < nogoList.size(); ngi++ ) { OsmNodeNamed n = nogoList.get( ngi ); - int color = 0xff0000; - paintCircle( canvas, n, color, 4 ); + if (n instanceof OsmNogoPolygon) + { + paintPolygon( canvas, (OsmNogoPolygon)n, 4 ); + } + else + { + int color = 0xff0000; + paintCircle( canvas, n, color, 4 ); + } } Paint paint = new Paint(); diff --git a/brouter-routing-app/src/main/java/btools/routingapp/BRouterWorker.java b/brouter-routing-app/src/main/java/btools/routingapp/BRouterWorker.java index 736caa4..cbcb67c 100644 --- a/brouter-routing-app/src/main/java/btools/routingapp/BRouterWorker.java +++ b/brouter-routing-app/src/main/java/btools/routingapp/BRouterWorker.java @@ -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); diff --git a/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderOsmAnd.java b/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderOsmAnd.java index 917c45a..b4b059f 100644 --- a/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderOsmAnd.java +++ b/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderOsmAnd.java @@ -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(); + } + } } diff --git a/brouter-server/src/main/java/btools/server/BRouter.java b/brouter-server/src/main/java/btools/server/BRouter.java index 6a72c3d..c6933ff 100644 --- a/brouter-server/src/main/java/btools/server/BRouter.java +++ b/brouter-server/src/main/java/btools/server/BRouter.java @@ -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"); diff --git a/brouter-server/src/main/java/btools/server/RouteServer.java b/brouter-server/src/main/java/btools/server/RouteServer.java index 51c4e12..130cf54 100644 --- a/brouter-server/src/main/java/btools/server/RouteServer.java +++ b/brouter-server/src/main/java/btools/server/RouteServer.java @@ -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"); diff --git a/brouter-server/src/main/java/btools/server/request/ServerHandler.java b/brouter-server/src/main/java/btools/server/request/ServerHandler.java index 8388411..c63ea86 100644 --- a/brouter-server/src/main/java/btools/server/request/ServerHandler.java +++ b/brouter-server/src/main/java/btools/server/request/ServerHandler.java @@ -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 nogoList = readNogoList(); + List 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; } @@ -224,5 +236,42 @@ public class ServerHandler extends RequestHandler { n.ilat = (int)( ( lat + 90. ) *1000000. + 0.5); n.isNogo = true; return n; - } + } + + private List readNogoPolygons() + { + List result = new ArrayList(); + 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 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); + } + } + } + } + } } diff --git a/pom.xml b/pom.xml index a8999e9..10b06db 100644 --- a/pom.xml +++ b/pom.xml @@ -28,6 +28,11 @@ Arndt Brenschede Arndt.Brenschede@web.de + + norbert.truchsess + Norbert Truchsess + norbert.truchsess@t-online.de + @@ -146,7 +151,7 @@ junit junit - 4.11 + 4.12 test