From c1048ab62a6da516cacf2d6022bfd6b905259b2b Mon Sep 17 00:00:00 2001 From: ntruchsess Date: Sat, 20 Jan 2018 18:47:57 +0100 Subject: [PATCH 01/14] add OsmNogoPolygon --- .../java/btools/router/OsmNogoPolygon.java | 376 ++++++++++++++++++ .../java/btools/router/RoutingContext.java | 7 +- .../btools/router/OsmNogoPolygonTest.java | 47 +++ 3 files changed, 429 insertions(+), 1 deletion(-) create mode 100644 brouter-core/src/main/java/btools/router/OsmNogoPolygon.java create mode 100644 brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java 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..05f85d9 --- /dev/null +++ b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java @@ -0,0 +1,376 @@ +/* + * Copyright 2018 Norbert Truchsess + * + * this code is based on work of Dan Sunday published at: + * http://geomalgorithms.com/a03-_inclusion.html + * (implementation of winding number algorithm in c) + * http://geomalgorithms.com/a08-_containers.html + * (fast computation of bounding circly in c) + * + * Copyright 2001 softSurfer, 2012 Dan Sunday + * 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. + */ +package btools.router; + +import java.util.ArrayList; +import java.util.List; + +public class OsmNogoPolygon extends OsmNodeNamed +{ + public final class Point { + /** + * The latitude + */ + public final int y; + + /** + * The longitude + */ + public final int x; + + public Point(final int lon, final int lat) + { + x = lon; + y = lat; + } + } + + public List P = new ArrayList(); + + public void addVertex(int lon, int lat) + { + P.add(new Point(lon, lat)); + } + + public void calcBoundingCircle() + { + double Cx, Cy; // Center of ball + double rad, rad2; // radius and radius squared + double xmin, xmax, ymin, ymax; // bounding box extremes + int i_xmin, i_xmax, i_ymin, i_ymax; // index of P[] at box extreme + + // find a large diameter to start with + // first get the bounding box and P[] extreme points for it + xmin = xmax = P.get(0).x; + ymin = ymax = P.get(0).y; + i_xmin = i_xmax = i_ymin = i_ymax = 0; + for (int i = 1; i < P.size(); i++) + { + Point Pi = P.get(i); + if (Pi.x < xmin) + { + xmin = Pi.x; + i_xmin = i; + } + else if (Pi.x > xmax) + { + xmax = Pi.x; + i_xmax = i; + } + if (Pi.y < ymin) + { + ymin = Pi.y; + i_ymin = i; + } + else if (Pi.y > ymax) + { + ymax = Pi.y; + i_ymax = i; + } + } + // select the largest extent as an initial diameter for the ball + Point Pi_xmax = P.get(i_xmax); + Point Pi_xmin = P.get(i_xmin); + Point Pi_ymax = P.get(i_ymax); + Point Pi_ymin = P.get(i_ymin); + + int dPx_x = (Pi_xmax.x - Pi_xmin.x); // diff of Px max and min + int dPx_y = Pi_xmax.y - Pi_xmin.y; + + int dPy_x = Pi_ymax.x - Pi_ymin.x; // diff of Py max and min + int dPy_y = Pi_ymax.y - Pi_ymin.y; + + int dx2 = dPx_x * dPx_x + dPx_y * dPx_y; // Px diff squared + int dy2 = dPy_x * dPy_x + dPy_y * dPy_y; // Py diff squared + + if (dx2 >= dy2) // x direction is largest extent + { + Cx = Pi_xmin.x + dPx_x / 2.0; // Center = midpoint of extremes + Cy = Pi_xmin.y + dPx_x / 2.0; + + double dPC_x = Pi_xmax.x - Cx; + double dPC_y = Pi_xmax.y - Cy; + + rad2 = dPC_x * dPC_x + dPC_y * dPC_y; // radius squared + + } + else // y direction is largest extent + { + Cx = Pi_ymin.x + dPy_x / 2.0; // Center = midpoint of extremes + Cy = Pi_ymin.y + dPy_y / 2.0; + + double dPC_x = Pi_ymax.x - Cx; + double dPC_y = Pi_ymax.y - Cy; + + rad2 = dPC_x * dPC_x + dPC_y * dPC_y; // radius squared + } + rad = Math.sqrt(rad2); + + // now check that all points P[i] are in the ball + // and if not, expand the ball just enough to include them + double dist, dist2; + for (int i = 0; i < P.size(); i++) + { + Point Pi = P.get(i); + + double dPC_x = Pi.x - Cx; + double dPC_y = Pi.y - Cy; + + dist2 = dPC_x * dPC_x + dPC_y * dPC_y; + + if (dist2 <= rad2) // P[i] is inside the ball already + { + continue; + } + // P[i] not in ball, so expand ball to include it + dist = Math.sqrt(dist2); + rad = (rad + dist) / 2.0; // enlarge radius just enough + rad2 = rad * rad; + + double dd = (dist - rad) / dist; + + Cx = Cx + dd * dPC_x; // shift Center toward + Cy = Cy + dd * dPC_y; + } + ilon = (int) Math.round(Cx); + ilat = (int) Math.round(Cy); + // compensate rounding error of center-point + radius = rad + Math.max(Math.abs(Cx - ilon), Math.abs(Cy - ilat)); + return; + } + + public boolean intersectsOrIsWithin(int lon0, int lat0, int lon1, int lat1) + { + Point P0 = new Point (lon0,lat0); + Point P1 = new Point (lon1,lat1); + // is start or endpoint within polygon? + if ((wn_PnPoly(P0, P) > 0) || (wn_PnPoly(P1, P) > 0)) + { + return true; + } + Point P2 = P.get(0); + for (int i = 1; i < P.size(); i++) + { + Point P3 = P.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; + } + + /** + * isLeft(): tests if a point is Left|On|Right of an infinite line. Input: + * three points P0, P1, and P2 Return: >0 for P2 left of the line through P0 + * and P1 =0 for P2 on the line <0 for P2 right of the line See: Algorithm 1 + * "Area of Triangles and Polygons" + */ + + private static int isLeft(Point P0, Point P1, Point P2) { + return ((P1.x - P0.x) * (P2.y - P0.y) - (P2.x - P0.x) * (P1.y - P0.y)); + } + + /** + * cn_PnPoly(): crossing number test for a point in a polygon Input: P = a + * point, V[] = vertex points of a polygon V[n+1] with V[n]=V[0] Return: 0 = + * outside, 1 = inside This code is patterned after [Franklin, 2000] + */ + + private static boolean cn_PnPoly(Point P, List V) + { + int cn = 0; // the crossing number counter + + // loop through all edges of the polygon + int last = V.size()-1; + Point Vi = V.get(last); + for (int i = 0; i <= last; i++) // edge from V[i] to V[i+1] + { + Point Vi1 = V.get(i); + + if (((Vi.y <= P.y) && (Vi1.y > P.y)) // an upward crossing + || ((Vi.y > P.y) && (Vi1.y <= P.y))) // a downward crossing + { + // compute the actual edge-ray intersect x-coordinate + float vt = (float) (P.y - Vi.y) / (Vi1.y - Vi.y); + + if (P.x < Vi.x + vt * (Vi1.x - Vi.x)) // P.x < intersect + { + ++cn; // a valid crossing of y=P.y right of P.x + } + } + Vi = Vi1; + } + return ((cn & 1) > 0); // 0 if even (out), and 1 if odd (in) + } + + /** + * wn_PnPoly(): winding number test for a point in a polygon Input: P = a + * point, V = vertex points of a polygon V[n+1] with V[n]=V[0] Return: wn = + * the winding number (=0 only when P is outside) + */ + + private static int wn_PnPoly(Point P, List V) { + int wn = 0; // the winding number counter + + // loop through all edges of the polygon + int last = V.size()-1; + Point Vi = V.get(last); + for (int i = 0; i <= last; i++) // edge from V[i] to V[i+1] + { + Point Vi1 = V.get(i); + + if (Vi.y <= P.y) { // start y <= P.y + if (Vi1.y > P.y) { // an upward crossing + if (isLeft(Vi, Vi1, P) > 0) { // P left of edge + ++wn; // have a valid up intersect + } + } + } else { // start y > P.y (no test needed) + if (Vi1.y <= P.y) { // a downward crossing + if (isLeft(Vi, Vi1, P) < 0) { // P right of edge + --wn; // have a valid down intersect + } + } + } + Vi = Vi1; + } + return wn; + } + + /** + * inSegment(): determine if a point is inside a segment + * Input: a point P, and a collinear segment S + * Return: 1 = P is inside S + * 0 = P is not inside S + */ + + private static boolean inSegment( Point P, Point SP0, Point SP1) + { + if (SP0.x != SP1.x) // S is not vertical + { + if (SP0.x <= P.x && P.x <= SP1.x) + { + return true; + } + if (SP0.x >= P.x && P.x >= SP1.x) + { + return true; + } + } + else // S is vertical, so test y coordinate + { + if (SP0.y <= P.y && P.y <= SP1.y) + { + return true; + } + if (SP0.y >= P.y && P.y >= SP1.y) + { + return true; + } + } + return false; + } + + /** + * intersect2D_2Segments(): find the 2D intersection of 2 finite segments + * Input: two finite segments S1 and S2 + * Return: 0=disjoint (no intersect) + * 1=intersect in unique point I0 + * 2=overlap in segment from I0 to I1 + */ + private static int intersect2D_2Segments( Point S1P0, Point S1P1, Point S2P0, Point S2P1 ) + { + int ux = S1P1.x - S1P0.x; // vector u = S1P1-S1P0 (segment 1) + int uy = S1P1.y - S1P0.y; + int vx = S2P1.x - S2P0.x; // vector v = S2P1-S2P0 (segment 2) + int vy = S2P1.y - S2P0.y; + int wx = S1P0.x - S2P0.x; // vector w = S1P0-S2P0 (from start of segment 2 to start of segment 1 + int wy = S1P0.y - S2P0.y; + + int 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 + boolean du = ux == 0 && uy == 0; + 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) + float t0, t1; // endpoints of S1 in eqn for S2 + int w2x = S1P1.x - S2P0.x; // vector w2 = S1P1-S2P0 (from start of segment 2 to end of segment 1) + 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 + { + float 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 + + double sI = (vx * wy - vy * wx) / D; + if (sI < 0 || sI > 1) // no intersect with S1 + { + return 0; + } + + // get the intersect parameter for S2 + 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..b903977 100644 --- a/brouter-core/src/main/java/btools/router/RoutingContext.java +++ b/brouter-core/src/main/java/btools/router/RoutingContext.java @@ -294,7 +294,12 @@ 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 + && (!(nogo instanceof OsmNogoPolygon) + || ((OsmNogoPolygon)nogo).intersectsOrIsWithin(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..a53ddac --- /dev/null +++ b/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java @@ -0,0 +1,47 @@ +package btools.router; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; + +public class OsmNogoPolygonTest { + + OsmNogoPolygon p; + + @Before + public void setUp() throws Exception { + p = new OsmNogoPolygon(); + p.addVertex(1000, 1000); + p.addVertex(2001, 1000); + p.addVertex(2001, 1250); + p.addVertex(1750, 1250); + p.addVertex(1750, 1750); + p.addVertex(2001, 1750); + p.addVertex(2001, 2001); + p.addVertex(1000, 2001); + } + + @Test + public void testCalcBoundingCircle() { + p.calcBoundingCircle(); + assertEquals(1501,p.ilat); + assertEquals(1501,p.ilon); + assertEquals(707.813887968,p.radius,0.5); + } + + @Test + public void testIntersectsOrIsWithin() { + assertFalse(p.intersectsOrIsWithin(0,0, 0,0)); + assertFalse(p.intersectsOrIsWithin(1800,1500, 1800,1500)); + assertFalse(p.intersectsOrIsWithin(1500,2002, 1500,2002)); + assertTrue(p.intersectsOrIsWithin(1750, 1500, 1800,1500)); + assertTrue(p.intersectsOrIsWithin(1500, 2001, 1500,2002)); + assertTrue(p.intersectsOrIsWithin(1100, 1000, 1900, 1000)); + assertTrue(p.intersectsOrIsWithin(0, 0, 1500,1500)); + assertTrue(p.intersectsOrIsWithin(500, 1500, 1500, 1500)); + assertTrue(p.intersectsOrIsWithin(500, 1500, 2000, 1500)); + assertTrue(p.intersectsOrIsWithin(1400, 1500, 1500, 1500)); + } + +} From 1fd973daf2b2d890fffd2877ef1e83e91b126563 Mon Sep 17 00:00:00 2001 From: ntruchsess Date: Mon, 22 Jan 2018 15:39:38 +0100 Subject: [PATCH 02/14] rewrite calculation of bounding circle using coslat-transformed lon-values. --- .../java/btools/router/OsmNogoPolygon.java | 484 ++++++++++-------- .../btools/router/OsmNogoPolygonTest.java | 79 ++- 2 files changed, 322 insertions(+), 241 deletions(-) diff --git a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java index 05f85d9..7164527 100644 --- a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java +++ b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java @@ -1,19 +1,25 @@ -/* - * Copyright 2018 Norbert Truchsess - * - * this code is based on work of Dan Sunday published at: - * http://geomalgorithms.com/a03-_inclusion.html - * (implementation of winding number algorithm in c) - * http://geomalgorithms.com/a08-_containers.html - * (fast computation of bounding circly in c) - * - * Copyright 2001 softSurfer, 2012 Dan Sunday - * 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. - */ +/********************************************************************************************** + 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; @@ -21,266 +27,297 @@ import java.util.List; public class OsmNogoPolygon extends OsmNodeNamed { - public final class Point { - /** - * The latitude - */ - public final int y; + private final static class Point + { + final int y; + final int x; - /** - * The longitude - */ - public final int x; - - public Point(final int lon, final int lat) + Point(final int lon, final int lat) { x = lon; y = lat; } } - public List P = new ArrayList(); + private final List points = new ArrayList(); - public void addVertex(int lon, int lat) + public final void addVertex(int lon, int lat) { - P.add(new Point(lon, 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; + } + +/** + * method 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() { - double Cx, Cy; // Center of ball - double rad, rad2; // radius and radius squared - double xmin, xmax, ymin, ymax; // bounding box extremes - int i_xmin, i_xmax, i_ymin, i_ymax; // index of P[] at box extreme - - // find a large diameter to start with - // first get the bounding box and P[] extreme points for it - xmin = xmax = P.get(0).x; - ymin = ymax = P.get(0).y; - i_xmin = i_xmax = i_ymin = i_ymax = 0; - for (int i = 1; i < P.size(); i++) - { - Point Pi = P.get(i); - if (Pi.x < xmin) - { - xmin = Pi.x; - i_xmin = i; - } - else if (Pi.x > xmax) - { - xmax = Pi.x; - i_xmax = i; - } - if (Pi.y < ymin) - { - ymin = Pi.y; - i_ymin = i; - } - else if (Pi.y > ymax) - { - ymax = Pi.y; - i_ymax = i; - } - } - // select the largest extent as an initial diameter for the ball - Point Pi_xmax = P.get(i_xmax); - Point Pi_xmin = P.get(i_xmin); - Point Pi_ymax = P.get(i_ymax); - Point Pi_ymin = P.get(i_ymin); + int cxmin, cxmax, cymin, cymax; + cxmin = cymin = Integer.MAX_VALUE; + cxmax = cymax = Integer.MIN_VALUE; - int dPx_x = (Pi_xmax.x - Pi_xmin.x); // diff of Px max and min - int dPx_y = Pi_xmax.y - Pi_xmin.y; - - int dPy_x = Pi_ymax.x - Pi_ymin.x; // diff of Py max and min - int dPy_y = Pi_ymax.y - Pi_ymin.y; - - int dx2 = dPx_x * dPx_x + dPx_y * dPx_y; // Px diff squared - int dy2 = dPy_x * dPy_x + dPy_y * dPy_y; // Py diff squared - - if (dx2 >= dy2) // x direction is largest extent + // first calculate a starting center point as center of boundingbox + for (int i = 0; i < points.size(); i++) { - Cx = Pi_xmin.x + dPx_x / 2.0; // Center = midpoint of extremes - Cy = Pi_xmin.y + dPx_x / 2.0; - - double dPC_x = Pi_xmax.x - Cx; - double dPC_y = Pi_xmax.y - Cy; - - rad2 = dPC_x * dPC_x + dPC_y * dPC_y; // radius squared - - } - else // y direction is largest extent - { - Cx = Pi_ymin.x + dPy_x / 2.0; // Center = midpoint of extremes - Cy = Pi_ymin.y + dPy_y / 2.0; - - double dPC_x = Pi_ymax.x - Cx; - double dPC_y = Pi_ymax.y - Cy; - - rad2 = dPC_x * dPC_x + dPC_y * dPC_y; // radius squared - } - rad = Math.sqrt(rad2); - - // now check that all points P[i] are in the ball - // and if not, expand the ball just enough to include them - double dist, dist2; - for (int i = 0; i < P.size(); i++) - { - Point Pi = P.get(i); - - double dPC_x = Pi.x - Cx; - double dPC_y = Pi.y - Cy; - - dist2 = dPC_x * dPC_x + dPC_y * dPC_y; - - if (dist2 <= rad2) // P[i] is inside the ball already + final Point p = points.get(i); + if (p.x < cxmin) { - continue; + 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; } - // P[i] not in ball, so expand ball to include it - dist = Math.sqrt(dist2); - rad = (rad + dist) / 2.0; // enlarge radius just enough - rad2 = rad * rad; - - double dd = (dist - rad) / dist; - - Cx = Cx + dd * dPC_x; // shift Center toward - Cy = Cy + dd * dPC_y; } - ilon = (int) Math.round(Cx); - ilat = (int) Math.round(Cy); + + 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.max(Math.abs(Cx - ilon), Math.abs(Cy - ilat)); + radius = rad + Math.sqrt(dpx * dpx + dpy * dpy); return; } public boolean intersectsOrIsWithin(int lon0, int lat0, int lon1, int lat1) { - Point P0 = new Point (lon0,lat0); - Point P1 = new Point (lon1,lat1); + Point p0 = new Point (lon0,lat0); + Point p1 = new Point (lon1,lat1); // is start or endpoint within polygon? - if ((wn_PnPoly(P0, P) > 0) || (wn_PnPoly(P1, P) > 0)) + if ((wn_PnPoly(p0, points) > 0) || (wn_PnPoly(p1, points) > 0)) { return true; } - Point P2 = P.get(0); - for (int i = 1; i < P.size(); i++) + int i_last = points.size()-1; + Point p2 = points.get(i_last); + for (int i = 0; i <= i_last; i++) { - Point P3 = P.get(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) + if (intersect2D_2Segments(p0,p1,p2,p3) > 0) { return true; } - P2 = P3; + p2 = p3; } return false; } - /** - * isLeft(): tests if a point is Left|On|Right of an infinite line. Input: - * three points P0, P1, and P2 Return: >0 for P2 left of the line through P0 - * and P1 =0 for P2 on the line <0 for P2 right of the line See: Algorithm 1 - * "Area of Triangles and Polygons" - */ - - private static int isLeft(Point P0, Point P1, Point P2) { - return ((P1.x - P0.x) * (P2.y - P0.y) - (P2.x - P0.x) * (P1.y - P0.y)); - } - - /** - * cn_PnPoly(): crossing number test for a point in a polygon Input: P = a - * point, V[] = vertex points of a polygon V[n+1] with V[n]=V[0] Return: 0 = - * outside, 1 = inside This code is patterned after [Franklin, 2000] - */ - - private static boolean cn_PnPoly(Point P, List V) +/** + * Copyright 2001 softSurfer, 2012 Dan Sunday + * 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. + * + * cn_PnPoly(): crossing number test for a point in a polygon Input: P = a + * point, V[] = vertex points of a polygon V[n+1] with V[n]=V[0] Return: 0 = + * outside, 1 = inside This code is patterned after [Franklin, 2000] + */ + private static boolean cn_PnPoly(final Point p, final List v) { int cn = 0; // the crossing number counter // loop through all edges of the polygon - int last = V.size()-1; - Point Vi = V.get(last); + int last = v.size()-1; + Point v0 = v.get(last); for (int i = 0; i <= last; i++) // edge from V[i] to V[i+1] { - Point Vi1 = V.get(i); + Point v1 = v.get(i); - if (((Vi.y <= P.y) && (Vi1.y > P.y)) // an upward crossing - || ((Vi.y > P.y) && (Vi1.y <= P.y))) // a downward crossing + if (((v0.y <= p.y) && (v1.y > p.y)) // an upward crossing + || ((v0.y > p.y) && (v1.y <= p.y))) // a downward crossing { // compute the actual edge-ray intersect x-coordinate - float vt = (float) (P.y - Vi.y) / (Vi1.y - Vi.y); + double vt = (double) (p.y - v0.y) / (v1.y - v0.y); - if (P.x < Vi.x + vt * (Vi1.x - Vi.x)) // P.x < intersect + if (p.x < v0.x + vt * (v1.x - v0.x)) // P.x < intersect { ++cn; // a valid crossing of y=P.y right of P.x } } - Vi = Vi1; + v0 = v1; } return ((cn & 1) > 0); // 0 if even (out), and 1 if odd (in) } - /** - * wn_PnPoly(): winding number test for a point in a polygon Input: P = a - * point, V = vertex points of a polygon V[n+1] with V[n]=V[0] Return: wn = - * the winding number (=0 only when P is outside) - */ +/** + * Copyright 2001 softSurfer, 2012 Dan Sunday + * 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. + * + * wn_PnPoly(): winding number test for a point in a polygon Input: P = a + * point, V = vertex points of a polygon V[n+1] with V[n]=V[0] Return: wn = + * the winding number (=0 only when P is outside) + */ - private static int wn_PnPoly(Point P, List V) { + private static int wn_PnPoly(final Point p, final List v) { int wn = 0; // the winding number counter - + + final int px = p.x; + final int py = p.y; + // loop through all edges of the polygon - int last = V.size()-1; - Point Vi = V.get(last); - for (int i = 0; i <= last; i++) // edge from V[i] to V[i+1] + final int i_last = v.size()-1; + final Point p0 = v.get(i_last); + long p0x = p0.x; // need to use long to avoid overflow in products + long p0y = p0.y; + + for (int i = 0; i <= i_last; i++) // edge from v[i] to v[i+1] { - Point Vi1 = V.get(i); + final Point p1 = v.get(i); + final long p1x = p1.x; + final long p1y = p1.y; - if (Vi.y <= P.y) { // start y <= P.y - if (Vi1.y > P.y) { // an upward crossing - if (isLeft(Vi, Vi1, P) > 0) { // P left of edge - ++wn; // have a valid up intersect + 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 (Vi1.y <= P.y) { // a downward crossing - if (isLeft(Vi, Vi1, P) < 0) { // P right of edge - --wn; // have a valid down 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 } } } - Vi = Vi1; + p0x = p1x; + p0y = p1y; } return wn; } - /** - * inSegment(): determine if a point is inside a segment - * Input: a point P, and a collinear segment S - * Return: 1 = P is inside S - * 0 = P is not inside S - */ - - private static boolean inSegment( Point P, Point SP0, Point SP1) +/** + * Copyright 2001 softSurfer, 2012 Dan Sunday + * 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 + * Input: a point P, and a collinear segment S + * 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) { - if (SP0.x != SP1.x) // S is not vertical + final int sp0x = seg_p0.x; + final int sp1x = seg_p1.x; + + if (sp0x != sp1x) // S is not vertical { - if (SP0.x <= P.x && P.x <= SP1.x) + final int px = p.x; + if (sp0x <= px && px <= sp1x) { return true; } - if (SP0.x >= P.x && P.x >= SP1.x) + if (sp0x >= px && px >= sp1x) { return true; } } - else // S is vertical, so test y coordinate + else // S is vertical, so test y coordinate { - if (SP0.y <= P.y && P.y <= SP1.y) + 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 (SP0.y >= P.y && P.y >= SP1.y) + if (sp0y >= py && py >= sp1y) { return true; } @@ -288,26 +325,33 @@ public class OsmNogoPolygon extends OsmNodeNamed return false; } - /** - * intersect2D_2Segments(): find the 2D intersection of 2 finite segments - * Input: two finite segments S1 and S2 - * Return: 0=disjoint (no intersect) - * 1=intersect in unique point I0 - * 2=overlap in segment from I0 to I1 - */ - private static int intersect2D_2Segments( Point S1P0, Point S1P1, Point S2P0, Point S2P1 ) +/** + * Copyright 2001 softSurfer, 2012 Dan Sunday + * 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 + * Input: two finite segments S1 and S2 + * 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 ) { - int ux = S1P1.x - S1P0.x; // vector u = S1P1-S1P0 (segment 1) - int uy = S1P1.y - S1P0.y; - int vx = S2P1.x - S2P0.x; // vector v = S2P1-S2P0 (segment 2) - int vy = S2P1.y - S2P0.y; - int wx = S1P0.x - S2P0.x; // vector w = S1P0-S2P0 (from start of segment 2 to start of segment 1 - int wy = S1P0.y - S2P0.y; + 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; - int D = ux * vy - uy * vx; + 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 (d == 0) // S1 and S2 are parallel { if ((ux * wy - uy * wx) != 0 || (vx * wy - vy * wx) != 0) { @@ -316,24 +360,24 @@ public class OsmNogoPolygon extends OsmNodeNamed // they are collinear or degenerate // check if they are degenerate points - boolean du = ux == 0 && uy == 0; - boolean dv = vx == 0 && vy == 0; + 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? + 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? + return inSegment(s2p0, s1p0, s1p1) ? 1 : 0; // is it part of S1? } // they are collinear segments - get overlap (or not) - float t0, t1; // endpoints of S1 in eqn for S2 - int w2x = S1P1.x - S2P0.x; // vector w2 = S1P1-S2P0 (from start of segment 2 to end of segment 1) - int w2y = S1P1.y - S2P0.y; + 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; @@ -346,7 +390,7 @@ public class OsmNogoPolygon extends OsmNodeNamed } if (t0 > t1) // must have t0 smaller than t1 { - float t=t0; // swap if not + final double t=t0; // swap if not t0=t1; t1=t; } @@ -363,14 +407,14 @@ public class OsmNogoPolygon extends OsmNodeNamed // the segments are skew and may intersect in a point // get the intersect parameter for S1 - double sI = (vx * wy - vy * wx) / D; + 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 - double tI = (ux * wy - uy * wx) / D; + 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/test/java/btools/router/OsmNogoPolygonTest.java b/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java index a53ddac..4d81cff 100644 --- a/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java +++ b/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java @@ -1,3 +1,20 @@ +/********************************************************************************************** + 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.*; @@ -8,40 +25,60 @@ import org.junit.Test; public class OsmNogoPolygonTest { OsmNogoPolygon p; + + final double[] lons = { 1.0, 1.0, 0.5, 0.5, 1.0, 1.0, -1.0, -1.0 }; + final double[] lats = { -1.0, -0.1, -0.1, 0.1, 0.1, 1.0, 1.0, -1.0 }; + + int toOsmLon(double lon) { + return (int)( ( lon + 180. ) *1000000. + 0.5); // see ServerHandler.readPosition() + } + + int toOsmLat(double lat) { + return (int)( ( lat + 90. ) *1000000. + 0.5); + } + + 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; + } @Before public void setUp() throws Exception { p = new OsmNogoPolygon(); - p.addVertex(1000, 1000); - p.addVertex(2001, 1000); - p.addVertex(2001, 1250); - p.addVertex(1750, 1250); - p.addVertex(1750, 1750); - p.addVertex(2001, 1750); - p.addVertex(2001, 2001); - p.addVertex(1000, 2001); + for (int i = 0; i= r1("+r1+")", diff >= 0); + } } @Test public void testIntersectsOrIsWithin() { - assertFalse(p.intersectsOrIsWithin(0,0, 0,0)); - assertFalse(p.intersectsOrIsWithin(1800,1500, 1800,1500)); - assertFalse(p.intersectsOrIsWithin(1500,2002, 1500,2002)); - assertTrue(p.intersectsOrIsWithin(1750, 1500, 1800,1500)); - assertTrue(p.intersectsOrIsWithin(1500, 2001, 1500,2002)); - assertTrue(p.intersectsOrIsWithin(1100, 1000, 1900, 1000)); - assertTrue(p.intersectsOrIsWithin(0, 0, 1500,1500)); - assertTrue(p.intersectsOrIsWithin(500, 1500, 1500, 1500)); - assertTrue(p.intersectsOrIsWithin(500, 1500, 2000, 1500)); - assertTrue(p.intersectsOrIsWithin(1400, 1500, 1500, 1500)); + double[] p0lons = { 0.0, 1.0, -0.5, 0.5, 0.7, 0.7, 0.7, -1.5, }; + double[] p0lats = { 0.0, 0.0, 0.5, 0.5, 0.5, 0.05, 0.05, -1.5, }; + double[] p1lons = { 0.0, 1.0, 0.5, 1.0, 0.7, 0.7, 0.7, -0.5, }; + double[] p1lats = { 0.0, 0.0, 0.5, 0.5, -0.5, -0.5, -0.05, -0.5, }; + boolean[] within = { true, false, true, true, true, true, false, true, }; + + for (int i=0; i Date: Mon, 22 Jan 2018 16:18:38 +0100 Subject: [PATCH 03/14] update javadoc --- .../java/btools/router/OsmNogoPolygon.java | 161 ++++++++++-------- 1 file changed, 93 insertions(+), 68 deletions(-) diff --git a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java index 7164527..40bc553 100644 --- a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java +++ b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java @@ -55,22 +55,22 @@ public class OsmNogoPolygon extends OsmNodeNamed return 1.- l2 + l4 / 6.; // - l6 / 90; } -/** - * method 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. - */ + /** + * 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; @@ -159,6 +159,22 @@ public class OsmNogoPolygon extends OsmNodeNamed return; } + /** + * intersectsOrIsWithin + * + * 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. Any point being positioned on any of the polygons edges is + * defined as being 'inside'. 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 intersectsOrIsWithin(int lon0, int lat0, int lon1, int lat1) { Point p0 = new Point (lon0,lat0); @@ -183,18 +199,22 @@ public class OsmNogoPolygon extends OsmNodeNamed return false; } -/** - * Copyright 2001 softSurfer, 2012 Dan Sunday - * 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. - * - * cn_PnPoly(): crossing number test for a point in a polygon Input: P = a - * point, V[] = vertex points of a polygon V[n+1] with V[n]=V[0] Return: 0 = - * outside, 1 = inside This code is patterned after [Franklin, 2000] - */ +/* Copyright 2001 softSurfer, 2012 Dan Sunday, 2018 Norbert Truchses + 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. */ + /** + * cn_PnPoly(): crossing 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 0 = outside, 1 = inside. + * + * This code is patterned after [Franklin, 2000] + */ private static boolean cn_PnPoly(final Point p, final List v) { int cn = 0; // the crossing number counter @@ -222,19 +242,20 @@ public class OsmNogoPolygon extends OsmNodeNamed return ((cn & 1) > 0); // 0 if even (out), and 1 if odd (in) } -/** - * Copyright 2001 softSurfer, 2012 Dan Sunday - * 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. - * - * wn_PnPoly(): winding number test for a point in a polygon Input: P = a - * point, V = vertex points of a polygon V[n+1] with V[n]=V[0] Return: wn = - * the winding number (=0 only when P is outside) - */ - +/* Copyright 2001 softSurfer, 2012 Dan Sunday, 2018 Norbert Truchses + 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) + */ private static int wn_PnPoly(final Point p, final List v) { int wn = 0; // the winding number counter @@ -277,19 +298,21 @@ public class OsmNogoPolygon extends OsmNodeNamed return wn; } -/** - * Copyright 2001 softSurfer, 2012 Dan Sunday - * 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 - * Input: a point P, and a collinear segment S - * Return: 1 = P is inside S - * 0 = P is not inside S - */ +/* Copyright 2001 softSurfer, 2012 Dan Sunday, 2018 Norbert Truchses + 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; @@ -325,20 +348,22 @@ public class OsmNogoPolygon extends OsmNodeNamed return false; } -/** - * Copyright 2001 softSurfer, 2012 Dan Sunday - * 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 - * Input: two finite segments S1 and S2 - * Return: 0=disjoint (no intersect) - * 1=intersect in unique point I0 - * 2=overlap in segment from I0 to I1 - */ +/* Copyright 2001 softSurfer, 2012 Dan Sunday, 2018 Norbert Truchses + 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) From 32a49bfa32d7fadf2f3224dc5c21fb6deccd825b Mon Sep 17 00:00:00 2001 From: ntruchsess Date: Mon, 22 Jan 2018 18:59:10 +0100 Subject: [PATCH 04/14] add method 'isWithin' for single WP (being called from RoutingContext.cleanNogolist) --- .../java/btools/router/OsmNogoPolygon.java | 42 +++++++++++++------ .../java/btools/router/RoutingContext.java | 4 +- .../btools/router/OsmNogoPolygonTest.java | 15 ++++++- 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java index 40bc553..6e467ea 100644 --- a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java +++ b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java @@ -160,12 +160,26 @@ public class OsmNogoPolygon extends OsmNodeNamed } /** - * intersectsOrIsWithin - * + * tests whether a point is within the polygon. + * The current implementation doesn't produce consistent results for points + * being located exactly on the edge of the polygon. That doesn't have + * major impact on the routing-results though. + * For this method 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 lon longitude of point + * @param lat latitude of point + * @return true if point is inside of polygon, false otherwise + */ + public boolean isWithin(int lon, int lat) + { + return wn_PnPoly(new Point(lon,lat),points) > 0; + } + + /** * 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. Any point being positioned on any of the polygons edges is - * defined as being 'inside'. For this test the winding-number algorithm is + * 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. * @@ -177,8 +191,8 @@ public class OsmNogoPolygon extends OsmNodeNamed */ public boolean intersectsOrIsWithin(int lon0, int lat0, int lon1, int lat1) { - Point p0 = new Point (lon0,lat0); - Point p1 = new Point (lon1,lat1); + final Point p0 = new Point (lon0,lat0); + final Point p1 = new Point (lon1,lat1); // is start or endpoint within polygon? if ((wn_PnPoly(p0, points) > 0) || (wn_PnPoly(p1, points) > 0)) { @@ -199,7 +213,7 @@ public class OsmNogoPolygon extends OsmNodeNamed return false; } -/* Copyright 2001 softSurfer, 2012 Dan Sunday, 2018 Norbert Truchses +/* 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 @@ -242,7 +256,7 @@ public class OsmNogoPolygon extends OsmNodeNamed return ((cn & 1) > 0); // 0 if even (out), and 1 if odd (in) } -/* Copyright 2001 softSurfer, 2012 Dan Sunday, 2018 Norbert Truchses +/* 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 @@ -259,8 +273,8 @@ public class OsmNogoPolygon extends OsmNodeNamed private static int wn_PnPoly(final Point p, final List v) { int wn = 0; // the winding number counter - final int px = p.x; - final int py = p.y; + final long px = p.x; + final long py = p.y; // loop through all edges of the polygon final int i_last = v.size()-1; @@ -283,7 +297,9 @@ public class OsmNogoPolygon extends OsmNodeNamed ++wn; // have a valid up intersect } } - } else { // start y > p.y (no test needed) + } + 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) @@ -298,7 +314,7 @@ public class OsmNogoPolygon extends OsmNodeNamed return wn; } -/* Copyright 2001 softSurfer, 2012 Dan Sunday, 2018 Norbert Truchses +/* 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 @@ -348,7 +364,7 @@ public class OsmNogoPolygon extends OsmNodeNamed return false; } -/* Copyright 2001 softSurfer, 2012 Dan Sunday, 2018 Norbert Truchses +/* 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 diff --git a/brouter-core/src/main/java/btools/router/RoutingContext.java b/brouter-core/src/main/java/btools/router/RoutingContext.java index b903977..4b0cea4 100644 --- a/brouter-core/src/main/java/btools/router/RoutingContext.java +++ b/brouter-core/src/main/java/btools/router/RoutingContext.java @@ -215,7 +215,9 @@ 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).isWithin(wp.ilon, wp.ilat))) { goodGuy = false; break; diff --git a/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java b/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java index 4d81cff..a1f2d7c 100644 --- a/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java +++ b/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java @@ -68,6 +68,19 @@ public class OsmNogoPolygonTest { } } + @Test + public void testIsWithin() { + // for points exactly on the edge of the polygon the result is not the same for all directions. + // that doesn't have a major impact on routing though. + 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, }; // false, false, false, false, false, + + for (int i=0; i Date: Mon, 22 Jan 2018 23:24:59 +0100 Subject: [PATCH 05/14] add parsing of NogoPolygons to ServerHandler --- .../java/btools/routingapp/BRouterWorker.java | 2 +- .../btools/server/request/ServerHandler.java | 37 ++++++++++++++++++- 2 files changed, 36 insertions(+), 3 deletions(-) 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-server/src/main/java/btools/server/request/ServerHandler.java b/brouter-server/src/main/java/btools/server/request/ServerHandler.java index 8388411..a0d1f4d 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; @@ -57,10 +58,16 @@ public class ServerHandler extends RequestHandler { List nogoList = readNogoList(); if ( nogoList != null ) { - rc.prepareNogoPoints( nogoList ); + RoutingContext.prepareNogoPoints( nogoList ); rc.nogopoints = nogoList; } + List nogoPolygonsList = readNogoPolygons(); + if ( nogoPolygonsList != null ) + { + rc.nogopoints.addAll(nogoPolygonsList); + } + return rc; } @@ -224,5 +231,31 @@ public class ServerHandler extends RequestHandler { n.ilat = (int)( ( lat + 90. ) *1000000. + 0.5); n.isNogo = true; return n; - } + } + + private List readNogoPolygons() + { + String polygons = params.get( "polygons" ); + if ( polygons == null ) return null; + + String[] polygonList = polygons.split("\\|"); + + List nogoPolygonList = new ArrayList(); + for (int i = 0; i < polygonList.length; i++) + { + String[] lonLatList = polygonList[i].split(","); + OsmNogoPolygon polygon = new OsmNogoPolygon(); + for (int j = 0; j < lonLatList.length; j++) + { + String slon = lonLatList[i++]; + String slat = lonLatList[i]; + int lon = (int)( ( Double.parseDouble(slon) + 180. ) *1000000. + 0.5); + int lat = (int)( ( Double.parseDouble(slat) + 90. ) *1000000. + 0.5); + polygon.addVertex(lon, lat); + } + polygon.calcBoundingCircle(); + nogoPolygonList.add(polygon); + } + return nogoPolygonList; + } } From 144c0018de78d9381d19decdc6cd38a0a6afef7d Mon Sep 17 00:00:00 2001 From: ntruchsess Date: Tue, 23 Jan 2018 23:57:17 +0100 Subject: [PATCH 06/14] fix parsing and generics errors --- .../java/btools/router/OsmNogoPolygon.java | 5 +++++ .../btools/server/request/ServerHandler.java | 21 ++++++++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java index 6e467ea..8172257 100644 --- a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java +++ b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java @@ -27,6 +27,11 @@ import java.util.List; public class OsmNogoPolygon extends OsmNodeNamed { + public OsmNogoPolygon() + { + isNogo = true; + } + private final static class Point { final int y; 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 a0d1f4d..6b36ee4 100644 --- a/brouter-server/src/main/java/btools/server/request/ServerHandler.java +++ b/brouter-server/src/main/java/btools/server/request/ServerHandler.java @@ -62,10 +62,17 @@ public class ServerHandler extends RequestHandler { rc.nogopoints = nogoList; } - List nogoPolygonsList = readNogoPolygons(); + List nogoPolygonsList = readNogoPolygons(); if ( nogoPolygonsList != null ) { - rc.nogopoints.addAll(nogoPolygonsList); + if (rc.nogopoints == null) + { + rc.nogopoints = nogoPolygonsList; + } + else + { + rc.nogopoints.addAll(nogoPolygonsList); + } } return rc; @@ -233,22 +240,22 @@ public class ServerHandler extends RequestHandler { return n; } - private List readNogoPolygons() + private List readNogoPolygons() { String polygons = params.get( "polygons" ); if ( polygons == null ) return null; String[] polygonList = polygons.split("\\|"); - List nogoPolygonList = new ArrayList(); + List nogoPolygonList = new ArrayList(); for (int i = 0; i < polygonList.length; i++) { String[] lonLatList = polygonList[i].split(","); OsmNogoPolygon polygon = new OsmNogoPolygon(); - for (int j = 0; j < lonLatList.length; j++) + for (int j = 0; j < lonLatList.length-1;) { - String slon = lonLatList[i++]; - String slat = lonLatList[i]; + 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); From 1fc6c9e62cc0454b5873492c8ee527b468aed53f Mon Sep 17 00:00:00 2001 From: ntruchsess Date: Wed, 24 Jan 2018 15:40:34 +0100 Subject: [PATCH 07/14] fix radius-calculation, clockwise windingnumber and wp-init --- .../java/btools/router/OsmNogoPolygon.java | 28 +++++------- .../btools/router/OsmNogoPolygonTest.java | 2 +- .../btools/server/request/ServerHandler.java | 44 +++++++++++-------- 3 files changed, 36 insertions(+), 38 deletions(-) diff --git a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java index 8172257..97f08c3 100644 --- a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java +++ b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java @@ -27,11 +27,6 @@ import java.util.List; public class OsmNogoPolygon extends OsmNodeNamed { - public OsmNogoPolygon() - { - isNogo = true; - } - private final static class Point { final int y; @@ -44,7 +39,7 @@ public class OsmNogoPolygon extends OsmNodeNamed } } - private final List points = new ArrayList(); + public final List points = new ArrayList(); public final void addVertex(int lon, int lat) { @@ -160,12 +155,12 @@ public class OsmNogoPolygon extends OsmNodeNamed dpx = cx - ilon; // rounding error dpy = cy - ilat; // compensate rounding error of center-point - radius = rad + Math.sqrt(dpx * dpx + dpy * dpy); + radius = (rad + Math.sqrt(dpx * dpx + dpy * dpy)) * 0.000001; return; } /** - * tests whether a point is within the polygon. + * tests whether a point is within the polygon. * The current implementation doesn't produce consistent results for points * being located exactly on the edge of the polygon. That doesn't have * major impact on the routing-results though. @@ -178,9 +173,9 @@ public class OsmNogoPolygon extends OsmNodeNamed */ public boolean isWithin(int lon, int lat) { - return wn_PnPoly(new Point(lon,lat),points) > 0; + return wn_PnPoly(lon,lat,points) != 0; } - + /** * 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 @@ -196,13 +191,13 @@ public class OsmNogoPolygon extends OsmNodeNamed */ public boolean intersectsOrIsWithin(int lon0, int lat0, int lon1, int lat1) { - final Point p0 = new Point (lon0,lat0); - final Point p1 = new Point (lon1,lat1); // is start or endpoint within polygon? - if ((wn_PnPoly(p0, points) > 0) || (wn_PnPoly(p1, points) > 0)) + if ((wn_PnPoly(lon0,lat0, points) != 0) || (wn_PnPoly(lon1,lat1, points) != 0)) { return true; } + final Point p0 = new Point (lon0,lat0); + final Point p1 = new Point (lon1,lat1); int i_last = points.size()-1; Point p2 = points.get(i_last); for (int i = 0; i <= i_last; i++) @@ -275,12 +270,9 @@ public class OsmNogoPolygon extends OsmNodeNamed * is implicitly closed connecting the last and first point. * @return the winding number (=0 only when P is outside) */ - private static int wn_PnPoly(final Point p, final List v) { + private static int wn_PnPoly(final long px, final long py, final List v) { int wn = 0; // the winding number counter - - final long px = p.x; - final long py = p.y; - + // loop through all edges of the polygon final int i_last = v.size()-1; final Point p0 = v.get(i_last); diff --git a/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java b/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java index a1f2d7c..bda1d7c 100644 --- a/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java +++ b/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java @@ -62,7 +62,7 @@ public class OsmNogoPolygonTest { double py = toOsmLat(lats[i]); double dpx = (toOsmLon(lons[i]) - p.ilon) * coslat(p.ilat); double dpy = py - p.ilat; - double r1 = Math.sqrt(dpx * dpx + dpy * dpy); + double r1 = Math.sqrt(dpx * dpx + dpy * dpy) * 0.000001; double diff = r-r1; assertTrue("i: "+i+" r("+r+") >= r1("+r1+")", diff >= 0); } 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 6b36ee4..98088d5 100644 --- a/brouter-server/src/main/java/btools/server/request/ServerHandler.java +++ b/brouter-server/src/main/java/btools/server/request/ServerHandler.java @@ -56,23 +56,21 @@ public class ServerHandler extends RequestHandler { rc.setAlternativeIdx(Integer.parseInt(params.get( "alternativeidx" ))); List nogoList = readNogoList(); + List nogoPolygonsList = readNogoPolygons(); + if ( nogoList != null ) { RoutingContext.prepareNogoPoints( nogoList ); rc.nogopoints = nogoList; } - List nogoPolygonsList = readNogoPolygons(); - if ( nogoPolygonsList != null ) + if (rc.nogopoints == null) { - if (rc.nogopoints == null) - { - rc.nogopoints = nogoPolygonsList; - } - else - { - rc.nogopoints.addAll(nogoPolygonsList); - } + rc.nogopoints = nogoPolygonsList; + } + else if ( nogoPolygonsList != null ) + { + rc.nogopoints.addAll(nogoPolygonsList); } return rc; @@ -251,17 +249,25 @@ public class ServerHandler extends RequestHandler { for (int i = 0; i < polygonList.length; i++) { String[] lonLatList = polygonList[i].split(","); - OsmNogoPolygon polygon = new OsmNogoPolygon(); - for (int j = 0; j < lonLatList.length-1;) + if ( 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); + OsmNogoPolygon polygon = new OsmNogoPolygon(); + 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.name = ""; + polygon.isNogo = true; + polygon.calcBoundingCircle(); + nogoPolygonList.add(polygon); + } } - polygon.calcBoundingCircle(); - nogoPolygonList.add(polygon); } return nogoPolygonList; } From 05b0b6d3628f8f6a8a1f14b9258262a43c8e7191 Mon Sep 17 00:00:00 2001 From: ntruchsess Date: Sun, 4 Feb 2018 18:58:16 +0100 Subject: [PATCH 08/14] more elaborated NogoPolygon unit-test --- .../btools/router/OsmNogoPolygonTest.java | 60 +++++++++++-------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java b/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java index bda1d7c..7aa95dc 100644 --- a/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java +++ b/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java @@ -17,27 +17,32 @@ **********************************************************************************************/ package btools.router; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; -import org.junit.Before; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; public class OsmNogoPolygonTest { - OsmNogoPolygon p; + static final int offset_x = 11000000; + static final int offset_y = 50000000; + + static OsmNogoPolygon polygon; - final double[] lons = { 1.0, 1.0, 0.5, 0.5, 1.0, 1.0, -1.0, -1.0 }; - final double[] lats = { -1.0, -0.1, -0.1, 0.1, 0.1, 1.0, 1.0, -1.0 }; + 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 }; - int toOsmLon(double lon) { - return (int)( ( lon + 180. ) *1000000. + 0.5); // see ServerHandler.readPosition() + static int toOsmLon(double lon) { + return (int)( ( lon + 180. ) *1000000. + 0.5)+offset_x; // see ServerHandler.readPosition() } - int toOsmLat(double lat) { - return (int)( ( lat + 90. ) *1000000. + 0.5); + static int toOsmLat(double lat) { + return (int)( ( lat + 90. ) *1000000. + 0.5)+offset_y; } - double coslat(int lat) // see RoutingContext.calcDistance() + 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; @@ -46,22 +51,27 @@ public class OsmNogoPolygonTest { return 1.- l2 + l4 / 6.; // - l6 / 90; } - @Before - public void setUp() throws Exception { - p = new OsmNogoPolygon(); + @BeforeClass + public static void setUp() throws Exception { + polygon = new OsmNogoPolygon(); for (int i = 0; i= r1("+r1+")", diff >= 0); @@ -77,20 +87,20 @@ public class OsmNogoPolygonTest { boolean[] within = { true, false, false, false, false, }; // false, false, false, false, false, for (int i=0; i Date: Sun, 4 Feb 2018 19:24:44 +0100 Subject: [PATCH 09/14] fix NogoPolygon radius being modified --- .../src/main/java/btools/router/RoutingContext.java | 10 ++++++---- .../test/java/btools/router/OsmNogoPolygonTest.java | 1 - 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/brouter-core/src/main/java/btools/router/RoutingContext.java b/brouter-core/src/main/java/btools/router/RoutingContext.java index 4b0cea4..23661de 100644 --- a/brouter-core/src/main/java/btools/router/RoutingContext.java +++ b/brouter-core/src/main/java/btools/router/RoutingContext.java @@ -296,11 +296,13 @@ public final class RoutingContext radius = Math.sqrt( s1 < s2 ? r12 : r22 ); if ( radius > nogo.radius ) continue; // 20m ^ 2 } - if ( nogo.isNogo - && (!(nogo instanceof OsmNogoPolygon) - || ((OsmNogoPolygon)nogo).intersectsOrIsWithin(lon1, lat1, lon2, lat2))) + if ( nogo.isNogo ) { - nogomatch = true; + if (!(nogo instanceof OsmNogoPolygon) + || ((OsmNogoPolygon)nogo).intersectsOrIsWithin(lon1, lat1, lon2, lat2)) + { + nogomatch = true; + } } else { diff --git a/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java b/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java index 7aa95dc..55aa0aa 100644 --- a/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java +++ b/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java @@ -61,7 +61,6 @@ public class OsmNogoPolygonTest { @AfterClass public static void tearDown() throws Exception { - polygon.waitForTracker(); } @Test From 419cb4e78c493a2c91e3d39393d85de75b23dda7 Mon Sep 17 00:00:00 2001 From: ntruchsess Date: Sun, 4 Feb 2018 20:19:33 +0100 Subject: [PATCH 10/14] add junit to brouter-core dependencies --- brouter-core/pom.xml | 5 +++++ pom.xml | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) 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/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 From a0198e3b344fb5edebfea72e7eaccd2f09d66547 Mon Sep 17 00:00:00 2001 From: ntruchsess Date: Wed, 7 Feb 2018 20:50:06 +0100 Subject: [PATCH 11/14] add support for open nogo-polygons --- .../java/btools/router/OsmNogoPolygon.java | 144 +++++++++++------- .../java/btools/router/RoutingContext.java | 6 +- .../btools/router/OsmNogoPolygonTest.java | 73 +++++++-- .../btools/server/request/ServerHandler.java | 53 ++++--- 4 files changed, 180 insertions(+), 96 deletions(-) diff --git a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java index 97f08c3..3014cd8 100644 --- a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java +++ b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java @@ -27,7 +27,7 @@ import java.util.List; public class OsmNogoPolygon extends OsmNodeNamed { - private final static class Point + public final static class Point { final int y; final int x; @@ -40,6 +40,15 @@ public class OsmNogoPolygon extends OsmNodeNamed } 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) { @@ -171,11 +180,11 @@ public class OsmNogoPolygon extends OsmNodeNamed * @param lat latitude of point * @return true if point is inside of polygon, false otherwise */ - public boolean isWithin(int lon, int lat) - { - return wn_PnPoly(lon,lat,points) != 0; - } - +// public boolean isWithin(int lon, int lat) +// { +// return wn_PnPoly(lon,lat,points) != 0; +// } + /** * 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 @@ -189,18 +198,25 @@ public class OsmNogoPolygon extends OsmNodeNamed * @param lat1 latitude of start point * @return true if segment or any of it's points are 'inside' of polygon */ - public boolean intersectsOrIsWithin(int lon0, int lat0, int lon1, int lat1) + public boolean intersects(int lon0, int lat0, int lon1, int lat1) { - // is start or endpoint within polygon? - if ((wn_PnPoly(lon0,lat0, points) != 0) || (wn_PnPoly(lon1,lat1, points) != 0)) - { - return true; - } + // is start or endpoint within closed polygon? +// if (isClosed) +// { +// if (wn_PnPoly(lon1,lat1, points) != 0) +// { +// return true; +// } + // check of wn_PnPoly(lon0,lat0, points) would return true only very few times. + // in the majority of cases (point within bounding-circle but outside of + // polygon both wn_PnPoly and intersect would both run, but intersect-check + // will catch all points inside the polygon as well. +// } final Point p0 = new Point (lon0,lat0); final Point p1 = new Point (lon1,lat1); int i_last = points.size()-1; - Point p2 = points.get(i_last); - for (int i = 0; i <= i_last; i++) + 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? @@ -213,47 +229,56 @@ public class OsmNogoPolygon extends OsmNodeNamed 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. */ - /** - * cn_PnPoly(): crossing 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 0 = outside, 1 = inside. - * - * This code is patterned after [Franklin, 2000] - */ - private static boolean cn_PnPoly(final Point p, final List v) + public boolean isOnPolyline( long px, long py ) { - int cn = 0; // the crossing number counter - - // loop through all edges of the polygon - int last = v.size()-1; - Point v0 = v.get(last); - for (int i = 0; i <= last; i++) // edge from V[i] to V[i+1] + int i_last = points.size()-1; + Point p1 = points.get(0); + for (int i = 1 ; i <= i_last; i++) { - Point v1 = v.get(i); - - if (((v0.y <= p.y) && (v1.y > p.y)) // an upward crossing - || ((v0.y > p.y) && (v1.y <= p.y))) // a downward crossing + final Point p2 = points.get(i); + if (OsmNogoPolygon.isOnLine(px,py,p1.x,p1.y,p2.x,p2.y)) { - // compute the actual edge-ray intersect x-coordinate - double vt = (double) (p.y - v0.y) / (v1.y - v0.y); - - if (p.x < v0.x + vt * (v1.x - v0.x)) // P.x < intersect - { - ++cn; // a valid crossing of y=P.y right of P.x - } + return true; } - v0 = v1; + p1 = p2; } - return ((cn & 1) > 0); // 0 if even (out), and 1 if odd (in) + 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 @@ -270,21 +295,28 @@ public class OsmNogoPolygon extends OsmNodeNamed * is implicitly closed connecting the last and first point. * @return the winding number (=0 only when P is outside) */ - private static int wn_PnPoly(final long px, final long py, final List v) { + 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 = v.size()-1; - final Point p0 = v.get(i_last); + 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 = 0; i <= i_last; i++) // edge from v[i] to v[i+1] + for (int i = isClosed ? 0 : 1; i <= i_last; i++) // edge from v[i] to v[i+1] { - final Point p1 = v.get(i); + 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 @@ -308,7 +340,7 @@ public class OsmNogoPolygon extends OsmNodeNamed p0x = p1x; p0y = p1y; } - return wn; + return wn != 0; } /* Copyright 2001 softSurfer, 2012 Dan Sunday, 2018 Norbert Truchsess diff --git a/brouter-core/src/main/java/btools/router/RoutingContext.java b/brouter-core/src/main/java/btools/router/RoutingContext.java index 23661de..2a66f0b 100644 --- a/brouter-core/src/main/java/btools/router/RoutingContext.java +++ b/brouter-core/src/main/java/btools/router/RoutingContext.java @@ -217,7 +217,9 @@ public final class RoutingContext { if ( wp.calcDistance( nogo ) < radiusInMeter && (!(nogo instanceof OsmNogoPolygon) - || ((OsmNogoPolygon)nogo).isWithin(wp.ilon, wp.ilat))) + || (((OsmNogoPolygon)nogo).isClosed + ? ((OsmNogoPolygon)nogo).isWithin(wp.ilon, wp.ilat) + : ((OsmNogoPolygon)nogo).isOnPolyline(wp.ilon, wp.ilat)))) { goodGuy = false; break; @@ -299,7 +301,7 @@ public final class RoutingContext if ( nogo.isNogo ) { if (!(nogo instanceof OsmNogoPolygon) - || ((OsmNogoPolygon)nogo).intersectsOrIsWithin(lon1, lat1, lon2, lat2)) + || ((OsmNogoPolygon)nogo).intersects(lon1, lat1, lon2, lat2)) { nogomatch = true; } diff --git a/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java b/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java index 55aa0aa..59f7fef 100644 --- a/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java +++ b/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java @@ -18,18 +18,22 @@ 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 }; @@ -53,10 +57,14 @@ public class OsmNogoPolygonTest { @BeforeClass public static void setUp() throws Exception { - polygon = new OsmNogoPolygon(); + 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() { - // for points exactly on the edge of the polygon the result is not the same for all directions. - // that doesn't have a major impact on routing though. - 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, }; // false, false, false, false, false, + 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 readNogoPolygons() { - String polygons = params.get( "polygons" ); - if ( polygons == null ) return null; - - String[] polygonList = polygons.split("\\|"); - - List nogoPolygonList = new ArrayList(); - for (int i = 0; i < polygonList.length; i++) + 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[] lonLatList = polygonList[i].split(","); - if ( lonLatList.length > 1 ) + String[] polygonList = polygons.split("\\|"); + for (int i = 0; i < polygonList.length; i++) { - OsmNogoPolygon polygon = new OsmNogoPolygon(); - for (int j = 0; j < lonLatList.length-1;) + String[] lonLatList = polygonList[i].split(","); + if ( 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.name = ""; - polygon.isNogo = true; - polygon.calcBoundingCircle(); - nogoPolygonList.add(polygon); + 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); + } } } - } - return nogoPolygonList; + } } } From 41201520c713a1e0baa58aac9108a041cc15472a Mon Sep 17 00:00:00 2001 From: Norbert Truchsess Date: Sun, 25 Feb 2018 20:00:50 +0100 Subject: [PATCH 12/14] read NogoPolygons from OsmAnd Tracks --- .../java/btools/router/OsmNogoPolygon.java | 4 +- .../java/btools/router/RoutingContext.java | 24 +++--- .../java/btools/routingapp/BRouterView.java | 50 +++++++++++- .../routingapp/CoordinateReaderOsmAnd.java | 80 +++++++++++++++++++ 4 files changed, 143 insertions(+), 15 deletions(-) diff --git a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java index 3014cd8..bf6fed6 100644 --- a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java +++ b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java @@ -29,8 +29,8 @@ public class OsmNogoPolygon extends OsmNodeNamed { public final static class Point { - final int y; - final int x; + public final int y; + public final int x; Point(final int lon, final int lat) { diff --git a/brouter-core/src/main/java/btools/router/RoutingContext.java b/brouter-core/src/main/java/btools/router/RoutingContext.java index 2a66f0b..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; } } diff --git a/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java b/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java index d611000..d532fe0 100644 --- a/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java +++ b/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java @@ -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; @@ -640,6 +642,41 @@ public class BRouterView extends View canvas.drawCircle( (float) x, (float) y, (float) ir, paint ); } } + + 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,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/CoordinateReaderOsmAnd.java b/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderOsmAnd.java index 917c45a..7824d48 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(true); + 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(); + } + } } From fb00e0d13095c8c55b463a4f898b8ebda9dea5a0 Mon Sep 17 00:00:00 2001 From: Norbert Truchsess Date: Sun, 25 Feb 2018 20:33:10 +0100 Subject: [PATCH 13/14] cleanup --- .../java/btools/router/OsmNogoPolygon.java | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java index bf6fed6..f6ad5ef 100644 --- a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java +++ b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java @@ -168,23 +168,6 @@ public class OsmNogoPolygon extends OsmNodeNamed return; } - /** - * tests whether a point is within the polygon. - * The current implementation doesn't produce consistent results for points - * being located exactly on the edge of the polygon. That doesn't have - * major impact on the routing-results though. - * For this method 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 lon longitude of point - * @param lat latitude of point - * @return true if point is inside of polygon, false otherwise - */ -// public boolean isWithin(int lon, int lat) -// { -// return wn_PnPoly(lon,lat,points) != 0; -// } - /** * 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 @@ -200,18 +183,6 @@ public class OsmNogoPolygon extends OsmNodeNamed */ public boolean intersects(int lon0, int lat0, int lon1, int lat1) { - // is start or endpoint within closed polygon? -// if (isClosed) -// { -// if (wn_PnPoly(lon1,lat1, points) != 0) -// { -// return true; -// } - // check of wn_PnPoly(lon0,lat0, points) would return true only very few times. - // in the majority of cases (point within bounding-circle but outside of - // polygon both wn_PnPoly and intersect would both run, but intersect-check - // will catch all points inside the polygon as well. -// } final Point p0 = new Point (lon0,lat0); final Point p1 = new Point (lon1,lat1); int i_last = points.size()-1; From 16259f1f178d384d63497190b0dd7a95bad883f3 Mon Sep 17 00:00:00 2001 From: Norbert Truchsess Date: Mon, 26 Feb 2018 16:33:14 +0100 Subject: [PATCH 14/14] set default open nogo-lines for OsmAnd --- .../src/main/java/btools/routingapp/CoordinateReaderOsmAnd.java | 2 +- brouter-server/src/main/java/btools/server/BRouter.java | 2 +- brouter-server/src/main/java/btools/server/RouteServer.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 7824d48..b4b059f 100644 --- a/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderOsmAnd.java +++ b/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderOsmAnd.java @@ -152,7 +152,7 @@ public class CoordinateReaderOsmAnd extends CoordinateReader XmlPullParser xpp = factory.newPullParser(); xpp.setInput(new FileReader(file)); - OsmNogoPolygon nogo = new OsmNogoPolygon(true); + OsmNogoPolygon nogo = new OsmNogoPolygon(false); int eventType = xpp.getEventType(); int numSeg = 0; while (eventType != XmlPullParser.END_DOCUMENT) { 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");