diff --git a/README.md b/README.md index cecb125..4f6f9d3 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ +Forked from https://github.com/abrensch/brouter + +- changed processUnused to true for safety, shortest, and trekking +- added lts_score to lookups.dat + + BRouter ======= diff --git a/brouter-core/src/main/java/btools/router/FormatGpx.java b/brouter-core/src/main/java/btools/router/FormatGpx.java index c652a0a..1d0b88c 100644 --- a/brouter-core/src/main/java/btools/router/FormatGpx.java +++ b/brouter-core/src/main/java/btools/router/FormatGpx.java @@ -197,25 +197,32 @@ public class FormatGpx extends Formatter { for (int i = 0; i <= t.pois.size() - 1; i++) { OsmNodeNamed poi = t.pois.get(i); - formatWaypointGpx(sb, poi); + formatWaypointGpx(sb, poi, "poi"); } if (t.exportWaypoints) { for (int i = 0; i <= t.matchedWaypoints.size() - 1; i++) { MatchedWaypoint wt = t.matchedWaypoints.get(i); - sb.append(" \n") - .append(" ").append(StringUtils.escapeXml10(wt.name)).append("\n"); if (i == 0) { - sb.append(" from\n"); + formatWaypointGpx(sb, wt, "from"); } else if (i == t.matchedWaypoints.size() - 1) { - sb.append(" to\n"); + formatWaypointGpx(sb, wt, "to"); } else { - sb.append(" via\n"); + formatWaypointGpx(sb, wt, "via"); } - sb.append(" \n"); } } + if (t.exportCorrectedWaypoints) { + for (int i = 0; i <= t.matchedWaypoints.size() - 1; i++) { + MatchedWaypoint wt = t.matchedWaypoints.get(i); + if (wt.correctedpoint != null) { + OsmNodeNamed n = new OsmNodeNamed(wt.correctedpoint); + n.name = wt.name + "_corr"; + formatWaypointGpx(sb, n, "via_corr"); + } + } + } + sb.append(" \n"); if (turnInstructionMode == 9 || turnInstructionMode == 2 @@ -454,7 +461,7 @@ public class FormatGpx extends Formatter { StringWriter sw = new StringWriter(8192); BufferedWriter bw = new BufferedWriter(sw); formatGpxHeader(bw); - formatWaypointGpx(bw, n); + formatWaypointGpx(bw, n, null); formatGpxFooter(bw); bw.close(); sw.close(); @@ -477,7 +484,7 @@ public class FormatGpx extends Formatter { sb.append("\n"); } - public void formatWaypointGpx(BufferedWriter sb, OsmNodeNamed n) throws IOException { + public void formatWaypointGpx(BufferedWriter sb, OsmNodeNamed n, String type) throws IOException { sb.append(" "); if (n.getSElev() != Short.MIN_VALUE) { @@ -489,6 +496,24 @@ public class FormatGpx extends Formatter { if (n.nodeDescription != null && rc != null) { sb.append("").append(rc.expctxWay.getKeyValueDescription(false, n.nodeDescription)).append(""); } + if (type != null) { + sb.append("").append(type).append(""); + } + sb.append("\n"); + } + + public void formatWaypointGpx(BufferedWriter sb, MatchedWaypoint wp, String type) throws IOException { + sb.append(" "); + if (wp.waypoint.getSElev() != Short.MIN_VALUE) { + sb.append("").append("" + wp.waypoint.getElev()).append(""); + } + if (wp.name != null) { + sb.append("").append(StringUtils.escapeXml10(wp.name)).append(""); + } + if (type != null) { + sb.append("").append(type).append(""); + } sb.append("\n"); } diff --git a/brouter-core/src/main/java/btools/router/FormatJson.java b/brouter-core/src/main/java/btools/router/FormatJson.java index 53f0b4a..d5ba17b 100644 --- a/brouter-core/src/main/java/btools/router/FormatJson.java +++ b/brouter-core/src/main/java/btools/router/FormatJson.java @@ -126,7 +126,7 @@ public class FormatJson extends Formatter { sb.append(" ]\n"); sb.append(" }\n"); - if (t.exportWaypoints || !t.pois.isEmpty()) { + if (t.exportWaypoints || t.exportCorrectedWaypoints || !t.pois.isEmpty()) { sb.append(" },\n"); for (int i = 0; i <= t.pois.size() - 1; i++) { OsmNodeNamed poi = t.pois.get(i); @@ -137,6 +137,7 @@ public class FormatJson extends Formatter { sb.append(" \n"); } if (t.exportWaypoints) { + if (!t.pois.isEmpty()) sb.append(" ,\n"); for (int i = 0; i <= t.matchedWaypoints.size() - 1; i++) { String type; if (i == 0) { @@ -155,6 +156,23 @@ public class FormatJson extends Formatter { sb.append(" \n"); } } + if (t.exportCorrectedWaypoints) { + if (t.exportWaypoints) sb.append(" ,\n"); + boolean hasCorrPoints = false; + for (int i = 0; i <= t.matchedWaypoints.size() - 1; i++) { + String type = "via_corr"; + + MatchedWaypoint wp = t.matchedWaypoints.get(i); + if (wp.correctedpoint != null) { + if (hasCorrPoints) { + sb.append(","); + } + addFeature(sb, type, wp.name + "_corr", wp.correctedpoint.ilat, wp.correctedpoint.ilon, wp.correctedpoint.getSElev()); + sb.append(" \n"); + hasCorrPoints = true; + } + } + } } else { sb.append(" }\n"); } diff --git a/brouter-core/src/main/java/btools/router/FormatKml.java b/brouter-core/src/main/java/btools/router/FormatKml.java index 5798c5c..931689a 100644 --- a/brouter-core/src/main/java/btools/router/FormatKml.java +++ b/brouter-core/src/main/java/btools/router/FormatKml.java @@ -1,5 +1,6 @@ package btools.router; +import java.util.ArrayList; import java.util.List; import btools.mapaccess.MatchedWaypoint; @@ -43,7 +44,7 @@ public class FormatKml extends Formatter { sb.append(" \n"); sb.append(" \n"); sb.append(" \n"); - if (t.exportWaypoints || !t.pois.isEmpty()) { + if (t.exportWaypoints || t.exportCorrectedWaypoints || !t.pois.isEmpty()) { if (!t.pois.isEmpty()) { sb.append(" \n"); sb.append(" poi\n"); @@ -62,6 +63,19 @@ public class FormatKml extends Formatter { } createFolder(sb, "end", t.matchedWaypoints.subList(size - 1, size)); } + if (t.exportCorrectedWaypoints) { + List list = new ArrayList<>(); + for (int i = 0; i < t.matchedWaypoints.size(); i++) { + MatchedWaypoint wp = t.matchedWaypoints.get(i); + if (wp.correctedpoint != null) { + OsmNodeNamed n = new OsmNodeNamed(wp.correctedpoint); + n.name = wp.name + "_corr"; + list.add(n); + } + } + int size = list.size(); + createViaFolder(sb, "via_corr", list.subList(0, size)); + } } sb.append(" \n"); sb.append("\n"); @@ -79,6 +93,17 @@ public class FormatKml extends Formatter { sb.append(" \n"); } + private void createViaFolder(StringBuilder sb, String type, List waypoints) { + if (waypoints.isEmpty()) return; + sb.append(" \n"); + sb.append(" " + type + "\n"); + for (int i = 0; i < waypoints.size(); i++) { + OsmNodeNamed wp = waypoints.get(i); + createPlaceMark(sb, wp.name, wp.ilat, wp.ilon); + } + sb.append(" \n"); + } + private void createPlaceMark(StringBuilder sb, String name, int ilat, int ilon) { sb.append(" \n"); sb.append(" " + StringUtils.escapeXml10(name) + "\n"); diff --git a/brouter-core/src/main/java/btools/router/OsmTrack.java b/brouter-core/src/main/java/btools/router/OsmTrack.java index ccc232a..848493b 100644 --- a/brouter-core/src/main/java/btools/router/OsmTrack.java +++ b/brouter-core/src/main/java/btools/router/OsmTrack.java @@ -23,8 +23,8 @@ import btools.util.CompactLongMap; import btools.util.FrozenLongMap; public final class OsmTrack { - final public static String version = "1.7.7"; - final public static String versionDate = "23072024"; + final public static String version = "1.7.8"; + final public static String versionDate = "12072025"; // csv-header-line private static final String MESSAGES_HEADER = "Longitude\tLatitude\tElevation\tDistance\tCostPerKm\tElevCost\tTurnCost\tNodeCost\tInitialCost\tWayTags\tNodeTags\tTime\tEnergy"; @@ -62,6 +62,7 @@ public final class OsmTrack { protected List matchedWaypoints; public boolean exportWaypoints = false; + public boolean exportCorrectedWaypoints = false; public void addNode(OsmPathElement node) { nodes.add(0, node); @@ -338,6 +339,7 @@ public final class OsmTrack { } float t0 = ourSize > 0 ? nodes.get(ourSize - 1).getTime() : 0; float e0 = ourSize > 0 ? nodes.get(ourSize - 1).getEnergy() : 0; + int c0 = ourSize > 0 ? nodes.get(ourSize - 1).cost : 0; for (i = 0; i < t.nodes.size(); i++) { OsmPathElement e = t.nodes.get(i); if (i == 0 && ourSize > 0 && nodes.get(ourSize - 1).getSElev() == Short.MIN_VALUE) @@ -345,6 +347,7 @@ public final class OsmTrack { if (i > 0 || ourSize == 0) { e.setTime(e.getTime() + t0); e.setEnergy(e.getEnergy() + e0); + e.cost = e.cost + c0; if (e.message != null){ if (!(e.message.lon == e.getILon() && e.message.lat == e.getILat())) { e.message.lon = e.getILon(); diff --git a/brouter-core/src/main/java/btools/router/RoutingContext.java b/brouter-core/src/main/java/btools/router/RoutingContext.java index f5b2bf3..792014c 100644 --- a/brouter-core/src/main/java/btools/router/RoutingContext.java +++ b/brouter-core/src/main/java/btools/router/RoutingContext.java @@ -77,6 +77,7 @@ public final class RoutingContext { public double waypointCatchingRange; public boolean correctMisplacedViaPoints; public double correctMisplacedViaPointsDistance; + public boolean continueStraight; public boolean useDynamicDistance; public boolean buildBeelineOnRange; @@ -126,6 +127,8 @@ public final class RoutingContext { correctMisplacedViaPoints = 0.f != expctxGlobal.getVariableValue("correctMisplacedViaPoints", 1.f); correctMisplacedViaPointsDistance = expctxGlobal.getVariableValue("correctMisplacedViaPointsDistance", 0.f); // 0 == don't use distance + continueStraight = 0.f != expctxGlobal.getVariableValue("continueStraight", 0.f); + // process tags not used in the profile (to have them in the data-tab) processUnusedTags = 0.f != expctxGlobal.getVariableValue("processUnusedTags", 0.f); @@ -221,6 +224,7 @@ public final class RoutingContext { public String outputFormat = "gpx"; public boolean exportWaypoints = false; + public boolean exportCorrectedWaypoints = false; public OsmPrePath firstPrePath; diff --git a/brouter-core/src/main/java/btools/router/RoutingEngine.java b/brouter-core/src/main/java/btools/router/RoutingEngine.java index 698bc7b..42ae5a1 100644 --- a/brouter-core/src/main/java/btools/router/RoutingEngine.java +++ b/brouter-core/src/main/java/btools/router/RoutingEngine.java @@ -23,6 +23,7 @@ import btools.mapaccess.OsmLinkHolder; import btools.mapaccess.OsmNode; import btools.mapaccess.OsmNodePairSet; import btools.mapaccess.OsmPos; +import btools.util.CheapAngleMeter; import btools.util.CheapRuler; import btools.util.CompactLongMap; import btools.util.SortedHeap; @@ -262,6 +263,7 @@ public class RoutingEngine extends Thread { } oldTrack = null; track.exportWaypoints = routingContext.exportWaypoints; + track.exportCorrectedWaypoints = routingContext.exportCorrectedWaypoints; filename = outfileBase + i + "." + routingContext.outputFormat; switch (routingContext.outputFormat) { case "gpx": @@ -975,6 +977,10 @@ public class RoutingEngine extends Thread { hasDirectRouting = true; } } + for (MatchedWaypoint mwp : matchedWaypoints) { + //System.out.println(FormatGpx.getWaypoint(mwp.waypoint.ilon, mwp.waypoint.ilat, mwp.name, null)); + //System.out.println(FormatGpx.getWaypoint(mwp.crosspoint.ilon, mwp.crosspoint.ilat, mwp.name+"_cp", null)); + } routingContext.hasDirectRouting = hasDirectRouting; @@ -995,7 +1001,7 @@ public class RoutingEngine extends Thread { } else { seg = searchTrack(matchedWaypoints.get(i), matchedWaypoints.get(i + 1), i == matchedWaypoints.size() - 2 ? nearbyTrack : null, refTracks[i]); wptIndex = i; - if (engineMode == BROUTER_ENGINEMODE_ROUNDTRIP) { + if (routingContext.continueStraight) { if (i < matchedWaypoints.size() - 2) { OsmNode lastPoint = seg.containsNode(matchedWaypoints.get(i+1).node1) ? matchedWaypoints.get(i+1).node1 : matchedWaypoints.get(i+1).node2; OsmNodeNamed nogo = new OsmNodeNamed(lastPoint); @@ -1015,7 +1021,7 @@ public class RoutingEngine extends Thread { boolean changed = false; if (routingContext.correctMisplacedViaPoints && !matchedWaypoints.get(i).direct && !routingContext.allowSamewayback) { - changed = snappPathConnection(totaltrack, seg, routingContext.inverseRouting ? matchedWaypoints.get(i + 1) : matchedWaypoints.get(i)); + changed = snapPathConnection(totaltrack, seg, routingContext.inverseRouting ? matchedWaypoints.get(i + 1) : matchedWaypoints.get(i)); } if (wptIndex > 0) matchedWaypoints.get(wptIndex).indexInTrack = totaltrack.nodes.size() - 1; @@ -1038,12 +1044,198 @@ public class RoutingEngine extends Thread { if (routingContext.poipoints != null) totaltrack.pois = routingContext.poipoints; - totaltrack.matchedWaypoints = matchedWaypoints; + return totaltrack; } + OsmTrack getExtraSegment(OsmPathElement start, OsmPathElement end) { + + List wptlist = new ArrayList<>(); + MatchedWaypoint wpt1 = new MatchedWaypoint(); + wpt1.waypoint = new OsmNode(start.getILon(), start.getILat()); + wpt1.name = "wptx1"; + wpt1.crosspoint = new OsmNode(start.getILon(), start.getILat()); + wpt1.node1 = new OsmNode(start.getILon(), start.getILat()); + wpt1.node2 = new OsmNode(end.getILon(), end.getILat()); + wptlist.add(wpt1); + MatchedWaypoint wpt2 = new MatchedWaypoint(); + wpt2.waypoint = new OsmNode(end.getILon(), end.getILat()); + wpt2.name = "wptx2"; + wpt2.crosspoint = new OsmNode(end.getILon(), end.getILat()); + wpt2.node2 = new OsmNode(start.getILon(), start.getILat()); + wpt2.node1 = new OsmNode(end.getILon(), end.getILat()); + wptlist.add(wpt2); + + MatchedWaypoint mwp1 = wptlist.get(0); + MatchedWaypoint mwp2 = wptlist.get(1); + + OsmTrack mid = null; + + boolean corr = routingContext.correctMisplacedViaPoints; + routingContext.correctMisplacedViaPoints = false; + + guideTrack = new OsmTrack(); + guideTrack.addNode(start); + guideTrack.addNode(end); + + mid = findTrack("getinfo", mwp1, mwp2, null, null, false); + + guideTrack = null; + routingContext.correctMisplacedViaPoints = corr; + + return mid; + } + + private int snapRoundaboutConnection(OsmTrack tt, OsmTrack t, int indexStart, int indexEnd, int indexMeeting, MatchedWaypoint startWp) { + + int indexMeetingBack = (indexMeeting == -1 ? tt.nodes.size() - 1 : indexMeeting); + int indexMeetingFore = 0; + int indexStartBack = indexStart; + int indexStartFore = 0; + + OsmPathElement ptStart = tt.nodes.get(indexStartBack); + OsmPathElement ptMeeting = tt.nodes.get(indexMeetingBack); + OsmPathElement ptEnd = t.nodes.get(indexEnd); + + boolean bMeetingIsOnRoundabout = ptMeeting.message.isRoundabout(); + boolean bMeetsRoundaboutStart = false; + + int i; + for (i = 0; i < indexEnd; i++) { + OsmPathElement n = t.nodes.get(i); + if (n.positionEquals(ptStart)) { + indexStartFore = i; + bMeetsRoundaboutStart = true; + } + if (n.positionEquals(ptMeeting)) { + indexMeetingFore = i; + } + + } + + if (!bMeetsRoundaboutStart && bMeetingIsOnRoundabout) { + indexEnd = indexMeetingFore; + } + if (bMeetsRoundaboutStart && bMeetingIsOnRoundabout) { + indexEnd = indexStartFore; + } + + List removeList = new ArrayList<>(); + if (!bMeetsRoundaboutStart) { + indexStartBack = indexMeetingBack; + while (!tt.nodes.get(indexStartBack).message.isRoundabout()) { + indexStartBack--; + if (indexStartBack == 2) break; + } + } + + for (i = indexStartBack + 1; i < tt.nodes.size(); i++) { + OsmPathElement n = tt.nodes.get(i); + OsmTrack.OsmPathElementHolder detours = tt.getFromDetourMap(n.getIdFromPos()); + OsmTrack.OsmPathElementHolder h = detours; + while (h != null) { + h = h.nextHolder; + } + removeList.add(n); + } + + OsmPathElement ttend = null; + OsmPathElement ttend_next = null; + if (!bMeetingIsOnRoundabout && !bMeetsRoundaboutStart) { + ttend = tt.nodes.get(indexStartBack); + ttend_next = tt.nodes.get(indexStartBack + 1); + OsmTrack.OsmPathElementHolder ttend_detours = tt.getFromDetourMap(ttend.getIdFromPos()); + + tt.registerDetourForId(ttend.getIdFromPos(), null); + } + + for (OsmPathElement e : removeList) { + tt.nodes.remove(e); + } + removeList.clear(); + + + for (i = 0; i < indexEnd; i++) { + OsmPathElement n = t.nodes.get(i); + if (n.positionEquals(bMeetsRoundaboutStart ? ptStart : ptEnd)) break; + if (!bMeetingIsOnRoundabout && !bMeetsRoundaboutStart && n.message.isRoundabout()) break; + + OsmTrack.OsmPathElementHolder detours = t.getFromDetourMap(n.getIdFromPos()); + OsmTrack.OsmPathElementHolder h = detours; + while (h != null) { + h = h.nextHolder; + } + removeList.add(n); + } + + // time hold + float atime = 0; + float aenergy = 0; + int acost = 0; + if (i > 1) { + atime = t.nodes.get(i).getTime(); + aenergy = t.nodes.get(i).getEnergy(); + acost = t.nodes.get(i).cost; + } + + for (OsmPathElement e : removeList) { + t.nodes.remove(e); + } + removeList.clear(); + + if (atime > 0f) { + for (OsmPathElement e : t.nodes) { + e.setTime(e.getTime() - atime); + e.setEnergy(e.getEnergy() - aenergy); + e.cost = e.cost - acost; + } + } + + if (!bMeetingIsOnRoundabout && !bMeetsRoundaboutStart) { + + OsmPathElement tstart = t.nodes.get(0); + OsmPathElement tstart_next = null; + OsmTrack.OsmPathElementHolder tstart_detours = t.getFromDetourMap(tstart.getIdFromPos()); + OsmTrack.OsmPathElementHolder ttend_detours = tt.getFromDetourMap(ttend.getIdFromPos()); + + OsmTrack mid = getExtraSegment(ttend, ttend_detours.node); + OsmPathElement tt_end = tt.nodes.get(tt.nodes.size() - 1); + + int last_cost = tt_end.cost; + int tmp_cost = 0; + + if (mid != null) { + boolean start = false; + for (OsmPathElement e : mid.nodes) { + if (start) { + if (e.positionEquals(ttend_detours.node)) { + tmp_cost = e.cost; + break; + } + e.cost = last_cost + e.cost; + tt.nodes.add(e); + } + if (e.positionEquals(tt_end)) start = true; + } + + } + + ttend_detours.node.cost = last_cost + tmp_cost; + tt.nodes.add(ttend_detours.node); + t.nodes.add(0, ttend_detours.node); + + } + + tt.cost = tt.nodes.get(tt.nodes.size()-1).cost; + t.cost = t.nodes.get(t.nodes.size()-1).cost; + + startWp.correctedpoint = new OsmNode(ptStart.getILon(), ptStart.getILat()); + + return (t.nodes.size()); + } + // check for way back on way point - private boolean snappPathConnection(OsmTrack tt, OsmTrack t, MatchedWaypoint startWp) { + private boolean snapPathConnection(OsmTrack tt, OsmTrack t, MatchedWaypoint startWp) { if (!startWp.name.startsWith("via") && !startWp.name.startsWith("rt")) return false; @@ -1075,29 +1267,88 @@ public class RoutingEngine extends Thread { OsmPathElement newTarget = null; OsmPathElement tmpback = null; OsmPathElement tmpfore = null; + OsmPathElement tmpStart = null; int indexback = ourSize - 1; int indexfore = 0; int stop = (indexback - MAX_STEPS_CHECK > 1 ? indexback - MAX_STEPS_CHECK : 1); double wayDistance = 0; double nextDist = 0; + boolean bCheckRoundAbout = false; + boolean bBackRoundAbout = false; + boolean bForeRoundAbout = false; + int indexBackFound = 0; + int indexForeFound = 0; + int differentLanePoints = 0; + int indexMeeting = -1; + while (indexback >= 1 && indexback >= stop && indexfore < t.nodes.size()) { + tmpback = tt.nodes.get(indexback); + tmpfore = t.nodes.get(indexfore); + if (!bBackRoundAbout && tmpback.message != null && tmpback.message.isRoundabout()) { + bBackRoundAbout = true; + indexBackFound = indexfore; + } + if (!bForeRoundAbout && + tmpfore.message != null && tmpfore.message.isRoundabout() || + (tmpback.positionEquals(tmpfore) && tmpback.message.isRoundabout())) { + bForeRoundAbout = true; + indexForeFound = indexfore; + } + if (indexfore == 0) { + tmpStart = t.nodes.get(0); + } else { + double dirback = CheapAngleMeter.getDirection(tmpStart.getILon(), tmpStart.getILat(), tmpback.getILon(), tmpback.getILat()); + double dirfore = CheapAngleMeter.getDirection(tmpStart.getILon(), tmpStart.getILat(), tmpfore.getILon(), tmpfore.getILat()); + double dirdiff = CheapAngleMeter.getDifferenceFromDirection(dirback, dirfore); + // walking wrong direction + if (dirdiff > 60 && !bBackRoundAbout && !bForeRoundAbout) break; + } + // seems no roundabout, only on one end + if (bBackRoundAbout != bForeRoundAbout && indexfore - Math.abs(indexForeFound - indexBackFound) > 8) break; + if (!tmpback.positionEquals(tmpfore)) differentLanePoints++; + if (tmpback.positionEquals(tmpfore)) indexMeeting = indexback; + bCheckRoundAbout = bBackRoundAbout && bForeRoundAbout; + if (bCheckRoundAbout) break; + indexback--; + indexfore++; + } + //System.out.println("snap round result " + indexback + ": " + bBackRoundAbout + " - " + indexfore + "; " + bForeRoundAbout + " pts " + differentLanePoints); + if (bCheckRoundAbout) { + + tmpback = tt.nodes.get(--indexback); + while (tmpback.message != null && tmpback.message.isRoundabout()) { + tmpback = tt.nodes.get(--indexback); + } + + int ifore = ++indexfore; + OsmPathElement testfore = t.nodes.get(ifore); + while (ifore < t.nodes.size() && testfore.message != null && testfore.message.isRoundabout()) { + testfore = t.nodes.get(ifore); + ifore++; + } + + snapRoundaboutConnection(tt, t, indexback, --ifore, indexMeeting, startWp); + + // remove filled arrays + removeVoiceHintList.clear(); + removeBackList.clear(); + removeForeList.clear(); + return true; + } + indexback = ourSize - 1; + indexfore = 0; while (indexback >= 1 && indexback >= stop && indexfore < t.nodes.size()) { int junctions = 0; tmpback = tt.nodes.get(indexback); tmpfore = t.nodes.get(indexfore); if (tmpback.message != null && tmpback.message.isRoundabout()) { - removeBackList.clear(); - removeForeList.clear(); - removeVoiceHintList.clear(); - return false; + bCheckRoundAbout = true; } if (tmpfore.message != null && tmpfore.message.isRoundabout()) { - removeBackList.clear(); - removeForeList.clear(); - removeVoiceHintList.clear(); - return false; + bCheckRoundAbout = true; } - int dist = tmpback.calcDistance(tmpfore); - if (1 == 1) { + { + + int dist = tmpback.calcDistance(tmpfore); OsmTrack.OsmPathElementHolder detours = tt.getFromDetourMap(tmpback.getIdFromPos()); OsmTrack.OsmPathElementHolder h = detours; while (h != null) { @@ -1105,48 +1356,56 @@ public class RoutingEngine extends Thread { lastJunctions.put(h.node.getIdFromPos(), h); h = h.nextHolder; } - } - if (dist == 1 && indexfore > 0) { - if (indexfore == 1) { - removeBackList.add(tt.nodes.get(tt.nodes.size() - 1)); // last and first should be equal, so drop only on second also equal - removeForeList.add(t.nodes.get(0)); - removeBackList.add(tmpback); - removeForeList.add(tmpfore); - removeVoiceHintList.add(tt.nodes.size() - 1); - removeVoiceHintList.add(indexback); - } else { - removeBackList.add(tmpback); - removeForeList.add(tmpfore); - removeVoiceHintList.add(indexback); - } - nextDist = t.nodes.get(indexfore - 1).calcDistance(tmpfore); - wayDistance += nextDist; - } - if (dist > 1 || indexback == 1) { - if (removeBackList.size() != 0) { - // recover last - should be the cross point - removeBackList.remove(removeBackList.get(removeBackList.size() - 1)); - removeForeList.remove(removeForeList.get(removeForeList.size() - 1)); - break; - } else { + if (dist == 1 && indexfore > 0) { + if (indexfore == 1) { + removeBackList.add(tt.nodes.get(tt.nodes.size() - 1)); // last and first should be equal, so drop only on second also equal + removeForeList.add(t.nodes.get(0)); + removeBackList.add(tmpback); + removeForeList.add(tmpfore); + removeVoiceHintList.add(tt.nodes.size() - 1); + removeVoiceHintList.add(indexback); + } else { + removeBackList.add(tmpback); + removeForeList.add(tmpfore); + removeVoiceHintList.add(indexback); + } + nextDist = t.nodes.get(indexfore - 1).calcDistance(tmpfore); + wayDistance += nextDist; + + } + if (dist > 1 || indexback == 1) { + if (removeBackList.size() != 0) { + // recover last - should be the cross point + removeBackList.remove(removeBackList.get(removeBackList.size() - 1)); + removeForeList.remove(removeForeList.get(removeForeList.size() - 1)); + break; + } else { + return false; + } + } + indexback--; + indexfore++; + + if (routingContext.correctMisplacedViaPointsDistance > 0 && + wayDistance > routingContext.correctMisplacedViaPointsDistance) { + removeVoiceHintList.clear(); + removeBackList.clear(); + removeForeList.clear(); return false; } } - indexback--; - indexfore++; - - if (routingContext.correctMisplacedViaPointsDistance > 0 && - wayDistance > routingContext.correctMisplacedViaPointsDistance) break; } // time hold float atime = 0; float aenergy = 0; + int acost = 0; if (removeForeList.size() > 1) { - atime = t.nodes.get(removeForeList.size() - 2).getTime(); - aenergy = t.nodes.get(removeForeList.size() - 2).getEnergy(); + atime = t.nodes.get(indexfore -1).getTime(); + aenergy = t.nodes.get(indexfore -1).getEnergy(); + acost = t.nodes.get(indexfore -1).cost; } for (OsmPathElement e : removeBackList) { @@ -1166,6 +1425,7 @@ public class RoutingEngine extends Thread { for (OsmPathElement e : t.nodes) { e.setTime(e.getTime() - atime); e.setEnergy(e.getEnergy() - aenergy); + e.cost = e.cost - acost; } } @@ -1181,35 +1441,17 @@ public class RoutingEngine extends Thread { newJunction = t.nodes.get(0); newTarget = t.nodes.get(1); - setNewVoiceHint(t, last, lastJunctions, newJunction, newTarget); + tt.cost = tt.nodes.get(tt.nodes.size()-1).cost; + t.cost = t.nodes.get(t.nodes.size()-1).cost; + + // fill to correctedpoint + startWp.correctedpoint = new OsmNode(newJunction.getILon(), newJunction.getILat()); return true; } return false; } - private void setNewVoiceHint(OsmTrack t, OsmPathElement last, CompactLongMap lastJunctiona, OsmPathElement newJunction, OsmPathElement newTarget) { - - if (last == null || newJunction == null || newTarget == null) - return; - int lon0, - lat0, - lon1, - lat1, - lon2, - lat2; - lon0 = last.getILon(); - lat0 = last.getILat(); - lon1 = newJunction.getILon(); - lat1 = newJunction.getILat(); - lon2 = newTarget.getILon(); - lat2 = newTarget.getILat(); - // get a new angle - double angle = routingContext.anglemeter.calcAngle(lon0, lat0, lon1, lat1, lon2, lat2); - - newTarget.message.turnangle = (float) angle; - } - private void recalcTrack(OsmTrack t) { int totaldist = 0; int totaltime = 0; @@ -1553,7 +1795,7 @@ public class RoutingEngine extends Thread { OsmPath p = getStartPath(n1, n2, new OsmNodeNamed(mwp.crosspoint), endPos, sameSegmentSearch); // special case: start+end on same segment - if (p.cost >= 0 && sameSegmentSearch && endPos != null && endPos.radius < 1.5) { + if (p != null && p.cost >= 0 && sameSegmentSearch && endPos != null && endPos.radius < 1.5) { p.treedepth = 0; // hack: mark for the final-check } return p; @@ -1592,7 +1834,7 @@ public class RoutingEngine extends Thread { if (bestLink != null) { bestLink.addLinkHolder(bestPath, n1); } - bestPath.treedepth = 1; + if (bestPath != null) bestPath.treedepth = 1; return bestPath; } finally { @@ -1690,6 +1932,9 @@ public class RoutingEngine extends Thread { logInfo("firstMatchCost from initial match=" + firstMatchCost); } + if (startPath1 == null) return null; + if (startPath2 == null) return null; + synchronized (openSet) { openSet.clear(); addToOpenset(startPath1); diff --git a/brouter-core/src/main/java/btools/router/RoutingParamCollector.java b/brouter-core/src/main/java/btools/router/RoutingParamCollector.java index f239315..1bcc6ee 100644 --- a/brouter-core/src/main/java/btools/router/RoutingParamCollector.java +++ b/brouter-core/src/main/java/btools/router/RoutingParamCollector.java @@ -227,6 +227,8 @@ public class RoutingParamCollector { } } else if (key.equals("exportWaypoints")) { rctx.exportWaypoints = (Integer.parseInt(value) == 1); + } else if (key.equals("exportCorrectedWaypoints")) { + rctx.exportCorrectedWaypoints = (Integer.parseInt(value) == 1); } else if (key.equals("format")) { rctx.outputFormat = ((String) value).toLowerCase(); } else if (key.equals("trackFormat")) { diff --git a/brouter-core/src/main/java/btools/router/VoiceHint.java b/brouter-core/src/main/java/btools/router/VoiceHint.java index 691453c..09d38ca 100644 --- a/brouter-core/src/main/java/btools/router/VoiceHint.java +++ b/brouter-core/src/main/java/btools/router/VoiceHint.java @@ -580,7 +580,11 @@ public class VoiceHint { } else if (lowerBadWayAngle >= -100.f && higherBadWayAngle < 45.f) { cmd = KL; } else { - cmd = C; + if (lowerBadWayAngle > -35.f && higherBadWayAngle > 55.f) { + cmd = KR; + } else { + cmd = C; + } } } else if (cmdAngle < 5.f) { if (lowerBadWayAngle > -30.f) { @@ -597,7 +601,11 @@ public class VoiceHint { } else if (lowerBadWayAngle > -45.f && higherBadWayAngle <= 100.f) { cmd = KR; } else { - cmd = C; + if (lowerBadWayAngle < -55.f && higherBadWayAngle < 35.f) { + cmd = KL; + } else { + cmd = C; + } } } else if (cmdAngle < 45.f) { cmd = TSLR; diff --git a/brouter-core/src/main/java/btools/router/VoiceHintProcessor.java b/brouter-core/src/main/java/btools/router/VoiceHintProcessor.java index 5df8a67..83a2ad4 100644 --- a/brouter-core/src/main/java/btools/router/VoiceHintProcessor.java +++ b/brouter-core/src/main/java/btools/router/VoiceHintProcessor.java @@ -116,6 +116,7 @@ public final class VoiceHintProcessor { input.angle = roundAboutTurnAngle; input.goodWay.turnangle = roundAboutTurnAngle; input.distanceToNext = distance; + input.turnAngleConsumed = true; //input.roundaboutExit = startTurn < 0 ? roundaboutExit : -roundaboutExit; input.roundaboutExit = roundAboutTurnAngle < 0 ? roundaboutExit : -roundaboutExit; float tmpangle = 0; @@ -314,7 +315,13 @@ public final class VoiceHintProcessor { input.cmd == VoiceHint.KR || input.cmd == VoiceHint.KL) && !input.goodWay.isLinktType()) { - if (input.goodWay.getPrio() < input.maxBadPrio && (inputLastSaved != null && inputLastSaved.distanceToNext > catchingRange)) { + if ( + ((Math.abs(input.lowerBadWayAngle) < 35.f || + input.higherBadWayAngle < 35.f) + || input.goodWay.getPrio() < input.maxBadPrio) + && (inputLastSaved != null && inputLastSaved.distanceToNext > minRange) + && (input.distanceToNext > minRange) + ) { results.add(input); } else { if (inputLast != null) { // when drop add distance to last diff --git a/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java b/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java index 630af03..e94677e 100644 --- a/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java +++ b/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java @@ -782,7 +782,7 @@ public abstract class BExpressionContext implements IByteArrayUnifier { public void parseFile(File file, String readOnlyContext, Map keyValues) { if (!file.exists()) { - throw new IllegalArgumentException("profile " + file + " does not exist"); + throw new IllegalArgumentException("profile " + file.getName() + " does not exist"); } try { if (readOnlyContext != null) { @@ -813,12 +813,12 @@ public abstract class BExpressionContext implements IByteArrayUnifier { variableData[i] = readOnlyData[i]; } } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("ParseException " + file + " at line " + linenr + ": " + e.getMessage()); + throw new IllegalArgumentException("ParseException " + file.getName() + " at line " + linenr + ": " + e.getMessage()); } catch (Exception e) { throw new RuntimeException(e); } if (expressionList.size() == 0) { - throw new IllegalArgumentException(file.getAbsolutePath() + throw new IllegalArgumentException(file.getName() + " does not contain expressions for context " + context + " (old version?)"); } } diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/MatchedWaypoint.java b/brouter-mapaccess/src/main/java/btools/mapaccess/MatchedWaypoint.java index c9556d5..4c2a415 100644 --- a/brouter-mapaccess/src/main/java/btools/mapaccess/MatchedWaypoint.java +++ b/brouter-mapaccess/src/main/java/btools/mapaccess/MatchedWaypoint.java @@ -16,6 +16,7 @@ public final class MatchedWaypoint { public OsmNode node2; public OsmNode crosspoint; public OsmNode waypoint; + public OsmNode correctedpoint; public String name; // waypoint name used in error messages public double radius; // distance in meter between waypoint and crosspoint public boolean direct; // from this point go direct to next = beeline routing diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/WaypointMatcherImpl.java b/brouter-mapaccess/src/main/java/btools/mapaccess/WaypointMatcherImpl.java index 6096c79..b2769cd 100644 --- a/brouter-mapaccess/src/main/java/btools/mapaccess/WaypointMatcherImpl.java +++ b/brouter-mapaccess/src/main/java/btools/mapaccess/WaypointMatcherImpl.java @@ -116,7 +116,7 @@ public final class WaypointMatcherImpl implements WaypointMatcher { double r22 = x2 * x2 + y2 * y2; double radius = Math.abs(r12 < r22 ? y1 * dx - x1 * dy : y2 * dx - x2 * dy) / d; - if (radius < mwp.radius) { + if (radius <= mwp.radius) { double s1 = x1 * dx + y1 * dy; double s2 = x2 * dx + y2 * dy; diff --git a/brouter-routing-app/build.gradle b/brouter-routing-app/build.gradle index d6a9bfc..beec651 100644 --- a/brouter-routing-app/build.gradle +++ b/brouter-routing-app/build.gradle @@ -8,7 +8,7 @@ plugins { } android { - compileSdk 35 + compileSdk 36 base { archivesName = "BRouterApp." + project.version @@ -18,13 +18,13 @@ android { namespace 'btools.routingapp' applicationId "btools.routingapp" - versionCode 54 + versionCode 55 versionName project.version resValue('string', 'app_version', defaultConfig.versionName) minSdkVersion 21 - targetSdkVersion 34 + targetSdkVersion 36 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -100,9 +100,9 @@ repositories { } dependencies { - implementation 'androidx.appcompat:appcompat:1.7.0' - implementation "androidx.constraintlayout:constraintlayout:2.1.4" - implementation 'androidx.work:work-runtime:2.9.0' + implementation 'androidx.appcompat:appcompat:1.7.1' + implementation "androidx.constraintlayout:constraintlayout:2.2.1" + implementation 'androidx.work:work-runtime:2.10.2' implementation 'com.google.android.material:material:1.12.0' implementation project(':brouter-mapaccess') @@ -115,7 +115,7 @@ dependencies { androidTestImplementation 'androidx.test.ext:junit:1.2.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' - androidTestImplementation 'androidx.work:work-testing:2.9.0' + androidTestImplementation 'androidx.work:work-testing:2.10.2' } gradle.projectsEvaluated { 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 485d03f..dc1c0a1 100644 --- a/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java +++ b/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java @@ -30,6 +30,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.zip.ZipEntry; @@ -44,6 +45,8 @@ import btools.router.OsmTrack; import btools.router.RoutingContext; import btools.router.RoutingEngine; import btools.router.RoutingHelper; +import btools.router.RoutingParamCollector; + import btools.util.CheapRuler; public class BRouterView extends View { @@ -437,6 +440,7 @@ public class BRouterView extends View { public void startProcessing(String profile) { rawTrackPath = null; + String params = null; if (profile.startsWith(" 2) { + try { + Map profileParamsCollection = null; + RoutingParamCollector routingParamCollector = new RoutingParamCollector(); + profileParamsCollection = routingParamCollector.getUrlParams(params); + routingParamCollector.setProfileParams(rc, profileParamsCollection); + } catch (Exception e) {} + } + int plain_distance = 0; int maxlon = Integer.MIN_VALUE; int minlon = Integer.MAX_VALUE; 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 33ee802..093b9f6 100644 --- a/brouter-routing-app/src/main/java/btools/routingapp/BRouterWorker.java +++ b/brouter-routing-app/src/main/java/btools/routingapp/BRouterWorker.java @@ -100,11 +100,19 @@ public class BRouterWorker { } routingParamCollector.setParams(rc, waypoints, theParams); + Map profileParamsCollection = null; + try { + if (profileParams != null) { + profileParamsCollection = routingParamCollector.getUrlParams(profileParams); + routingParamCollector.setProfileParams(rc, profileParamsCollection); + } + } catch (UnsupportedEncodingException e) { + // ignore + } if (params.containsKey("extraParams")) { - Map profileparams = null; try { - profileparams = routingParamCollector.getUrlParams(params.getString("extraParams")); - routingParamCollector.setProfileParams(rc, profileparams); + profileParamsCollection = routingParamCollector.getUrlParams(params.getString("extraParams")); + routingParamCollector.setProfileParams(rc, profileParamsCollection); } catch (UnsupportedEncodingException e) { // ignore } @@ -161,6 +169,7 @@ public class BRouterWorker { track = cr.getFoundTrack(); if (track != null) { track.exportWaypoints = rc.exportWaypoints; + track.exportCorrectedWaypoints = rc.exportCorrectedWaypoints; if (pathToFileResult == null) { switch (writeFromat) { case OUTPUT_FORMAT_KML: @@ -212,6 +221,14 @@ public class BRouterWorker { bw.write("\n"); writeWPList(bw, waypoints); writeWPList(bw, rc.nogopoints); + if (rc.keyValues != null) { + StringBuilder sb = new StringBuilder(); + for (Map.Entry e : rc.keyValues.entrySet()) { + sb.append(sb.length()>0 ? "&" : "").append(e.getKey()).append("=").append(e.getValue()); + } + bw.write(sb.toString()); + bw.write("\n"); + } bw.close(); } diff --git a/brouter-routing-app/src/main/java/btools/routingapp/RoutingParameterDialog.java b/brouter-routing-app/src/main/java/btools/routingapp/RoutingParameterDialog.java index d69a037..3557b55 100644 --- a/brouter-routing-app/src/main/java/btools/routingapp/RoutingParameterDialog.java +++ b/brouter-routing-app/src/main/java/btools/routingapp/RoutingParameterDialog.java @@ -377,8 +377,8 @@ public class RoutingParameterDialog extends AppCompatActivity { for (String tmp : sa) { // Add the name and address to the ListPreference enties and entyValues //L.v("AFTrack", "device: "+device.getName() + " -- " + device.getAddress()); - entryValues[i] = "" + i; entries[i] = tmp.trim(); + entryValues[i] = entries[i].split("=")[0].trim(); if (entryValues[i].equals(s)) ii = i; i++; } @@ -394,11 +394,14 @@ public class RoutingParameterDialog extends AppCompatActivity { listPref.setSummary(p.description); listPref.setOnPreferenceChangeListener((Preference preference, Object newValue) -> { p.value = (String) newValue; - int iii = Integer.decode(p.value); - listPref.setTitle(p.name + ": " + entries[iii]); - + for (int iii = 0; iii < entryValues.length; iii++) { + String entryValue = entryValues[iii]; + if (entryValue.equals(p.value)) { + listPref.setTitle(p.name + ": " + entries[iii]); + break; + } + } return true; - }); gpsPrefCat.addPreference(listPref); diff --git a/brouter-server/src/main/java/btools/server/RouteServer.java b/brouter-server/src/main/java/btools/server/RouteServer.java index 4b2be7a..2def82b 100644 --- a/brouter-server/src/main/java/btools/server/RouteServer.java +++ b/brouter-server/src/main/java/btools/server/RouteServer.java @@ -160,8 +160,8 @@ public class RouteServer extends Thread implements Comparable { } else if (url.startsWith(PROFILE_UPLOAD_URL)) { if (getline.startsWith("OPTIONS")) { // handle CORS preflight request (Safari) - String corsHeaders = "Access-Control-Allow-Methods: GET, POST\n" - + "Access-Control-Allow-Headers: Content-Type\n"; + String corsHeaders = "Access-Control-Allow-Methods: GET, POST\r\n" + + "Access-Control-Allow-Headers: Content-Type\r\n"; writeHttpHeader(bw, "text/plain", null, corsHeaders, HTTP_STATUS_OK); bw.flush(); return; @@ -220,7 +220,7 @@ public class RouteServer extends Thread implements Comparable { // no zip for this engineMode encodings = null; } - String headers = encodings == null || encodings.indexOf("gzip") < 0 ? null : "Content-Encoding: gzip\n"; + String headers = encodings == null || encodings.indexOf("gzip") < 0 ? null : "Content-Encoding: gzip\r\n"; writeHttpHeader(bw, handler.getMimeType(), handler.getFileName(), headers, HTTP_STATUS_OK); if (engineMode == RoutingEngine.BROUTER_ENGINEMODE_ROUTING || engineMode == RoutingEngine.BROUTER_ENGINEMODE_ROUNDTRIP) { @@ -407,17 +407,17 @@ public class RouteServer extends Thread implements Comparable { private static void writeHttpHeader(BufferedWriter bw, String mimeType, String fileName, String headers, String status) throws IOException { // http-header - bw.write(String.format("HTTP/1.1 %s\n", status)); - bw.write("Connection: close\n"); - bw.write("Content-Type: " + mimeType + "; charset=utf-8\n"); + bw.write(String.format("HTTP/1.1 %s\r\n", status)); + bw.write("Connection: close\r\n"); + bw.write("Content-Type: " + mimeType + "; charset=utf-8\r\n"); if (fileName != null) { - bw.write("Content-Disposition: attachment; filename=\"" + fileName + "\"\n"); + bw.write("Content-Disposition: attachment; filename=\"" + fileName + "\"\r\n"); } - bw.write("Access-Control-Allow-Origin: *\n"); + bw.write("Access-Control-Allow-Origin: *\r\n"); if (headers != null) { bw.write(headers); } - bw.write("\n"); + bw.write("\r\n"); } private static void cleanupThreadQueue(Queue threadQueue) { 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 37ba145..fcb536c 100644 --- a/brouter-server/src/main/java/btools/server/request/ServerHandler.java +++ b/brouter-server/src/main/java/btools/server/request/ServerHandler.java @@ -78,6 +78,10 @@ public class ServerHandler extends RequestHandler { if (exportWaypointsStr != null && Integer.parseInt(exportWaypointsStr) != 0) { track.exportWaypoints = true; } + exportWaypointsStr = params.get("exportCorrectedWaypoints"); + if (exportWaypointsStr != null && Integer.parseInt(exportWaypointsStr) != 0) { + track.exportCorrectedWaypoints = true; + } if (format == null || "gpx".equals(format)) { result = new FormatGpx(rc).format(track); diff --git a/brouter-server/src/test/java/btools/server/RouteServerTest.java b/brouter-server/src/test/java/btools/server/RouteServerTest.java index d4c971e..ad6776c 100644 --- a/brouter-server/src/test/java/btools/server/RouteServerTest.java +++ b/brouter-server/src/test/java/btools/server/RouteServerTest.java @@ -14,6 +14,8 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.ConnectException; import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -28,7 +30,7 @@ public class RouteServerTest { public static TemporaryFolder profileDir = new TemporaryFolder(); @BeforeClass - public static void setupServer() throws IOException, InterruptedException { + public static void setupServer() throws IOException, InterruptedException, URISyntaxException { File workingDir = new File(".").getCanonicalFile(); File segmentDir = new File(workingDir, "../brouter-map-creator/build/resources/test/tmp/segments"); File profileSourceDir = new File(workingDir, "../misc/profiles2"); @@ -41,7 +43,7 @@ public class RouteServerTest { try { RouteServer.main(new String[]{segmentDir.getAbsolutePath(), profileDir.getRoot().getAbsolutePath(), customProfileDir, port, "1"}); } catch (Exception e) { - e.printStackTrace(); + e.printStackTrace(System.out); } }; @@ -49,7 +51,7 @@ public class RouteServerTest { thread.start(); // Busy-wait for server startup - URL requestUrl = new URL(baseUrl); + URL requestUrl = new URI(baseUrl).toURL(); HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); for (int i = 20; i >= 0; i--) { try { @@ -66,8 +68,8 @@ public class RouteServerTest { } @Test - public void defaultRouteTrekking() throws IOException { - URL requestUrl = new URL(baseUrl + "brouter?lonlats=8.723037,50.000491|8.712737,50.002899&nogos=&profile=trekking&alternativeidx=0&format=geojson"); + public void defaultRouteTrekking() throws IOException, URISyntaxException { + URL requestUrl = new URI(baseUrl + "brouter?lonlats=8.723037,50.000491%7C8.712737,50.002899&nogos=&profile=trekking&alternativeidx=0&format=geojson").toURL(); HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); httpConnection.connect(); @@ -82,8 +84,8 @@ public class RouteServerTest { } @Test - public void overrideParameter() throws IOException { - URL requestUrl = new URL(baseUrl + "brouter?lonlats=8.723037,50.000491|8.712737,50.002899&nogos=&profile=trekking&alternativeidx=0&format=geojson&profile:avoid_unsafe=1"); + public void overrideParameter() throws IOException, URISyntaxException { + URL requestUrl = new URI(baseUrl + "brouter?lonlats=8.723037,50.000491%7C8.712737,50.002899&nogos=&profile=trekking&alternativeidx=0&format=geojson&profile:avoid_unsafe=1").toURL(); HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); httpConnection.connect(); @@ -95,8 +97,8 @@ public class RouteServerTest { } @Test - public void voiceHints() throws IOException { - URL requestUrl = new URL(baseUrl + "brouter?lonlats=8.705796,50.003124|8.705859,50.0039599&nogos=&profile=trekking&alternativeidx=0&format=geojson&timode=2"); + public void voiceHints() throws IOException, URISyntaxException { + URL requestUrl = new URI(baseUrl + "brouter?lonlats=8.705796,50.003124%7C8.705859,50.0039599&nogos=&profile=trekking&alternativeidx=0&format=geojson&timode=2").toURL(); HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); httpConnection.connect(); @@ -108,8 +110,8 @@ public class RouteServerTest { } @Test - public void directRoutingFirst() throws IOException { - URL requestUrl = new URL(baseUrl + "brouter?lonlats=8.718354,50.001514|8.718917,50.001361|8.716986,50.000105|8.718306,50.00145&nogos=&profile=trekking&alternativeidx=0&format=geojson&straight=0&timode=3"); + public void directRoutingFirst() throws IOException, URISyntaxException { + URL requestUrl = new URI(baseUrl + "brouter?lonlats=8.718354,50.001514%7C8.718917,50.001361%7C8.716986,50.000105%7C8.718306,50.00145&nogos=&profile=trekking&alternativeidx=0&format=geojson&straight=0&timode=3").toURL(); HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); httpConnection.connect(); @@ -121,8 +123,8 @@ public class RouteServerTest { } @Test - public void directRoutingLast() throws IOException { - URL requestUrl = new URL(baseUrl + "brouter?lonlats=8.718306,50.00145|8.717464,50.000405|8.718917,50.001361|8.718354,50.001514&nogos=&profile=trekking&alternativeidx=0&format=geojson&straight=2&timode=3"); + public void directRoutingLast() throws IOException, URISyntaxException { + URL requestUrl = new URI(baseUrl + "brouter?lonlats=8.718306,50.00145%7C8.717464,50.000405%7C8.718917,50.001361%7C8.718354,50.001514&nogos=&profile=trekking&alternativeidx=0&format=geojson&straight=2&timode=3").toURL(); HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); httpConnection.connect(); @@ -134,8 +136,8 @@ public class RouteServerTest { } @Test - public void directRoutingMiddle() throws IOException { - URL requestUrl = new URL(baseUrl + "brouter?lonlats=8.718539,50.006581|8.718198,50.006065,d|8.71785,50.006034|8.7169,50.004456&nogos=&profile=trekking&alternativeidx=0&format=geojson&timode=3"); + public void directRoutingMiddle() throws IOException, URISyntaxException { + URL requestUrl = new URI(baseUrl + "brouter?lonlats=8.718539,50.006581%7C8.718198,50.006065,d%7C8.71785,50.006034%7C8.7169,50.004456&nogos=&profile=trekking&alternativeidx=0&format=geojson&timode=3").toURL(); HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); httpConnection.connect(); @@ -147,8 +149,8 @@ public class RouteServerTest { } @Test - public void misplacedPoints() throws IOException { - URL requestUrl = new URL(baseUrl + "brouter?lonlats=8.708678,49.999188|8.71145,49.999761|8.715801,50.00065&nogos=&profile=trekking&alternativeidx=0&format=geojson&correctMisplacedViaPoints=1&timode=3"); + public void misplacedPoints() throws IOException, URISyntaxException { + URL requestUrl = new URI(baseUrl + "brouter?lonlats=8.708678,49.999188%7C8.71145,49.999761%7C8.715801,50.00065&nogos=&profile=trekking&alternativeidx=0&format=geojson&correctMisplacedViaPoints=1&timode=3").toURL(); HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); httpConnection.connect(); @@ -160,8 +162,21 @@ public class RouteServerTest { } @Test - public void uploadValidProfile() throws IOException { - URL requestUrl = new URL(baseUrl + "brouter/profile"); + public void misplacedPointsRoundabout() throws IOException, URISyntaxException { + URL requestUrl = new URI(baseUrl + "brouter?lonlats=8.699487,50.001257%7C8.701569,50.000092%7C8.704873,49.998898&nogos=&profile=trekking&alternativeidx=0&format=geojson&profile:correctMisplacedViaPoints=1&timode=3").toURL(); + HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); + httpConnection.connect(); + + Assert.assertEquals(HttpURLConnection.HTTP_OK, httpConnection.getResponseCode()); + + InputStream inputStream = httpConnection.getInputStream(); + JSONObject geoJson = new JSONObject(new String(inputStream.readAllBytes(), StandardCharsets.UTF_8)); + Assert.assertEquals("482", geoJson.query("/features/0/properties/track-length")); + } + + @Test + public void uploadValidProfile() throws IOException, URISyntaxException { + URL requestUrl = new URI(baseUrl + "brouter/profile").toURL(); HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); httpConnection.setRequestMethod("POST"); @@ -192,8 +207,8 @@ public class RouteServerTest { } @Test - public void uploadInvalidProfile() throws IOException { - URL requestUrl = new URL(baseUrl + "brouter/profile"); + public void uploadInvalidProfile() throws IOException, URISyntaxException { + URL requestUrl = new URI(baseUrl + "brouter/profile").toURL(); HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); httpConnection.setRequestMethod("POST"); @@ -214,8 +229,8 @@ public class RouteServerTest { } @Test - public void robots() throws IOException { - URL requestUrl = new URL(baseUrl + "robots.txt"); + public void robots() throws IOException, URISyntaxException { + URL requestUrl = new URI(baseUrl + "robots.txt").toURL(); HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); httpConnection.connect(); @@ -226,8 +241,8 @@ public class RouteServerTest { } @Test - public void invalidUrl() throws IOException { - URL requestUrl = new URL(baseUrl + "invalid"); + public void invalidUrl() throws IOException, URISyntaxException { + URL requestUrl = new URI(baseUrl + "invalid").toURL(); HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); httpConnection.connect(); diff --git a/brouter-util/src/main/java/btools/util/StackSampler.java b/brouter-util/src/main/java/btools/util/StackSampler.java index 753fec4..53c5db6 100644 --- a/brouter-util/src/main/java/btools/util/StackSampler.java +++ b/brouter-util/src/main/java/btools/util/StackSampler.java @@ -12,7 +12,7 @@ import java.util.Map; import java.util.Random; public class StackSampler extends Thread { - private DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS", new Locale("en", "US")); + private DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS", new Locale.Builder().setLanguage("en").setRegion("US").build()); private BufferedWriter bw; private Random rand = new Random(); diff --git a/build.gradle b/build.gradle index 946559c..6fd211e 100644 --- a/build.gradle +++ b/build.gradle @@ -6,13 +6,13 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:8.7.3' + classpath 'com.android.tools.build:gradle:8.10.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } -task clean(type: Delete) { - delete rootProject.buildDir +tasks.register('clean', Delete) { + delete rootProject.layout.buildDirectory } diff --git a/buildSrc/src/main/groovy/brouter.version-conventions.gradle b/buildSrc/src/main/groovy/brouter.version-conventions.gradle index b99c641..e0ce18b 100644 --- a/buildSrc/src/main/groovy/brouter.version-conventions.gradle +++ b/buildSrc/src/main/groovy/brouter.version-conventions.gradle @@ -4,4 +4,4 @@ // app: build.gradle (versionCode only) // OsmTrack (version and versionDate) // docs revisions.md (version and versionDate) -version '1.7.7' +version '1.7.8' diff --git a/docs/revisions.md b/docs/revisions.md index 895d4d5..c9a492b 100644 --- a/docs/revisions.md +++ b/docs/revisions.md @@ -2,7 +2,7 @@ (ZIP-Archives including APK, readme + profiles) -### next version +### [brouter-1.7.8.zip](../brouter_bin/brouter-1.7.8.zip) (current revision, 12.07.2025) Android @@ -10,6 +10,8 @@ Android - use parameter changed in the BRouter app - reuse parameter for repeat:profile function - use unordered values for profile listbox (e.g. fastbike profile) +- Android 16 + Library @@ -26,7 +28,7 @@ Library [Solved issues](https://github.com/abrensch/brouter/issues?q=is%3Aissue+milestone%3A%22Version+1.7.8%22+is%3Aclosed) -### [brouter-1.7.7.zip](../brouter_bin/brouter-1.7.7.zip) (current revision, 23.07.2024) +### [brouter-1.7.7.zip](../brouter_bin/brouter-1.7.7.zip) (23.07.2024) - new Android API 34 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e644113..9bbc975 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 09523c0..37f853b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a4..faf9300 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -203,7 +205,7 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. diff --git a/gradlew.bat b/gradlew.bat index 7101f8e..9b42019 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## diff --git a/misc/profiles2/.gitignore b/misc/profiles2/.gitignore index 8e365df..751a83b 100644 --- a/misc/profiles2/.gitignore +++ b/misc/profiles2/.gitignore @@ -2,7 +2,7 @@ /car-fast.brf /fastbike-asia-pacific.brf /fastbike-lowtraffic.brf -/safety.brf +#/safety.brf /trekking-ignore-cr.brf /trekking-noferries.brf /trekking-nosteps.brf diff --git a/misc/profiles2/fastbike.brf b/misc/profiles2/fastbike.brf index 97006bb..4507cc3 100644 --- a/misc/profiles2/fastbike.brf +++ b/misc/profiles2/fastbike.brf @@ -23,7 +23,7 @@ assign allow_steps = true # %allow_steps% | Set to false to disallow assign allow_ferries = true # %allow_ferries% | set to false to disallow ferries | boolean assign allow_motorways = false # %allow_motorways% | Set to true to allow motorways (useful in Asia / Oceania for example) | boolean -assign consider_traffic = false # %consider_traffic% | Activate to avoid traffic | boolean +assign consider_traffic = 1 # %consider_traffic% | how do you plan to drive the tour? | [1=as cyclist alone in the week, 0.5=as cyclist alone at weekend, 0.3 =with a group of cyclists, 0.1=with a group of cyclists at week-end, 0.0=do not consider traffic] assign consider_noise = false # %consider_noise% | Activate to prefer a low-noise route | boolean assign consider_river = false # %consider_river% | Activate to prefer a route along rivers, lakes, etc. | boolean assign consider_forest = false # %consider_forest% | Activate to prefer a route in forest or parks | boolean @@ -154,43 +154,14 @@ assign onewaypenalty = assign hascycleway = not and ( or cycleway= cycleway=no|none ) and ( or cycleway:left= cycleway:left=no ) ( or cycleway:right= cycleway:right=no ) -assign trafficpenalty0 = - if consider_traffic then - ( - if highway=primary|primary_link then - ( - if estimated_traffic_class=4 then 0.2 - else if estimated_traffic_class=5 then 0.4 - else if estimated_traffic_class=6|7 then 0.6 - else 0 - ) - else if highway=secondary|secondary_link then - ( - if estimated_traffic_class=3 then 0.2 - else if estimated_traffic_class=4 then 0.4 - else if estimated_traffic_class=5 then 0.6 - else if estimated_traffic_class=6|7 then 1 - else 0 - ) - else if highway=tertiary|tertiary_link then - ( - if estimated_traffic_class=2 then 0.1 - else if estimated_traffic_class=3 then 0.3 - else if estimated_traffic_class=4 then 0.5 - else if estimated_traffic_class=5|6|7 then 1 - else 0 - ) - else 0 - ) - else 0 assign trafficpenalty = - if consider_traffic then - ( - if hascycleway then min 0.3 trafficpenalty0 - else trafficpenalty0 - ) - else 0 + if estimated_traffic_class=|1|2 then 0 + else if estimated_traffic_class=3 then multiply 0.3 consider_traffic + else if estimated_traffic_class=4 then multiply 0.6 consider_traffic + else if estimated_traffic_class=5 then multiply 0.9 consider_traffic + else if estimated_traffic_class=6|7 then multiply 1.5 consider_traffic + else 0 assign isresidentialorliving = or highway=residential|living_street living_street=yes diff --git a/misc/profiles2/hiking-mountain.brf b/misc/profiles2/hiking-mountain.brf index 6d3d920..2b36b81 100644 --- a/misc/profiles2/hiking-mountain.brf +++ b/misc/profiles2/hiking-mountain.brf @@ -15,7 +15,6 @@ assign consider_noise = false # %consider_noise% | Activate to prefe assign consider_river = false # %consider_river% | Activate to prefer a route along rivers, lakes, etc. | boolean assign consider_forest = false # %consider_forest% | Activate to prefer a route in forest or green areas| boolean assign consider_town = false # %consider_town% | Activate to bypass cities / big towns as far as possible | boolean -assign consider_traffic = 1 # %consider_traffic% | how do you plan to drive the tour? | [1=as cyclist alone in the week, 0.5=as cyclist alone at weekend, 0.3 =with a group of cyclists, 0.1=with a group of cyclists at week-end] assign shortest_way 0 # 0 as default, duplicate shortest standard profile, SAC access limit ignored for now @@ -359,36 +358,7 @@ assign town_penalty switch estimated_town_class=5 1.4 switch estimated_town_class=6 1.6 99 0 -assign trafficpenalty = -# if any_cycleway then 0 -# else -if highway=primary|primary_link then - ( - if estimated_traffic_class=1|2 then 0 - else if estimated_traffic_class=3 then multiply 0.4 consider_traffic - else if estimated_traffic_class=4 then multiply 0.8 consider_traffic - else if estimated_traffic_class=5 then multiply 1 consider_traffic - else if estimated_traffic_class=6|7 then multiply 2 consider_traffic - else multiply 0.6 consider_traffic - ) - else if highway=secondary|secondary_link then - ( - if estimated_traffic_class=1|2 then multiply 0.1 consider_traffic - else if estimated_traffic_class=3 then multiply 0.3 consider_traffic - else if estimated_traffic_class=4 then multiply 0.7 consider_traffic - else if estimated_traffic_class=5 then multiply 1 consider_traffic - else if estimated_traffic_class=6|7 then multiply 1.5 consider_traffic - else multiply 0.2 consider_traffic - ) - else if highway=tertiary|tertiary_link then - ( - if estimated_traffic_class=1|2 then multiply 0.1 consider_traffic - else if estimated_traffic_class=3 then multiply 0.2 consider_traffic - else if estimated_traffic_class=4 then multiply 0.5 consider_traffic - else multiply if estimated_traffic_class=5|6|7 then multiply 1 consider_traffic - else 0.1 consider_traffic - ) - else 0 +assign trafficpenalty = 0 assign costfactor add town_penalty diff --git a/misc/profiles2/lookups.dat b/misc/profiles2/lookups.dat index e8dafc1..d51f455 100644 --- a/misc/profiles2/lookups.dat +++ b/misc/profiles2/lookups.dat @@ -711,6 +711,11 @@ estimated_town_class;0000000001 4 estimated_town_class;0000000001 5 estimated_town_class;0000000001 6 +lts_score;2000000001 1 +lts_score;2000000002 2 +lts_score;2000000003 3 +lts_score;2000000004 4 + ---context:node diff --git a/misc/profiles2/safety.brf b/misc/profiles2/safety.brf new file mode 100644 index 0000000..8a6345d --- /dev/null +++ b/misc/profiles2/safety.brf @@ -0,0 +1,403 @@ +# *** The trekking profile is for slow travel +# *** and avoiding car traffic, but still with +# *** a focus on approaching your destination +# *** efficiently. + +---context:global # following code refers to global config + +# Bike profile +assign validForBikes = true + +# Use the following switches to change behaviour +assign allow_steps = true # %allow_steps% | Set false to disallow steps | boolean +assign allow_ferries = true # %allow_ferries% | Set false to disallow ferries | boolean +assign ignore_cycleroutes = false # %ignore_cycleroutes% | Set true for better elevation results | boolean +assign stick_to_cycleroutes = false # %stick_to_cycleroutes% | Set true to just follow cycleroutes | boolean +assign avoid_unsafe = true # %avoid_unsafe% | Set true to avoid standard highways | boolean + +assign add_beeline = false # %add_beeline% | Enable beeline on distant start/end points | boolean + +assign consider_noise = false # %consider_noise% | Activate to prefer a low-noise route | boolean +assign consider_river = false # %consider_river% | Activate to prefer a route along rivers, lakes, etc. | boolean +assign consider_forest = false # %consider_forest% | Activate to prefer a route in forest or parks | boolean +assign consider_town = false # %consider_town% | Activate to bypass cities / big towns as far as possible | boolean +assign consider_traffic = false # %consider_traffic% | Activate to consider traffic estimates | boolean + + + +# Change elevation parameters +assign consider_elevation = true # %consider_elevation% | Set true to favor a route with few elevation meters | boolean + +assign downhillcost = 60 # %downhillcost% | Cost for going downhill | number +assign downhillcutoff = 1.5 # %downhillcutoff% | Gradients below this value in percents are not counted. | number +assign uphillcost = 0 # %uphillcost% | Cost for going uphill | number +assign uphillcutoff = 1.5 # %uphillcutoff% | Gradients below this value in percents are not counted. | number + +assign downhillcost = if consider_elevation then downhillcost else 0 +assign uphillcost = if consider_elevation then uphillcost else 0 + +# Kinematic model parameters (travel time computation) +assign totalMass = 90 # %totalMass% | Mass (in kg) of the bike + biker, for travel time computation | number +assign maxSpeed = 45 # %maxSpeed% | Absolute maximum speed (in km/h), for travel time computation | number +assign S_C_x = 0.225 # %S_C_x% | Drag coefficient times the reference area (in m^2), for travel time computation | number +assign C_r = 0.01 # %C_r% | Rolling resistance coefficient (dimensionless), for travel time computation | number +assign bikerPower = 100 # %bikerPower% | Average power (in W) provided by the biker, for travel time computation | number + +# Turn instructions settings +assign turnInstructionMode = 1 # %turnInstructionMode% | Mode for the generated turn instructions | [0=none, 1=auto-choose, 2=locus-style, 3=osmand-style, 4=comment-style, 5=gpsies-style, 6=orux-style, 7=locus-old-style] +assign turnInstructionCatchingRange = 40 # %turnInstructionCatchingRange% | Within this distance (in m) several turning instructions are combined into one and the turning angles are better approximated to the general direction | number +assign turnInstructionRoundabouts = true # %turnInstructionRoundabouts% | Set "false" to avoid generating special turning instructions for roundabouts | boolean +assign considerTurnRestrictions = true # %considerTurnRestrictions% | Set true to take turn restrictions into account | boolean + +assign processUnusedTags = true # %processUnusedTags% | Set true to output unused tags in data tab | boolean + +---context:way # following code refers to way-tags + +# classifier constants +assign classifier_none = 1 +assign classifier_ferry = 2 + +# +# pre-calculate some logical expressions +# + +assign any_cycleroute = + if route_bicycle_icn=yes then true + else if route_bicycle_ncn=yes then true + else if route_bicycle_rcn=yes then true + else if route_bicycle_lcn=yes then true + else false + +assign nodeaccessgranted = + if any_cycleroute then true + else lcn=yes + +assign is_ldcr = + if ignore_cycleroutes then false + else any_cycleroute + +assign isbike = or bicycle_road=yes or bicycle=yes or or bicycle=permissive bicycle=designated lcn=yes +assign ispaved = surface=paved|asphalt|concrete|paving_stones|sett +assign isunpaved = not or surface= or ispaved surface=fine_gravel|cobblestone +assign probablyGood = or ispaved and ( or isbike highway=footway ) not isunpaved + + +# +# this is the cost (in Meter) for a 90-degree turn +# The actual cost is calculated as turncost*cos(angle) +# (Suppressing turncost while following longdistance-cycleways +# makes them a little bit more magnetic) +# +assign turncost = if is_ldcr then 0 + else if junction=roundabout then 0 + else 90 + + +# +# for any change in initialclassifier, initialcost is added once +# +assign initialclassifier = + if route=ferry then classifier_ferry + else classifier_none + + +# +# calculate the initial cost +# this is added to the total cost each time the costfactor +# changed +# +assign initialcost = + if ( equal initialclassifier classifier_ferry ) then 10000 + else 0 + +# +# implicit access here just from the motorroad tag +# (implicit access rules from highway tag handled elsewhere) +# +assign defaultaccess = + if access= then not motorroad=yes + else if access=private|no then false + else true + +# +# calculate logical bike access +# +assign bikeaccess = + if bicycle= then + ( + if bicycle_road=yes then true + else if vehicle= then ( if highway=footway then false else defaultaccess ) + else not vehicle=private|no + ) + else not bicycle=private|no|dismount|use_sidepath + +# +# calculate logical foot access +# +assign footaccess = + if bicycle=dismount then true + else if foot= then defaultaccess + else not foot=private|no|use_sidepath + +# +# if not bike-, but foot-acess, just a moderate penalty, +# otherwise access is forbidden +# +assign accesspenalty = + if bikeaccess then 0 + else if footaccess then 4 + else if any_cycleroute then 15 + else 10000 + +# +# handle one-ways. On primary roads, wrong-oneways should +# be close to forbidden, while on other ways we just add +# 4 to the costfactor (making it at least 5 - you are allowed +# to push your bike) +# +assign badoneway = + if reversedirection=yes then + if oneway:bicycle=yes then true + else if oneway= then junction=roundabout + else oneway=yes|true|1 + else oneway=-1 + +assign onewaypenalty = + if ( badoneway ) then + ( + if ( cycleway=opposite|opposite_lane|opposite_track ) then 0 + else if ( cycleway:left=opposite|opposite_lane|opposite_track ) then 0 + else if ( cycleway:right=opposite|opposite_lane|opposite_track ) then 0 + else if ( oneway:bicycle=no ) then 0 + else if ( cycleway:left:oneway=no ) then 0 + else if ( cycleway:right:oneway=no ) then 0 + else if ( not footaccess ) then 100 + else if ( junction=roundabout|circular ) then 60 + else if ( highway=primary|primary_link ) then 50 + else if ( highway=secondary|secondary_link ) then 30 + else if ( highway=tertiary|tertiary_link ) then 20 + else 4.0 + ) + else 0.0 + +# add estimate tags +assign traffic_penalty + switch consider_traffic + switch estimated_traffic_class= 0 + switch estimated_traffic_class=1|2 0.2 + switch estimated_traffic_class=3 0.4 + switch estimated_traffic_class=4 0.6 + switch estimated_traffic_class=5 0.8 + switch estimated_traffic_class=6|7 1 99 0 + + +assign noise_penalty + switch consider_noise + switch estimated_noise_class= 0 + switch estimated_noise_class=1 0.3 + switch estimated_noise_class=2 0.5 + switch estimated_noise_class=3 0.8 + switch estimated_noise_class=4 1.4 + switch estimated_noise_class=5 1.7 + switch estimated_noise_class=6 2 0 0 + +assign no_river_penalty + switch consider_river + switch estimated_river_class= 2 + switch estimated_river_class=1 1.3 + switch estimated_river_class=2 1 + switch estimated_river_class=3 0.7 + switch estimated_river_class=4 0.4 + switch estimated_river_class=5 0.1 + switch estimated_river_class=6 0 99 0 + +assign no_forest_penalty + switch consider_forest + switch estimated_forest_class= 1 + switch estimated_forest_class=1 0.5 + switch estimated_forest_class=2 0.4 + switch estimated_forest_class=3 0.25 + switch estimated_forest_class=4 0.15 + switch estimated_forest_class=5 0.1 + switch estimated_forest_class=6 0 99 0 + +assign town_penalty + switch consider_town + switch estimated_town_class= 0 + switch estimated_town_class=1 0.5 + switch estimated_town_class=2 0.9 + switch estimated_town_class=3 1.2 + switch estimated_town_class=4 1.3 + switch estimated_town_class=5 1.4 + switch estimated_town_class=6 1.6 99 0 + +# +# calculate the cost-factor, which is the factor +# by which the distance of a way-segment is multiplied +# to calculate the cost of that segment. The costfactor +# must be >=1 and it's supposed to be close to 1 for +# the type of way the routing profile is searching for +# +assign isresidentialorliving = or highway=residential|living_street living_street=yes +assign costfactor + + # + # exclude rivers, rails etc. + # + if ( and highway= not route=ferry ) then 10000 + + # + # exclude motorways and proposed roads + # + else if ( highway=motorway|motorway_link ) then 10000 + else if ( highway=proposed|abandoned ) then 10000 + + # + # all other exclusions below (access, steps, ferries,..) + # should not be deleted by the decoder, to be available + # in voice-hint-processing + # + else min 9999 + + add town_penalty + add no_forest_penalty + add no_river_penalty + add noise_penalty + add traffic_penalty + + # + # apply oneway-and access-penalties + # + add max onewaypenalty accesspenalty + + # + # steps and ferries are special. Note this is handled + # before the cycleroute-switch, to be able + # to really exclude them be setting cost to infinity + # + if ( highway=steps ) then ( if allow_steps then 40 else 10000 ) + else if ( route=ferry ) then ( if allow_ferries then 5.67 else 10000 ) + + # + # handle long-distance cycle-routes. + # + else if ( is_ldcr ) then 1 # always treated as perfect (=1) + else + add ( if stick_to_cycleroutes then 0.5 else 0.05 ) # everything else somewhat up + + # + # some other highway types + # + if ( highway=pedestrian ) then 3 + else if ( highway=bridleway ) then 5 + else if ( highway=cycleway ) then 1 + else if ( isresidentialorliving ) then ( if isunpaved then 1.5 else 1.1 ) + else if ( highway=service ) then ( if isunpaved then 1.6 else 1.3 ) + + # + # tracks and track-like ways are rated mainly be tracktype/grade + # But note that if no tracktype is given (mainly for road/path/footway) + # it can be o.k. if there's any other hint for quality + # + else if ( highway=track|road|path|footway ) then + ( + if ( tracktype=grade1 ) then ( if probablyGood then 1.0 else 1.3 ) + else if ( tracktype=grade2 ) then ( if probablyGood then 1.1 else 2.0 ) + else if ( tracktype=grade3 ) then ( if probablyGood then 1.5 else 3.0 ) + else if ( tracktype=grade4 ) then ( if probablyGood then 2.0 else 5.0 ) + else if ( tracktype=grade5 ) then ( if probablyGood then 3.0 else 5.0 ) + else ( if probablyGood then 1.0 else 5.0 ) + ) + + # + # When avoiding unsafe ways, avoid highways without a bike hint + # + else add ( if ( and avoid_unsafe not isbike ) then 2 else 0 ) + + # + # actuals roads are o.k. if we have a bike hint + # + if ( highway=trunk|trunk_link ) then ( if isbike then 1.5 else 10 ) + else if ( highway=primary|primary_link ) then ( if isbike then 1.2 else 3 ) + else if ( highway=secondary|secondary_link ) then ( if isbike then 1.1 else 1.6 ) + else if ( highway=tertiary|tertiary_link ) then ( if isbike then 1.0 else 1.4 ) + else if ( highway=unclassified ) then ( if isbike then 1.0 else 1.3 ) + + # + # default for any other highway type not handled above + # + else 2.0 + + +# way priorities used for voice hint generation + +assign priorityclassifier = + + if ( highway=motorway ) then 30 + else if ( highway=motorway_link ) then 29 + else if ( highway=trunk ) then 28 + else if ( highway=trunk_link ) then 27 + else if ( highway=primary ) then 26 + else if ( highway=primary_link ) then 25 + else if ( highway=secondary ) then 24 + else if ( highway=secondary_link ) then 23 + else if ( highway=tertiary ) then 22 + else if ( highway=tertiary_link ) then 21 + else if ( highway=unclassified ) then 20 + else if ( isresidentialorliving ) then 6 + else if ( highway=service ) then 6 + else if ( highway=cycleway ) then 6 + else if ( or bicycle=designated bicycle_road=yes ) then 6 + else if ( highway=track ) then if tracktype=grade1 then 6 else 4 + else if ( highway=bridleway|road|path|footway ) then 4 + else if ( highway=steps ) then 2 + else if ( highway=pedestrian ) then 2 + else 0 + +# some more classifying bits used for voice hint generation... + +assign isbadoneway = not equal onewaypenalty 0 +assign isgoodoneway = if reversedirection=yes then oneway=-1 + else if oneway= then junction=roundabout else oneway=yes|true|1 +assign isroundabout = junction=roundabout +assign islinktype = highway=motorway_link|trunk_link|primary_link|secondary_link|tertiary_link +assign isgoodforcars = if greater priorityclassifier 6 then true + else if ( or isresidentialorliving highway=service ) then true + else if ( and highway=track tracktype=grade1 ) then true + else false + +# ... encoded into a bitmask + +assign classifiermask add isbadoneway + add multiply isgoodoneway 2 + add multiply isroundabout 4 + add multiply islinktype 8 + multiply isgoodforcars 16 + +# include `smoothness=` tags in the response's WayTags for track analysis +assign dummyUsage = smoothness= + +---context:node # following code refers to node tags + +assign defaultaccess = + if ( access= ) then true # add default barrier restrictions here! + else if ( access=private|no ) then false + else true + +assign bikeaccess = + if nodeaccessgranted=yes then true + else if bicycle= then + ( + if vehicle= then defaultaccess + else not vehicle=private|no + ) + else not bicycle=private|no|dismount + +assign footaccess = + if bicycle=dismount then true + else if foot= then defaultaccess + else not foot=private|no + +assign initialcost = + if bikeaccess then 0 + else ( if footaccess then 100 else 1000000 ) diff --git a/misc/profiles2/shortest.brf b/misc/profiles2/shortest.brf index f4e66db..cd1034e 100644 --- a/misc/profiles2/shortest.brf +++ b/misc/profiles2/shortest.brf @@ -12,6 +12,9 @@ assign validForFoot 1 ---context:way # following code refers to way-tags +# show unused tags +assign processUnusedTags = true + assign any_cycleroute or route_bicycle_icn=yes or route_bicycle_ncn=yes or route_bicycle_rcn=yes route_bicycle_lcn=yes assign nodeaccessgranted or any_cycleroute lcn=yes diff --git a/misc/profiles2/trekking.brf b/misc/profiles2/trekking.brf index bc10708..231a939 100644 --- a/misc/profiles2/trekking.brf +++ b/misc/profiles2/trekking.brf @@ -49,7 +49,7 @@ assign turnInstructionCatchingRange = 40 # %turnInstructionCatchingRange% | W assign turnInstructionRoundabouts = true # %turnInstructionRoundabouts% | Set "false" to avoid generating special turning instructions for roundabouts | boolean assign considerTurnRestrictions = true # %considerTurnRestrictions% | Set true to take turn restrictions into account | boolean -assign processUnusedTags = false # %processUnusedTags% | Set true to output unused tags in data tab | boolean +assign processUnusedTags = true # %processUnusedTags% | Set true to output unused tags in data tab | boolean ---context:way # following code refers to way-tags diff --git a/misc/scripts/mapcreation/brouter.sql b/misc/scripts/mapcreation/brouter.sql index 359f093..4e8a7a9 100644 --- a/misc/scripts/mapcreation/brouter.sql +++ b/misc/scripts/mapcreation/brouter.sql @@ -2,6 +2,845 @@ -- formatted by https://sqlformat.darold.net/ SET client_encoding TO UTF8; +-- prepare the lines table with a new index and a new column +SELECT + now(); + +ANALYZE; + +SELECT + now(); + +SELECT + osm_id, + highway, + maxspeed, + way, + waterway, + li.natural, + width, + oneway, + st_length (way) / st_length (ST_Transform (way, 4326)::geography) AS merca_coef INTO TABLE lines_bis +FROM + lines li; + +SELECT + now(); + +DROP TABLE lines; + +ALTER TABLE lines_bis RENAME TO lines; + +CREATE INDEX lines_osm_id_idx ON lines (osm_id) WITH (fillfactor = '100'); + +CREATE INDEX lines_way_idx ON public.lines USING gist (way) WITH (fillfactor = '100'); + +ANALYZE lines; + +-- generation of pseudo-tags +-- 1: noise +-- create a table with the segments producing noise (motorway, primary and secondary) and a noise_factor for each. +-- the noise_factor depends on the highway type, maxspeed and oneway +-- oneway is basically given on motorway segments, in some cases also on primary... +-- then 2 segments exist on the same route, so noise_factor per segment is lower!!!! +SELECT + now(); + +SELECT + osm_id::bigint, + highway, + maxspeed, + CASE WHEN maxspeed IS NULL + OR (NOT (maxspeed ~ '^\d+(\.\d+)?$')) + OR maxspeed::numeric > '105' THEN + -- maxspeed not defined OR not numeric / usable OR > 105 km/h + CASE WHEN highway IN ('motorway', 'motorway_link', 'trunk', 'trunk_link') THEN + 0.6 + WHEN highway IN ('primary', 'primary_link') THEN + CASE WHEN oneway IS NULL + OR oneway NOT IN ('yes', 'true', '1') THEN + 0.66 + ELSE + 0.45 + END + WHEN highway IN ('secondary') THEN + 0.33 + ELSE + 0 + END + WHEN maxspeed::numeric > '75' THEN + -- 75 < maxspeed <= 105 + CASE WHEN highway IN ('motorway', 'motorway_link', 'trunk', 'trunk_link') THEN + 0.55 + WHEN highway IN ('primary', 'primary_link') THEN + CASE WHEN oneway IS NULL + OR oneway NOT IN ('yes', 'true', '1') THEN + 0.66 + ELSE + 0.45 + END + WHEN highway IN ('secondary') THEN + 0.33 + ELSE + 0 + END + ELSE + -- maxspeed <= 75 + CASE WHEN highway IN ('motorway', 'motorway_link', 'trunk', 'trunk_link') THEN + 0.4 + WHEN highway IN ('primary', 'primary_link') THEN + CASE WHEN oneway IS NULL + OR oneway NOT IN ('yes', 'true', '1') THEN + 0.4 + ELSE + 0.3 + END + WHEN highway IN ('secondary') THEN + 0.2 + ELSE + 0 + END + END AS noise_factor, + way AS way, + ST_Buffer (way, 75 * merca_coef) AS way75, + merca_coef INTO TABLE noise_emittnew +FROM + lines li +WHERE + highway IS NOT NULL + AND highway IN ('motorway', 'motorway_link', 'trunk', 'trunk_link', 'primary', 'primary_link', 'secondary'); + +SELECT + now(); + +CREATE INDEX noise_emittnew_osm_id_idx ON noise_emittnew (osm_id) WITH (fillfactor = '100'); + +-- modify noise_factor by very small segments +SELECT + now(); + +UPDATE + noise_emittnew +SET + noise_factor = noise_factor * (st_length (way) / merca_coef) / 20 +WHERE (st_length (way) / merca_coef) < 20; + +SELECT + now(); + +ANALYZE noise_emittnew; + +SELECT + now(); + +-- create a tuple (highway + noise source) of the highways having noise (for perf tuning) +SELECT + dd.osm_id::bigint AS lines_osm_id, + dd.highway, + dd.merca_coef, + dd.way, + q.osm_id AS noise_osm_id INTO TABLE tuples_with_noise +FROM + lines dd + INNER JOIN noise_emittnew AS q ON ST_Intersects (dd.way, q.way75) +WHERE + dd.highway IS NOT NULL + AND dd.highway NOT IN ('proposed', 'construction') + AND (st_length (dd.way) / dd.merca_coef) < 40000; + +--group by dd.osm_id, dd.highway, dd.merca_coef, dd.way; +SELECT + now(); + +CREATE INDEX tuples_with_noise_osm_id_idx ON tuples_with_noise (lines_osm_id) WITH (fillfactor = '100'); + +SELECT + now(); + +ANALYZE tuples_with_noise; + +SELECT + lines_osm_id AS osm_id, + way, + merca_coef INTO TABLE lines_with_noise +FROM + tuples_with_noise +GROUP BY + lines_osm_id, + merca_coef, + way; + +SELECT + now(); + +CREATE INDEX lineswithnoise_osm_id_idx ON lines_with_noise (osm_id) WITH (fillfactor = '100'); + +ANALYZE lines_with_noise; + +-- calculate noise using "lines_with_noise" +-- split each segment with noise into 20 meter sections and calculate the noise per section +-- the average giving the noise for the segment +SELECT + now(); + +WITH lines_split AS ( + SELECT + osm_id, + merca_coef, + ST_LineSubstring (d.way, startfrac, LEAST (endfrac, 1)) AS way, + len / merca_coef AS lgt_seg_real + FROM ( + SELECT + osm_id, + merca_coef, + way, + st_length (way) len, + (20 * merca_coef) sublen + FROM + lines_with_noise) AS d + CROSS JOIN LATERAL ( + SELECT + i, + (sublen * i) / len AS startfrac, + (sublen * (i + 1)) / len AS endfrac + FROM + generate_series(0, floor(len / sublen)::integer) AS t (i) + -- skip last i if line length is exact multiple of sublen + WHERE (sublen * i) / len <> 1.0) AS d2 +) +SELECT + m.osm_id::bigint losmid, + m.lgt_seg_real, + st_distance (m.way, t.way) / m.merca_coef AS dist, + -- the line below delivers the same result as above !!!!!!! but need much more time (* 7 !) + -- st_distance(st_transform(m.way, 4326)::geography, st_transform(t.way, 4326)::geography) as distgeog, + t.noise_factor INTO TABLE noise_tmp2newz +FROM + lines_split AS m + INNER JOIN tuples_with_noise AS q ON m.osm_id = q.lines_osm_id + INNER JOIN noise_emittnew t ON t.osm_id = q.noise_osm_id +WHERE + st_distance (m.way, t.way) / m.merca_coef < 75; + +SELECT + now(); + +ANALYZE noise_tmp2newz; + +-- group +SELECT + now(); + +-- calculate an indicator per section (1 / d*d here) and reduce the results by taking the average on the osm_segment +SELECT + losmid, + m.lgt_seg_real, + sum(noise_factor / ((dist + 15) / 15)) / ((m.lgt_seg_real / 20)::integer + 1) AS sum_noise_factor INTO noise_tmp2new +FROM + noise_tmp2newz m +GROUP BY + m.losmid, + m.lgt_seg_real; + +SELECT + now(); + +DROP TABLE noise_tmp2newz; + +DROP TABLE tuples_with_noise; + +DROP TABLE noise_emittnew; + +ANALYZE noise_tmp2new; + +SELECT + now(); + +-- add noise from Airports... +-- polygons of the international airports +SELECT + name, + st_buffer (way, (700 * st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 3857)) / st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 4326)::geography))) AS way INTO TABLE poly_airportnew +FROM + polygons +WHERE + aeroway = 'aerodrome' + AND aerodrome = 'international'; + +SELECT + now(); + +ANALYZE poly_airportnew; + +SELECT + m.osm_id::bigint losmid, + -- st_area(st_intersection(m.way, q.way)) / (st_area(m.way) * 1.5) + -- 1 / 1.5 + (700 - (st_distance (m.way, q.way) / m.merca_coef)) / (700 * 1.5) AS dist_factor INTO TABLE noise_airportnew +FROM + lines AS m + INNER JOIN poly_airportnew AS q ON ST_intersects (m.way, q.way) +WHERE + m.highway IS NOT NULL +ORDER BY + dist_factor DESC; + +SELECT + now(); + +ANALYZE noise_airportnew; + +SELECT + losmid, + sum(noise_factor) AS sum_noise_factor INTO TABLE noise_tmp3new +FROM (( + SELECT + losmid, + sum_noise_factor AS noise_factor + FROM + noise_tmp2new AS nois1) + UNION ( + SELECT + losmid, + dist_factor AS noise_factor + FROM + noise_airportnew AS nois2)) AS nois_sum +GROUP BY + losmid; + +SELECT + now(); + +ANALYZE noise_tmp3new; + +-- create the noise classes +SELECT + now(); + +SELECT + losmid, + CASE WHEN y.sum_noise_factor < 0.06 THEN + '1' + WHEN y.sum_noise_factor < 0.13 THEN + '2' + WHEN y.sum_noise_factor < 0.26 THEN + '3' + WHEN y.sum_noise_factor < 0.45 THEN + '4' + WHEN y.sum_noise_factor < 0.85 THEN + '5' + ELSE + '6' + END AS noise_class INTO TABLE noise_tags +FROM + noise_tmp3new y +WHERE + y.sum_noise_factor > 0.01 +ORDER BY + noise_class; + +SELECT + now(); + +ANALYZE noise_tags; + +SELECT + count(*) +FROM + noise_tags; + +SELECT + noise_class, + count(*) +FROM + noise_tags +GROUP BY + noise_class +ORDER BY + noise_class; + +------------------------------------------------------------------------- +-- 2: create tags for river +-- create a table with the segments and polygons with "river" (or water!) +SELECT + now(); + +WITH river_from_polygons AS ( + SELECT + osm_id::bigint, + way, + ST_Buffer (way, 110 * st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 3857)) / st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 4326)::geography)) AS way2 + FROM + polygons q + WHERE + q.natural IN ('water', 'bay', 'beach', 'wetland') + AND (q.water IS NULL + OR q.water NOT IN ('wastewater')) + AND st_area (ST_Transform (q.way, 4326)::geography) BETWEEN 1000 AND 5000000000 +), +river_from_lines AS ( + SELECT + osm_id::bigint, + way, + ST_Buffer (way, 80 * merca_coef) AS way2 + FROM + lines q + WHERE + q.waterway IN ('river', 'canal', 'fairway') + OR q.natural IN ('coastline') + ORDER BY + way +), +river_coastline AS ( + SELECT + osm_id::bigint, + way, + ST_Buffer (ST_ExteriorRing (way), 100 * st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 3857)) / st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 4326)::geography)) AS way2 + FROM + polygons p + WHERE + st_area (ST_Transform (p.way, 4326)::geography) > 1000 + AND (p.natural IN ('coastline') + AND st_length (way) < 100000) + ORDER BY + way +) +SELECT + * INTO river_proxy +FROM ( + SELECT + * + FROM + river_from_polygons part1 + UNION + SELECT + * + FROM + river_from_lines part2 + UNION + SELECT + * + FROM + river_coastline part3) AS sumriver; + +SELECT + now(); + +CREATE INDEX river_proxy_osm_id_idx ON river_proxy (osm_id) WITH (fillfactor = '100'); + +ANALYZE river_proxy; + +SELECT + now(); + +-- create a tuple (highway + noise source) of the highways in river proxymity (for perf tuning) +SELECT + dd.osm_id::bigint AS lines_osm_id, + dd.merca_coef, + dd.way, + q.osm_id AS river_osm_id INTO TABLE tuples_with_river +FROM + lines dd + INNER JOIN river_proxy AS q ON ST_Intersects (dd.way, q.way2) +WHERE + dd.highway IS NOT NULL + AND dd.highway NOT IN ('proposed', 'construction') + AND (st_length (dd.way) / dd.merca_coef) < 40000; + +SELECT + now(); + +CREATE INDEX tuples_with_river_osm_id_idx ON tuples_with_river (lines_osm_id) WITH (fillfactor = '100'); + +SELECT + now(); + +ANALYZE tuples_with_river; + +SELECT + now(); + +-- create a table of highways with river... +SELECT + lines_osm_id AS osm_id, + way, + merca_coef INTO TABLE lines_with_river +FROM + tuples_with_river +GROUP BY + lines_osm_id, + merca_coef, + way; + +SELECT + now(); + +CREATE INDEX lineswithriver_osm_id_idx ON lines_with_river (osm_id) WITH (fillfactor = '100'); + +ANALYZE lines_with_river; + +SELECT + now(); + +-- calculate river factor using "lines_with_river" +-- split each segment with river into 20 meter sections and calculate the river per section +-- the average giving the river_factor for the segment +WITH lines_split AS ( + SELECT + osm_id, + merca_coef, + ST_LineSubstring (d.way, startfrac, LEAST (endfrac, 1)) AS way, + len / merca_coef AS lgt_seg_real + FROM ( + SELECT + osm_id, + merca_coef, + way, + st_length (way) len, + (20 * merca_coef) sublen + FROM + lines_with_river) AS d + CROSS JOIN LATERAL ( + SELECT + i, + (sublen * i) / len AS startfrac, + (sublen * (i + 1)) / len AS endfrac + FROM + generate_series(0, floor(len / sublen)::integer) AS t (i) + -- skip last i if line length is exact multiple of sublen + WHERE (sublen * i) / len <> 1.0) AS d2 +) +SELECT + m.osm_id::bigint losmid, + m.lgt_seg_real, + st_distance (m.way, t.way) / m.merca_coef AS dist INTO TABLE river_tmp2newz +FROM + lines_split AS m + INNER JOIN tuples_with_river AS q ON m.osm_id = q.lines_osm_id + INNER JOIN river_proxy t ON t.osm_id = q.river_osm_id +WHERE + st_distance (m.way, t.way) / m.merca_coef < 165; + +SELECT + now(); + +ANALYZE river_tmp2newz; + +SELECT + now(); + +SELECT + losmid, + m.lgt_seg_real, + sum(1 / ((dist + 50) / 50)) / ((m.lgt_seg_real / 20)::integer + 1) AS sum_river_factor INTO river_tmp2new +FROM + river_tmp2newz m +GROUP BY + m.losmid, + m.lgt_seg_real; + +SELECT + now(); + +DROP TABLE river_tmp2newz; + +DROP TABLE tuples_with_river; + +DROP TABLE river_proxy; + +ANALYZE river_tmp2new; + +SELECT + now(); + +SELECT + losmid, + CASE WHEN y.sum_river_factor < 0.22 THEN + '1' + WHEN y.sum_river_factor < 0.35 THEN + '2' + WHEN y.sum_river_factor < 0.5 THEN + '3' + WHEN y.sum_river_factor < 0.75 THEN + '4' + WHEN y.sum_river_factor < 0.98 THEN + '5' + ELSE + '6' + END AS river_class INTO TABLE river_tags +FROM + river_tmp2new y +WHERE + y.sum_river_factor > 0.03; + +SELECT + now(); + +SELECT + count(*) +FROM + river_tags; + +SELECT + river_class, + count(*) +FROM + river_tags +GROUP BY + river_class +ORDER BY + river_class; + +SELECT + now(); + +------------------------------------------------------------- +-- create pseudo-tags for forest +-- +-- create first a table of the polygons with forest +SELECT + now(); + +SELECT + osm_id::bigint, + leisure, + landuse, + p.natural, + p.water, + way, + ST_Buffer (way, 32.15 * st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 3857)) / st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 4326)::geography)) AS way32 INTO TABLE osm_poly_forest +FROM + polygons p +WHERE + st_area (ST_Transform (p.way, 4326)::geography) > 1500 + AND ((p.landuse IN ('forest', 'allotments', 'flowerbed', 'orchard', 'vineyard', 'recreation_ground', 'village_green')) + OR p.leisure IN ('garden', 'park', 'nature_reserve')) + AND st_area (ST_Transform (p.way, 4326)::geography) BETWEEN 5000 AND 5000000000 +ORDER BY + way; + +SELECT + now(); + +CREATE INDEX osm_poly_forest_osm_id_idx ON osm_poly_forest (osm_id) WITH (fillfactor = '100'); + +SELECT + now(); + +ANALYZE osm_poly_forest; + +-- create a table of the lines within forests (green_factor is nomally 1, but 5 is better to calculate class 6 ) +SELECT + now(); + +SELECT + m.osm_id::bigint, + m.highway, + 6 AS green_factor INTO TABLE lines_within_forest +FROM + lines AS m + INNER JOIN osm_poly_forest q ON ST_Within (m.way, q.way) +WHERE + m.highway IS NOT NULL +GROUP BY + m.osm_id, + m.highway, + m.way; + +CREATE INDEX lines_within_forest_osm_id_idx ON lines_within_forest (osm_id) WITH (fillfactor = '100'); + +SELECT + now(); + +ANALYZE lines_within_forest; + +-- create a tuple table (lines+polygons) of the lines near but not within forests +SELECT + m.osm_id::bigint AS lines_osm_id, + m.highway, + m.merca_coef, + m.way AS lines_way, + q.osm_id AS forest_osm_id INTO TABLE tuples_limit_forest +FROM + lines AS m + INNER JOIN osm_poly_forest AS q ON ST_Intersects (m.way, q.way32) +WHERE + m.highway IS NOT NULL + AND m.highway NOT IN ('proposed', 'construction') + AND (st_length (m.way) / m.merca_coef) < 40000 + AND m.osm_id::bigint NOT IN ( + SELECT + osm_id + FROM + lines_within_forest); + +SELECT + now(); + +CREATE INDEX tuples_lines_osm_id_idx ON tuples_limit_forest (lines_osm_id) WITH (fillfactor = '100'); + +SELECT + now(); + +ANALYZE tuples_limit_forest; + +SELECT + now(); + +-- create a table with only the lines near but not within forests +SELECT + m.lines_osm_id osm_id, + m.highway, + m.merca_coef, + m.lines_way AS way INTO TABLE lines_limit_forest +FROM + tuples_limit_forest AS m +GROUP BY + m.lines_osm_id, + m.highway, + m.merca_coef, + m.lines_way; + +SELECT + now(); + +CREATE INDEX lines_limit_forest_osm_id_idx ON lines_limit_forest (osm_id) WITH (fillfactor = '100'); + +SELECT + now(); + +ANALYZE lines_limit_forest; + +-- calculate the forest factor (or green_factor) for the lines at forest limit.. +-- spilt the line into 20 meter sections +-- calculate the distance section-forest +SELECT + now(); + +WITH lines_split AS ( + SELECT + osm_id, + highway, + merca_coef, + ST_LineSubstring (d.way, startfrac, LEAST (endfrac, 1)) AS way, + len / merca_coef AS lgt_seg_real + FROM ( + SELECT + osm_id, + highway, + merca_coef, + way, + st_length (way) len, + (20 * merca_coef) sublen + FROM + lines_limit_forest) AS d + CROSS JOIN LATERAL ( + SELECT + i, + (sublen * i) / len AS startfrac, + (sublen * (i + 1)) / len AS endfrac + FROM + generate_series(0, floor(len / sublen)::integer) AS t (i) + -- skip last i if line length is exact multiple of sublen + WHERE (sublen * i) / len <> 1.0) AS d2 +) +SELECT + m.osm_id, + lgt_seg_real, + st_distance (m.way, t.way) / m.merca_coef AS dist INTO TABLE forest_tmp2newz +FROM + lines_split AS m + INNER JOIN tuples_limit_forest AS q ON m.osm_id = q.lines_osm_id + INNER JOIN osm_poly_forest t ON t.osm_id = q.forest_osm_id +WHERE + st_distance (m.way, t.way) / m.merca_coef < 65; + +SELECT + now(); + +ANALYZE forest_tmp2newz; + +SELECT + now(); + +SELECT + m.osm_id, + m.lgt_seg_real, + sum(1 / ((dist + 25) / 25)) / ((m.lgt_seg_real / 20)::integer + 1) AS green_factor INTO forest_tmp2new +FROM + forest_tmp2newz m +GROUP BY + m.osm_id, + m.lgt_seg_real; + +SELECT + now(); + +ANALYZE forest_tmp2new; + +DROP TABLE forest_tmp2newz; + +DROP TABLE osm_poly_forest; + +DROP TABLE tuples_limit_forest; + +SELECT + now(); + +-- merge lines_within_forest with lines_limit_forest +WITH forest_tmp3new AS ( + SELECT + * + FROM ( + SELECT + osm_id, + green_factor + FROM + forest_tmp2new AS part1 + UNION + SELECT + osm_id, + green_factor + FROM + lines_within_forest) AS part2 +) +SELECT + y.osm_id losmid, + CASE WHEN y.green_factor < 0.32 THEN + '1' + WHEN y.green_factor < 0.5 THEN + '2' + WHEN y.green_factor < 0.7 THEN + '3' + WHEN y.green_factor < 0.92 THEN + '4' + WHEN y.green_factor < 5 THEN + '5' + ELSE + '6' + END AS forest_class INTO TABLE forest_tags +FROM + forest_tmp3new y +WHERE + y.green_factor > 0.1; + +ANALYZE forest_tags; + +SELECT + count(*) +FROM + forest_tags; + +SELECT + forest_class, + count(*) +FROM + forest_tags +GROUP BY + forest_class +ORDER BY + forest_class; + SELECT now(); @@ -21,133 +860,10 @@ $$ LANGUAGE plpgsql SECURITY INVOKER; --- create new tables for tuning --- -SELECT - osm_id::bigint, - highway, - waterway, - li.natural, - width, - maxspeed, - CASE WHEN maxspeed IS NULL THEN - 0 - --when not isnumeric(maxspeed) then 0 - WHEN NOT (maxspeed ~ '^\d+(\.\d+)?$') THEN - 0 - WHEN maxspeed::numeric > '105' THEN - 1 - WHEN maxspeed::numeric > '75' THEN - 2 - ELSE - 3 - END AS maxspeed_class - -- "buffer radius" was initially created with 50 meters at a latitude of 50 degrees... ==> ST_Buffer(way,50) - -- but, using geometry "projection", to get same results by a calculation of the planet (latitude between -80, +85) this value should be adapted to the latitude of the highways... -, - -- - ST_Buffer (way, 32.15 * st_length (ST_Transform (way, 3857)) / st_length (ST_Transform (way, 4326)::geography)) AS way INTO TABLE osm_line_buf_50 -FROM - lines li -WHERE - highway IS NOT NULL - OR waterway IN ('river', 'canal', 'fairway') - OR (li.natural = 'coastline' - AND st_length (way) < 100000); - SELECT now(); --- modify "way" by large waterways !!" (example Rhein ==> width = 400 ...) enlarge a bit the "50 meter" buffer -UPDATE - osm_line_buf_50 -SET - way = st_buffer (way, (width::numeric / 10)) -WHERE - waterway = 'river' - AND width IS NOT NULL - AND (width ~ '^[0-9\.]+$') - AND width::numeric > 15 - AND width::numeric < 2500; - -SELECT - osm_id::bigint, - leisure, - landuse, - p.natural, - p.water, - ST_Buffer (way, 32.15 * st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 3857)) / st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 4326)::geography)) AS way INTO TABLE osm_poly_buf_50 -FROM - polygons p -WHERE - -- do not consider small surfaces - st_area (p.way) > 1000 - AND (p.natural IN ('water', 'bay', 'beach', 'wetland') - OR p.landuse IN ('forest', 'allotments', 'flowerbed', 'orchard', 'vineyard', 'recreation_ground', 'village_green') - OR p.leisure IN ('garden', 'park', 'nature_reserve')); - --- by forest no buffer ! -SELECT - osm_id::bigint, - leisure, - landuse, - p.natural, - p.water, - way INTO TABLE osm_poly_no_buf -FROM - polygons p -WHERE - -- do not consider small surfaces - st_area (p.way) > 1000 - AND (p.natural IN ('water', 'bay', 'beach', 'costline', 'wetland') - OR p.landuse IN ('forest', 'allotments', 'flowerbed', 'orchard', 'vineyard', 'recreation_ground', 'village_green') - OR p.leisure IN ('garden', 'park', 'nature_reserve')); - -SELECT - osm_id::bigint, - leisure, - landuse, - p.natural, - p.water, - ST_Buffer (way, 45 * st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 3857)) / st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 4326)::geography)) AS way INTO TABLE osm_poly_buf_120 -FROM - osm_poly_buf_50 p; - --- for coastline special case -SELECT - osm_id::bigint, - leisure, - landuse, - p.natural, - p.water, - ST_Buffer (ST_ExteriorRing (way), 64 * st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 3857)) / st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 4326)::geography)) AS way INTO TABLE osm_poly_coastline_buf_100 -FROM - polygons p -WHERE - -- do not consider small surfaces - st_area (p.way) > 1000 - AND (p.natural IN ('coastline') - AND st_length (way) < 100000); - ---CREATE INDEX osm_poly_coastline_ind ON public.osm_poly_coastline_buf_100 USING gist (way) WITH (fillfactor='100'); -SELECT - * INTO TABLE osm_line_water -FROM - osm_line_buf_50 q -WHERE - q.waterway IN ('river', 'canal', 'fairway') - OR q.natural IN ('coastline'); - -CREATE INDEX osm_line_water_ind ON public.osm_line_water USING gist (way) WITH (fillfactor = '100'); - -SELECT - now(); - --- create indexes -CREATE INDEX osm_line_buf_50_idx ON public.osm_line_buf_50 USING gist (way) WITH (fillfactor = '100'); - -ANALYZE; - +-- create tables for traffic SELECT osm_id, highway, @@ -166,6 +882,168 @@ CREATE INDEX primsecter15k_idx1 ON public.primsecter15k USING gist (way) WITH (f CREATE INDEX primsecter15k_idx0 ON public.primsecter15k USING gist (way0) WITH (fillfactor = '100'); +ANALYZE primsecter15k; + +SELECT + now(); + +-- consistency check on population, first evaluate and documents it +WITH cities_x AS ( + SELECT + a.name, + a.name_en, + place, + osm_id, + replace(a.population, '.', '')::bigint population, + a.way + FROM + cities a + WHERE + a.population IS NOT NULL + AND isnumeric (a.population) + AND a.place IN ('village', 'town', 'city', 'municipality')) +SELECT + name, + name_en, + place, + population, + osm_id +FROM + cities_x a +WHERE (place = 'village' + AND a.population > 90000) + OR (place = 'town' + AND a.population > 1500000) + OR (place = 'city' + AND a.population > 40000000) +ORDER BY + place, + Population DESC; + +WITH cities_relx AS ( + SELECT + a.name, + a.name_en, + place, + osm_id, + replace(a.population, '.', '')::bigint population, + a.way + FROM + cities_rel a + WHERE + a.population IS NOT NULL + AND isnumeric (a.population) + AND a.place IN ('village', 'town', 'city', 'municipality')) +SELECT + name, + name_en, + place, + population, + osm_id +FROM + cities_relx a +WHERE (place = 'village' + AND a.population > 90000) + OR (place = 'town' + AND a.population > 1500000) + OR (place = 'city' + AND a.population > 40000000) + OR (place IS NULL + AND a.population > 40000000) +ORDER BY + place, + Population DESC; + +-- now store the inconstencies +WITH cities_x AS ( + SELECT + a.name, + a.name_en, + place, + osm_id, + replace(a.population, '.', '')::bigint population, + a.way + FROM + cities a + WHERE + a.population IS NOT NULL + AND isnumeric (a.population) + AND a.place IN ('village', 'town', 'city', 'municipality')) +SELECT + name, + name_en, + place, + population, + osm_id INTO TABLE cities_incon +FROM + cities_x a +WHERE (place = 'village' + AND a.population > 90000) + OR (place = 'town' + AND a.population > 1500000) + OR (place = 'city' + AND a.population > 40000000) +ORDER BY + place, + Population DESC; + +WITH cities_relx AS ( + SELECT + a.name, + a.name_en, + place, + osm_id, + replace(a.population, '.', '')::bigint population, + a.way + FROM + cities_rel a + WHERE + a.population IS NOT NULL + AND isnumeric (a.population) + AND a.place IN ('village', 'town', 'city', 'municipality')) +SELECT + name, + name_en, + place, + population, + osm_id INTO TABLE cities_rel_incon +FROM + cities_relx a +WHERE (place = 'village' + AND a.population > 90000) + OR (place = 'town' + AND a.population > 1500000) + OR (place = 'city' + AND a.population > 40000000) + OR (place IS NULL + AND a.population > 40000000) +ORDER BY + place, + Population DESC; + +-- and eliminate the inconsistencies +UPDATE + cities +SET + population = 0 +WHERE + osm_id IN ( + SELECT + osm_id + FROM + cities_incon); + +UPDATE + cities_rel +SET + population = 0 +WHERE + osm_id IN ( + SELECT + osm_id + FROM + cities_rel_incon); + SELECT now(); @@ -173,18 +1051,25 @@ SELECT -- clean the cities table (when population is null or population is not numeric or unusable) SELECT a.name, + a.name_en, replace(a.population, '.', '')::bigint population, - a.way INTO cities_ok + a.way INTO TABLE cities_ok FROM cities a WHERE a.population IS NOT NULL AND isnumeric (a.population) - AND a.place IN ('town', 'city', 'municipality'); + AND a.place IN ('village', 'town', 'city', 'municipality'); + +ANALYZE cities_ok; + +SELECT + now(); -- clean the cities_rel table (when population is not numeric or unusable) SELECT a.name AS name, + a.name_en AS name_en, a.place AS place, a.admin_level, CASE WHEN a.population IS NOT NULL @@ -193,20 +1078,26 @@ SELECT ELSE NULL END AS population, - a.way INTO cities_rel_ok + a.way INTO TABLE cities_rel_ok FROM cities_rel a WHERE - boundary = 'administrative'; + boundary IN ('administrative', 'ceremonial'); CREATE INDEX cities_ok_idx ON public.cities_ok USING gist (way) WITH (fillfactor = '100'); CREATE INDEX cities_rel_ok_idx ON public.cities_rel_ok USING gist (way) WITH (fillfactor = '100'); --- select town + population + way starting with cities_ok ... (to catch special cases as ex. "Berlin" which is tagged with "admin_level=4") +SELECT + now(); + +ANALYZE cities_rel_ok; + +-- select town + population + way starting with cities_ok .... (to catch specials cases as ex. "Berlin" which is tagged with "admin_level=4") -- SELECT a.name AS name, + a.name_en AS name_en, st_x (a.way), st_y (a.way), a.population, @@ -295,7 +1186,7 @@ LIMIT 1) AND a.name = b.name AND st_intersects (a.way, b.way)) LIMIT 1) --- Berlin admin_level=4! +-- Berlin admin_level=4! , but Beijing/Shangai administrative-regions have the same name and area>20000 km*2 !!! WHEN ( SELECT way @@ -324,7 +1215,7 @@ LIMIT 1) cities_rel_ok b WHERE (st_area (b.way) / 1000000 < 10000 AND b.admin_level IS NULL - AND b.place IN ('city', 'town') + AND b.place IN ('town', 'city', 'village', 'municipality') AND a.name = b.name AND st_intersects (a.way, b.way)) LIMIT 1) IS NOT NULL THEN @@ -335,7 +1226,7 @@ LIMIT 1) cities_rel_ok b WHERE (st_area (b.way) / 1000000 < 10000 AND b.admin_level IS NULL - AND b.place IN ('city', 'town') + AND b.place IN ('town', 'city', 'village', 'municipality') AND a.name = b.name AND st_intersects (a.way, b.way)) LIMIT 1) @@ -347,7 +1238,7 @@ LIMIT 1) cities_rel_ok b WHERE (st_area (b.way) / 1000000 < 10000 AND b.admin_level = '2' - AND b.place IN ('city', 'town') + AND b.place IN ('town', 'city', 'village', 'municipality') AND a.name = b.name AND st_intersects (a.way, b.way)) LIMIT 1) IS NOT NULL THEN @@ -358,7 +1249,7 @@ LIMIT 1) cities_rel_ok b WHERE (st_area (b.way) / 1000000 < 10000 AND b.admin_level = '2' - AND b.place IN ('city', 'town') + AND b.place IN ('town', 'city', 'village', 'municipality') AND a.name = b.name AND st_intersects (a.way, b.way)) LIMIT 1) @@ -376,9 +1267,17 @@ FROM ORDER BY name; --- select town + population + way starting with cities_rel_ok ... +CREATE INDEX cities_intermed3_idx ON public. cities_intermed3 USING gist (way) WITH (fillfactor = '100'); + +SELECT + now(); + +ANALYZE cities_intermed3; + +-- select town + population + way starting with cities_rel_ok .... SELECT a.name AS name, + a.name_en AS name_en, st_area (a.way) st_area, CASE WHEN a.population IS NOT NULL THEN a.population @@ -398,43 +1297,52 @@ FROM cities_rel_ok a WHERE a.admin_level = '8' + AND (a.place IS NULL + OR a.place IN ('town', 'city', 'village', 'municipality')) ORDER BY a.name; --- merge SELECT - name, - max(population) AS population, - way, - max(way0) AS way0, - st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 3857)) / st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 4326)::geography) AS merca_coef INTO cities_intermed5 -FROM (( - SELECT - name, - population, - way, - way0 - FROM - cities_intermed3) - UNION ( - SELECT - name, - population, - way, - way0 - FROM - cities_intermed4)) a -WHERE - population IS NOT NULL - -- and population > 20000 -GROUP BY - name, - way -ORDER BY - population; + now(); +-- merge +WITH intermed5 AS ( + SELECT + name, + max(name_en) AS name_en, + max(population) AS population, + way, + max(way0) AS way0, + st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 3857)) / st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 4326)::geography) AS merca_coef + FROM (( + SELECT + name, + name_en, + population, + way, + way0 + FROM + cities_intermed3) + UNION ( + SELECT + name, + name_en, + population, + way, + way0 + FROM + cities_intermed4)) a + WHERE + population IS NOT NULL + GROUP BY + name, + way + ORDER BY + population +) SELECT name, + name_en, population, way, CASE WHEN way0 IS NULL THEN @@ -443,565 +1351,16 @@ SELECT way0::geometry END AS way0, merca_coef INTO TABLE cities_all -FROM - cities_intermed5; - -SELECT - now(); - --- create tags for noise --- create raw data for noise coming from cars --- when several highways-segments are producing noise, aggregate the noises using the "ST_Union" of the segments! --- (better as using "sum" or "max" that do not deliver good factors) -SELECT - * INTO TABLE osm_line_noise -FROM - osm_line_buf_50 q -WHERE - q.highway IN ('motorway', 'motorway_link', 'trunk', 'trunk_link', 'primary', 'primary_link', 'secondary'); - -CREATE INDEX osm_line_noise_ind ON public.osm_line_noise USING gist (way) WITH (fillfactor = '100'); - -SELECT - now(); - -SELECT - m.osm_id losmid, - m.highway lhighway, - q.highway AS qhighway, - q.maxspeed_class, - st_area (st_intersection (m.way, ST_Union (q.way))) / st_area (m.way) AS noise_factor INTO TABLE noise_part0 -FROM - osm_line_buf_50 AS m - INNER JOIN osm_line_noise AS q ON ST_Intersects (m.way, q.way) -WHERE - m.highway IS NOT NULL - AND q.highway IN ('motorway', 'motorway_link', 'trunk', 'trunk_link') - AND q.maxspeed_class < 1.1 -GROUP BY - losmid, - lhighway, - m.way, - q.highway, - q.maxspeed_class -ORDER BY - noise_factor DESC; - -SELECT - now(); - -SELECT - m.osm_id losmid, - m.highway lhighway, - q.highway AS qhighway, - q.maxspeed_class, - st_area (st_intersection (m.way, ST_Union (q.way))) / (1.5 * st_area (m.way)) AS noise_factor INTO TABLE noise_part1 -FROM - osm_line_buf_50 AS m - INNER JOIN osm_line_noise AS q ON ST_Intersects (m.way, q.way) -WHERE - m.highway IS NOT NULL - AND q.highway IN ('motorway', 'motorway_link', 'trunk', 'trunk_link') - AND q.maxspeed_class >= 1.1 -GROUP BY - losmid, - lhighway, - m.way, - q.highway, - q.maxspeed_class -ORDER BY - noise_factor DESC; - -SELECT - now(); - -SELECT - m.osm_id losmid, - m.highway lhighway, - q.highway AS qhighway, - q.maxspeed_class, - st_area (st_intersection (m.way, ST_Union (q.way))) / (2 * st_area (m.way)) AS noise_factor INTO TABLE noise_part2 -FROM - osm_line_buf_50 AS m - INNER JOIN osm_line_noise AS q ON ST_Intersects (m.way, q.way) -WHERE - m.highway IS NOT NULL - AND q.highway IN ('primary', 'primary_link') - AND q.maxspeed_class < 2.1 -GROUP BY - losmid, - lhighway, - m.way, - q.highway, - q.maxspeed_class -ORDER BY - noise_factor DESC; - -SELECT - now(); - -SELECT - m.osm_id losmid, - m.highway lhighway, - q.highway AS qhighway, - q.maxspeed_class, - st_area (st_intersection (m.way, ST_Union (q.way))) / (3 * st_area (m.way)) AS noise_factor INTO TABLE noise_part3 -FROM - osm_line_buf_50 AS m - INNER JOIN osm_line_noise AS q ON ST_Intersects (m.way, q.way) -WHERE - m.highway IS NOT NULL - AND q.highway IN ('primary', 'primary_link') - AND q.maxspeed_class >= 2.1 -GROUP BY - losmid, - lhighway, - m.way, - q.highway, - q.maxspeed_class -ORDER BY - noise_factor DESC; - -SELECT - now(); - -SELECT - m.osm_id losmid, - m.highway lhighway, - q.highway AS qhighway, - q.maxspeed_class, - st_area (st_intersection (m.way, ST_Union (q.way))) / (3 * st_area (m.way)) AS noise_factor INTO TABLE noise_part4 -FROM - osm_line_buf_50 AS m - INNER JOIN osm_line_noise AS q ON ST_Intersects (m.way, q.way) -WHERE - m.highway IS NOT NULL - AND q.highway IN ('secondary') - AND q.maxspeed_class < 2.1 -GROUP BY - losmid, - lhighway, - m.way, - q.highway, - q.maxspeed_class -ORDER BY - noise_factor DESC; - -SELECT - now(); - -SELECT - m.osm_id losmid, - m.highway lhighway, - q.highway AS qhighway, - q.maxspeed_class, - st_area (st_intersection (m.way, ST_Union (q.way))) / (5 * st_area (m.way)) AS noise_factor INTO TABLE noise_part5 -FROM - osm_line_buf_50 AS m - INNER JOIN osm_line_noise AS q ON ST_Intersects (m.way, q.way) -WHERE - m.highway IS NOT NULL - AND q.highway IN ('secondary') - AND q.maxspeed_class >= 2.1 -GROUP BY - losmid, - lhighway, - m.way, - q.highway, - q.maxspeed_class -ORDER BY - noise_factor DESC; - -SELECT - now(); - --- MERGE -SELECT - losmid, - sum(noise_factor) AS sum_noise_factor INTO TABLE noise_tmp2 FROM ( SELECT - losmid, - noise_factor + * FROM - noise_part0 - UNION - SELECT - losmid, - noise_factor - FROM - noise_part1 - UNION - SELECT - losmid, - noise_factor - FROM - noise_part2 - UNION - SELECT - losmid, - noise_factor - FROM - noise_part3 - UNION - SELECT - losmid, - noise_factor - FROM - noise_part4 - UNION - SELECT - losmid, - noise_factor - FROM - noise_part5) AS abcd -GROUP BY - losmid -ORDER BY - sum_noise_factor DESC; + intermed5 a) b; SELECT now(); --- noise coming from airports -SELECT - name, - st_buffer (way, (643 * st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 3857)) / st_length (ST_Transform (st_makeline (st_startpoint (way), st_centroid (way)), 4326)::geography))) AS way INTO TABLE poly_airport -FROM - polygons -WHERE - aeroway = 'aerodrome' - AND aerodrome = 'international'; - -SELECT - m.osm_id losmid, - st_area (st_intersection (m.way, q.way)) / (st_area (m.way) * 1.5) AS dist_factor INTO TABLE noise_airport -FROM - osm_line_buf_50 AS m - INNER JOIN poly_airport AS q ON ST_intersects (m.way, q.way) -WHERE - m.highway IS NOT NULL - --GROUP BY losmid, m.way -ORDER BY - dist_factor DESC; - --- add car & airport noises -SELECT - losmid, - sum(noise_factor) AS sum_noise_factor INTO TABLE noise_tmp3 -FROM (( - SELECT - losmid, - sum_noise_factor AS noise_factor - FROM - noise_tmp2 AS nois1) - UNION ( - SELECT - losmid, - dist_factor AS noise_factor - FROM - noise_airport AS nois2)) AS nois_sum -GROUP BY - losmid; - --- create the noise classes -SELECT - losmid, - CASE WHEN y.sum_noise_factor < 0.1 THEN - '1' - WHEN y.sum_noise_factor < 0.25 THEN - '2' - WHEN y.sum_noise_factor < 0.4 THEN - '3' - WHEN y.sum_noise_factor < 0.55 THEN - '4' - WHEN y.sum_noise_factor < 0.8 THEN - '5' - ELSE - '6' - END AS noise_class INTO TABLE noise_tags -FROM - noise_tmp3 y -WHERE - y.sum_noise_factor > 0.01; - -SELECT - count(*) -FROM - noise_tags; - -SELECT - noise_class, - count(*) -FROM - noise_tags -GROUP BY - noise_class -ORDER BY - noise_class; - -DROP TABLE noise_tmp2; - -SELECT - now(); - --- create tags for river -SELECT - xid, - sum(water_river_see) AS river_see INTO TABLE river_tmp -FROM ( - SELECT - m.osm_id AS xid, - st_area (st_intersection (m.way, ST_Union (q.way))) / st_area (m.way) AS water_river_see - FROM - osm_line_buf_50 AS m - INNER JOIN osm_poly_buf_120 AS q ON ST_Intersects (m.way, q.way) - WHERE - m.highway IS NOT NULL - -- and st_area(q.way) > 90746 !!! filter on very small surfaces was set above !!!!!!!!! - AND q.natural IN ('water', 'bay', 'beach', 'wetland') - AND (q.water IS NULL - OR q.water NOT IN ('wastewater')) - AND (st_area (ST_Transform (q.way, 4326)::geography) / 1000000) < 5000 - GROUP BY - m.osm_id, - m.way - UNION - SELECT - m.osm_id AS xid, - st_area (st_intersection (m.way, ST_Union (q.way))) / st_area (m.way) AS water_river_see - FROM - osm_line_buf_50 AS m - INNER JOIN osm_poly_coastline_buf_100 AS q ON ST_Intersects (m.way, q.way) - WHERE - m.highway IS NOT NULL - -- and st_area(q.way) > 90746 !!! filter on very small surfaces was set above !!!!!!!!! - GROUP BY - m.osm_id, - m.way - UNION - SELECT - m.osm_id AS xid, - st_area (st_intersection (m.way, ST_Union (q.way))) / st_area (m.way) AS water_river_see - FROM - osm_line_buf_50 AS m - INNER JOIN osm_line_water AS q ON ST_Intersects (m.way, q.way) - WHERE - m.highway IS NOT NULL - AND (st_area (ST_Transform (q.way, 4326)::geography) / 1000000) < 5000 - GROUP BY - m.osm_id, - m.way) AS abcd -GROUP BY - xid -ORDER BY - river_see DESC; - -SELECT - y.xid losmid, - CASE WHEN y.river_see < 0.17 THEN - '1' - WHEN y.river_see < 0.35 THEN - '2' - WHEN y.river_see < 0.57 THEN - '3' - WHEN y.river_see < 0.80 THEN - '4' - WHEN y.river_see < 0.95 THEN - '5' - ELSE - '6' - END AS river_class INTO TABLE river_tags -FROM - river_tmp y -WHERE - y.river_see > 0.05; - -SELECT - count(*) -FROM - river_tags; - -SELECT - river_class, - count(*) -FROM - river_tags -GROUP BY - river_class -ORDER BY - river_class; - -SELECT - now(); - --- create tags for forest -SELECT - m.osm_id, - m.highway, - st_area (st_intersection (m.way, ST_Union (q.way))) / st_area (m.way) AS green_factor INTO TABLE forest_tmp -FROM - osm_line_buf_50 AS m - INNER JOIN osm_poly_no_buf AS q ON ST_Intersects (m.way, q.way) -WHERE - m.highway IS NOT NULL - AND ((q.landuse IN ('forest', 'allotments', 'flowerbed', 'orchard', 'vineyard', 'recreation_ground', 'village_green')) - OR q.leisure IN ('garden', 'park', 'nature_reserve')) - AND (st_area (ST_Transform (q.way, 4326)::geography) / 1000000) < 5000 -GROUP BY - m.osm_id, - m.highway, - m.way -ORDER BY - green_factor DESC; - --- -SELECT - y.osm_id losmid, - CASE WHEN y.green_factor < 0.1 THEN - NULL - WHEN y.green_factor < 0.2 THEN - '1' - WHEN y.green_factor < 0.4 THEN - '2' - WHEN y.green_factor < 0.6 THEN - '3' - WHEN y.green_factor < 0.8 THEN - '4' - WHEN y.green_factor < 0.98 THEN - '5' - ELSE - '6' - END AS forest_class INTO TABLE forest_tags -FROM - forest_tmp y -WHERE - y.green_factor > 0.1; - -SELECT - count(*) -FROM - forest_tags; - -SELECT - forest_class, - count(*) -FROM - forest_tags -GROUP BY - forest_class -ORDER BY - forest_class; - -SELECT - now(); - --- create "town" tags --- get the highways within the town -SELECT - m.osm_id losmid, - m.highway lhighway, - CASE WHEN q.population::decimal > '2000000' THEN - 1 - WHEN q.population::decimal > '1000000' THEN - 0.8 - WHEN q.population::decimal > '400000' THEN - 0.6 - WHEN q.population::decimal > '150000' THEN - 0.4 - WHEN q.population::decimal > '80000' THEN - 0.2 - ELSE - 0.1 - END AS town_factor INTO TABLE town_tmp -FROM - osm_line_buf_50 AS m - --INNER JOIN cities_all AS q ON ST_Intersects(m.way, q.way) - INNER JOIN cities_all AS q ON ST_Within (m.way, q.way) -WHERE - m.highway IS NOT NULL - AND q.population > '50000' -ORDER BY - town_factor DESC; - --- -SELECT - losmid, - CASE WHEN y.town_factor = 0.1 THEN - '1' - WHEN y.town_factor = 0.2 THEN - '2' - WHEN y.town_factor = 0.4 THEN - '3' - WHEN y.town_factor = 0.6 THEN - '4' - WHEN y.town_factor = 0.8 THEN - '5' - ELSE - '6' - END AS town_class INTO TABLE town_tags -FROM ( - SELECT - losmid, - max(town_factor) AS town_factor - FROM - town_tmp y - GROUP BY - losmid) y; - -SELECT - count(*) -FROM - town_tags; - -SELECT - town_class, - count(*) -FROM - town_tags -GROUP BY - town_class -ORDER BY - town_class; - --- --- subtract the ways from town with a green tag (because administrative surface are sometimes too large) --- -DELETE FROM town_tags -WHERE losmid IN ( - SELECT - losmid - FROM - forest_tags - WHERE - forest_class NOT IN ('1')); - -DELETE FROM town_tags -WHERE losmid IN ( - SELECT - losmid - FROM - river_tags - WHERE - river_class NOT IN ('1')); - -SELECT - count(*) -FROM - town_tags; - -SELECT - town_class, - count(*) -FROM - town_tags -GROUP BY - town_class -ORDER BY - town_class; - -SELECT - now(); +ANALYZE cities_all; ------------------------------------------- -- create tags for TRAFFIC @@ -1035,7 +1394,6 @@ FROM INNER JOIN cities_all AS q ON ST_DWithin (m.way0, q.way0, ((3215 * q.merca_coef) + ((64300 * q.merca_coef) * q.population / (q.population + 10000)))) WHERE m.highway IS NOT NULL - --and m.highway in ('primary','primary_link','secondary', 'secondary_link', 'tertiary') AND q.population > 200 GROUP BY m.osm_id, @@ -1047,8 +1405,10 @@ ORDER BY SELECT now(); +ANALYZE traffic_tmp; + -- prepare some special tables --- the intersections motorway_link with primary/secondary/tertiary deliver the motorway accesses... +-- the intersections motorway_link with primary/secondary/tertiary deliver the motorway acccesses.... SELECT * INTO TABLE lines_link FROM @@ -1086,6 +1446,8 @@ CREATE INDEX motorway_access_idx3 ON public.motorway_access USING gist (way3) WI SELECT now(); +ANALYZE motorway_access; + -- find out all the primary/secondary/tertiary within 1000 m and 2000 m from a motorway access SELECT now(); @@ -1109,7 +1471,7 @@ SELECT SELECT m.osm_id losmid, - sum(st_length (q.way) / (6430 * merca_coef)) motorway_factor INTO TABLE motorway_access_2000 + sum(st_length (q.way) / (6430 * q.merca_coef)) motorway_factor INTO TABLE motorway_access_2000 FROM lines AS m INNER JOIN motorway_access AS q ON ST_Intersects (m.way, q.way3) @@ -1124,6 +1486,8 @@ ORDER BY SELECT now(); +ANALYZE motorway_access_2000; + -- -- special regions: mountain_range with "peaks" ==> few highways ==> higher traffic !!! -- calculate the "peak_density" @@ -1139,6 +1503,7 @@ FROM INNER JOIN peak AS q ON ST_Intersects (m.way2, q.way) WHERE (q.ele ~ '^[0-9\.]+$') AND q.ele::decimal > 400 + -- where (q.ele not ~ '^\d+(\.\d+)?$') and q.ele :: decimal > 400 GROUP BY m.osm_id, m.way @@ -1164,17 +1529,21 @@ FROM WHERE (landuse IN ('industrial', 'retail')) OR (aeroway = 'aerodrome' AND aerodrome = 'international') - --where landuse in ('industrial', 'retail') - --where landuse in ('industrial') AND (plant_method IS NULL OR plant_method NOT IN ('photovoltaic')) AND (plant_source IS NULL OR plant_source NOT IN ('solar', 'wind')); +SELECT + now(); + +ANALYZE poly_industri; + SELECT name, way, ST_Centroid (way) way0, + ST_Buffer (way, 12860 * merca_coef) AS way2, st_area (way) * power(50 / (32.15 * merca_coef), 2) areaReal, merca_coef INTO industri FROM @@ -1197,7 +1566,7 @@ SELECT END AS industrial_factor INTO industri_tmp FROM primsecter15k AS m - INNER JOIN industri AS q ON ST_dwithin (m.way0, q.way0, (12860 * q.merca_coef)) + INNER JOIN industri AS q ON ST_intersects (m.way0, q.way2) GROUP BY m.osm_id, m.highway, @@ -1363,7 +1732,7 @@ GROUP BY SELECT now(); --- Do not apply the positive effect of "motorway density" in proximity of motorway accesses!!!! +-- Do not apply the positiv effect of "motorway density" in proximity of motorway accesses!!!! UPDATE except_all SET @@ -1375,11 +1744,11 @@ WHERE FROM motorway_access_2000); --- quite direct at motorway accesses set a negative effect !!!! +-- quite direct at motorway accesses set a negativ effect !!!! UPDATE except_all SET - motorway_factor = - 15 + motorway_factor = -15 WHERE losmid IN ( SELECT @@ -1427,6 +1796,120 @@ GROUP BY ORDER BY traffic_class; +-- create town tags................. +-- create "town" tags +-- get the highways within the town +SELECT + m.osm_id losmid, + m.highway lhighway, + CASE WHEN q.population::decimal > '2000000' THEN + 1 + WHEN q.population::decimal > '1000000' THEN + 0.8 + WHEN q.population::decimal > '400000' THEN + 0.6 + WHEN q.population::decimal > '150000' THEN + 0.4 + WHEN q.population::decimal > '80000' THEN + 0.2 + ELSE + 0.1 + END AS town_factor INTO TABLE town_tmp +FROM + lines AS m + INNER JOIN cities_all AS q ON ST_Within (m.way, q.way) +WHERE + m.highway IS NOT NULL + AND q.population > '50000' +ORDER BY + town_factor DESC; + +SELECT + now(); + +ANALYSE town_tmp; + +-- +SELECT + losmid::bigint, + CASE WHEN y.town_factor = 0.1 THEN + '1' + WHEN y.town_factor = 0.2 THEN + '2' + WHEN y.town_factor = 0.4 THEN + '3' + WHEN y.town_factor = 0.6 THEN + '4' + WHEN y.town_factor = 0.8 THEN + '5' + ELSE + '6' + END AS town_class INTO TABLE town_tags +FROM ( + SELECT + losmid, + max(town_factor) AS town_factor + FROM + town_tmp y + GROUP BY + losmid) y; + +ANALYSE town_tags; + +SELECT + count(*) +FROM + town_tags; + +SELECT + town_class, + count(*) +FROM + town_tags +GROUP BY + town_class +ORDER BY + town_class; + +-- +-- substract the ways from town with a green tag (because administrative surface are some times too large) +-- +DELETE FROM town_tags +WHERE losmid IN ( + SELECT + losmid + FROM + forest_tags + WHERE + forest_class NOT IN ('1')); + +DELETE FROM town_tags +WHERE losmid IN ( + SELECT + losmid + FROM + river_tags + WHERE + river_class NOT IN ('1')); + +SELECT + count(*) +FROM + town_tags; + +SELECT + town_class, + count(*) +FROM + town_tags +GROUP BY + town_class +ORDER BY + town_class; + +SELECT + now(); + -- -- put all tags together in 1 table (1 "direct" access per way in mapcreator) -- @@ -1452,7 +1935,7 @@ ORDER BY CREATE INDEX all_tags_ind ON all_tags (losmid, noise_class, river_class, forest_class, town_class, traffic_class) WITH (fillfactor = '100'); -ANALYSE; +ANALYSE all_tags; SELECT now(); diff --git a/misc/scripts/mapcreation/brouter_cfg.lua b/misc/scripts/mapcreation/brouter_cfg.lua index 07604f6..6998a69 100644 --- a/misc/scripts/mapcreation/brouter_cfg.lua +++ b/misc/scripts/mapcreation/brouter_cfg.lua @@ -18,6 +18,7 @@ tables.lines = osm2pgsql.define_way_table('lines', { { column = 'waterway', type = 'text' }, { column = 'natural', type = 'text' }, { column = 'width', type = 'text' }, + { column = 'oneway', type = 'text' }, { column = 'way', type = 'linestring', projection = srid, not_null = true }, }) @@ -43,6 +44,7 @@ tables.polygons = osm2pgsql.define_area_table('polygons', { tables.cities = osm2pgsql.define_node_table('cities', { { column = 'name', type = 'text' }, + { column = 'name_en', type = 'text' }, { column = 'place', type = 'text' }, { column = 'admin_level', type = 'text' }, { column = 'osm_id', type = 'text' }, @@ -56,6 +58,7 @@ tables.cities_rel = osm2pgsql.define_relation_table('cities_rel', { { column = 'admin_level', type = 'text' }, { column = 'boundary', type = 'text' }, { column = 'name', type = 'text' }, + { column = 'name_en', type = 'text' }, { column = 'place', type = 'text' }, { column = 'osm_id', type = 'text' }, { column = 'population', type = 'text' }, @@ -114,10 +117,11 @@ end function osm2pgsql.process_node(object) - if (object.tags.place == 'city' or object.tags.place == 'town' or object.tags.place == 'municipality') and has_area_tags(object.tags) then +if (object.tags.place == 'city' or object.tags.place == 'town' or object.tags.place == 'village' or object.tags.place == 'municipality') and has_area_tags(object.tags) then tables.cities:insert({ osm_id = object.id, name = object.tags.name, + name_en = object.tags['name:en'], place = object.tags.place, admin_level = object.tags.admin_level, population = object.tags.population, @@ -166,6 +170,7 @@ function osm2pgsql.process_way(object) natural = object.tags.natural, width = object.tags.width, maxspeed = object.tags.maxspeed, + oneway = object.tags.oneway, way = object:as_linestring() }) end @@ -202,6 +207,7 @@ function osm2pgsql.process_relation(object) boundary = object.tags.boundary, admin_level = object.tags.admin_level, name = object.tags.name, + name_en = object.tags['name:en'], place = object.tags.place, population = object.tags.population, osm_id = object.id,