diff --git a/brouter-core/src/main/java/btools/router/FormatCsv.java b/brouter-core/src/main/java/btools/router/FormatCsv.java
new file mode 100644
index 0000000..37b7408
--- /dev/null
+++ b/brouter-core/src/main/java/btools/router/FormatCsv.java
@@ -0,0 +1,43 @@
+package btools.router;
+
+import java.io.BufferedWriter;
+import java.io.StringWriter;
+
+public class FormatCsv extends Formatter {
+
+
+ public FormatCsv(RoutingContext rc) {
+ super(rc);
+ }
+
+ @Override
+ public String format(OsmTrack t) {
+ try {
+ StringWriter sw = new StringWriter();
+ BufferedWriter bw = new BufferedWriter(sw);
+ writeMessages(bw, t);
+ return sw.toString();
+ } catch (Exception ex) {
+ return "Error: " + ex.getMessage();
+ }
+ }
+
+ public void writeMessages(BufferedWriter bw, OsmTrack t) throws Exception {
+ dumpLine(bw, MESSAGES_HEADER);
+ for (String m : t.aggregateMessages()) {
+ dumpLine(bw, m);
+ }
+ if (bw != null)
+ bw.close();
+ }
+
+ private void dumpLine(BufferedWriter bw, String s) throws Exception {
+ if (bw == null) {
+ System.out.println(s);
+ } else {
+ bw.write(s);
+ bw.write("\n");
+ }
+ }
+
+}
diff --git a/brouter-core/src/main/java/btools/router/FormatGpx.java b/brouter-core/src/main/java/btools/router/FormatGpx.java
new file mode 100644
index 0000000..0ed6cc5
--- /dev/null
+++ b/brouter-core/src/main/java/btools/router/FormatGpx.java
@@ -0,0 +1,532 @@
+package btools.router;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.StringWriter;
+import java.util.Map;
+
+import btools.mapaccess.MatchedWaypoint;
+import btools.util.StringUtils;
+
+public class FormatGpx extends Formatter {
+ public FormatGpx(RoutingContext rc) {
+ super(rc);
+ }
+
+ @Override
+ public String format(OsmTrack t) {
+ try {
+ StringWriter sw = new StringWriter(8192);
+ BufferedWriter bw = new BufferedWriter(sw);
+ formatAsGpx(bw, t);
+ bw.close();
+ return sw.toString();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public String formatAsGpx(BufferedWriter sb, OsmTrack t) throws IOException {
+ int turnInstructionMode = t.voiceHints != null ? t.voiceHints.turnInstructionMode : 0;
+
+ sb.append("\n");
+ if (turnInstructionMode != 9) {
+ for (int i = t.messageList.size() - 1; i >= 0; i--) {
+ String message = t.messageList.get(i);
+ if (i < t.messageList.size() - 1)
+ message = "(alt-index " + i + ": " + message + " )";
+ if (message != null)
+ sb.append("\n");
+ }
+ }
+
+ if (turnInstructionMode == 4) { // comment style
+ sb.append("\n");
+ sb.append("\n");
+ sb.append("\n");
+ }
+ sb.append("\n");
+ } else {
+ sb.append(" creator=\"BRouter-" + t.version + "\" version=\"1.1\">\n");
+ }
+ if (turnInstructionMode == 9) {
+ sb.append(" \n");
+ sb.append(" ").append(t.name).append("\n");
+ sb.append(" \n");
+ sb.append(" ").append(t.messageList.get(0)).append("\n");
+ if (t.params != null && t.params.size() > 0) {
+ sb.append(" e : t.params.entrySet()) {
+ if (i++ != 0) sb.append("&");
+ sb.append(e.getKey()).append("=").append(e.getValue());
+ }
+ sb.append("]]>\n");
+ }
+ sb.append(" \n");
+ sb.append(" \n");
+ }
+ if (turnInstructionMode == 3 || turnInstructionMode == 8) { // osmand style, cruiser
+ float lastRteTime = 0;
+
+ sb.append(" \n");
+
+ float rteTime = t.getVoiceHintTime(0);
+ StringBuffer first = new StringBuffer();
+ // define start point
+ {
+ first.append(" \n")
+ .append(" start\n \n");
+ if (rteTime != lastRteTime) { // add timing only if available
+ double ti = rteTime - lastRteTime;
+ first.append(" \n");
+ lastRteTime = rteTime;
+ }
+ first.append(" 0\n \n \n");
+ }
+ if (turnInstructionMode == 8) {
+ if (t.matchedWaypoints.get(0).direct && t.voiceHints.list.get(0).indexInTrack == 0) {
+ // has a voice hint do nothing, voice hint will do
+ } else {
+ sb.append(first.toString());
+ }
+ } else {
+ sb.append(first.toString());
+ }
+
+ for (int i = 0; i < t.voiceHints.list.size(); i++) {
+ VoiceHint hint = t.voiceHints.list.get(i);
+ sb.append(" \n")
+ .append(" ")
+ .append(turnInstructionMode == 3 ? hint.getMessageString() : hint.getCruiserMessageString())
+ .append("\n \n");
+
+ rteTime = t.getVoiceHintTime(i + 1);
+
+ if (rteTime != lastRteTime) { // add timing only if available
+ double ti = rteTime - lastRteTime;
+ sb.append(" \n");
+ lastRteTime = rteTime;
+ }
+ sb.append(" ")
+ .append(turnInstructionMode == 3 ? hint.getCommandString() : hint.getCruiserCommandString())
+ .append("\n ").append("" + (int) hint.angle)
+ .append("\n ").append("" + hint.indexInTrack).append("\n \n \n");
+ }
+ sb.append(" \n")
+ .append(" destination\n \n");
+ sb.append(" \n");
+ sb.append(" ").append("" + (t.nodes.size() - 1)).append("\n \n \n");
+
+ sb.append("\n");
+ }
+
+ if (turnInstructionMode == 7) { // old locus style
+ float lastRteTime = t.getVoiceHintTime(0);
+
+ for (int i = 0; i < t.voiceHints.list.size(); i++) {
+ VoiceHint hint = t.voiceHints.list.get(i);
+ sb.append(" ")
+ .append(hint.selev == Short.MIN_VALUE ? "" : "" + (hint.selev / 4.) + "")
+ .append("").append(hint.getMessageString()).append("")
+ .append("").append("" + hint.distanceToNext).append("");
+ float rteTime = t.getVoiceHintTime(i + 1);
+ if (rteTime != lastRteTime) { // add timing only if available
+ double ti = rteTime - lastRteTime;
+ double speed = hint.distanceToNext / ti;
+ sb.append("").append("" + ti).append("")
+ .append("").append("" + speed).append("");
+ lastRteTime = rteTime;
+ }
+ sb.append("").append("" + hint.getLocusAction()).append("")
+ .append("\n");
+ }
+ }
+ if (turnInstructionMode == 5) { // gpsies style
+ for (VoiceHint hint : t.voiceHints.list) {
+ sb.append(" ")
+ .append("").append(hint.getMessageString()).append("")
+ .append("").append(hint.getSymbolString().toLowerCase()).append("")
+ .append("").append(hint.getSymbolString()).append("")
+ .append("\n");
+ }
+ }
+
+ if (turnInstructionMode == 6) { // orux style
+ for (VoiceHint hint : t.voiceHints.list) {
+ sb.append(" ")
+ .append(hint.selev == Short.MIN_VALUE ? "" : "" + (hint.selev / 4.) + "")
+ .append("\n" +
+ " \n" +
+ " ").append("" + hint.getOruxAction())
+ .append("\n" +
+ " \n" +
+ " \n" +
+ " \n");
+ }
+ }
+
+ for (int i = 0; i <= t.pois.size() - 1; i++) {
+ OsmNodeNamed poi = t.pois.get(i);
+ sb.append(" \n")
+ .append(" ").append(StringUtils.escapeXml10(poi.name)).append("\n")
+ .append(" \n");
+ }
+
+ 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");
+ } else if (i == t.matchedWaypoints.size() - 1) {
+ sb.append(" to\n");
+ } else {
+ sb.append(" via\n");
+ }
+ sb.append(" \n");
+ }
+ }
+ sb.append(" \n");
+ if (turnInstructionMode == 9
+ || turnInstructionMode == 2
+ || turnInstructionMode == 8
+ || turnInstructionMode == 4) { // Locus, comment, cruise, brouter style
+ sb.append(" ").append(t.name).append("\n");
+ sb.append(" ").append(t.voiceHints.getTransportMode()).append("\n");
+ } else {
+ sb.append(" ").append(t.name).append("\n");
+ }
+
+ if (turnInstructionMode == 7) {
+ sb.append(" \n");
+ sb.append(" ").append("" + t.voiceHints.getLocusRouteType()).append("\n");
+ sb.append(" 1\n");
+ sb.append(" \n");
+ }
+
+
+ // all points
+ sb.append(" \n");
+ String lastway = "";
+ boolean bNextDirect = false;
+ OsmPathElement nn = null;
+ String aSpeed;
+
+ for (int idx = 0; idx < t.nodes.size(); idx++) {
+ OsmPathElement n = t.nodes.get(idx);
+ String sele = n.getSElev() == Short.MIN_VALUE ? "" : "" + n.getElev() + "";
+ VoiceHint hint = t.getVoiceHint(idx);
+ MatchedWaypoint mwpt = t.getMatchedWaypoint(idx);
+
+ if (t.showTime) {
+ sele += "";
+ }
+ if (turnInstructionMode == 8) {
+ if (mwpt != null &&
+ !mwpt.name.startsWith("via") && !mwpt.name.startsWith("from") && !mwpt.name.startsWith("to")) {
+ sele += "" + mwpt.name + "";
+ }
+ }
+ boolean bNeedHeader = false;
+ if (turnInstructionMode == 9) { // trkpt/sym style
+
+ if (hint != null) {
+
+ if (mwpt != null &&
+ !mwpt.name.startsWith("via") && !mwpt.name.startsWith("from") && !mwpt.name.startsWith("to")) {
+ sele += "" + mwpt.name + "";
+ }
+ sele += "" + hint.getCruiserMessageString() + "";
+ sele += "" + hint.getCommandString(hint.cmd) + "";
+ if (mwpt != null) {
+ sele += "Via";
+ }
+ sele += "";
+ if (t.showspeed) {
+ double speed = 0;
+ if (nn != null) {
+ int dist = n.calcDistance(nn);
+ float dt = n.getTime() - nn.getTime();
+ if (dt != 0.f) {
+ speed = ((3.6f * dist) / dt + 0.5);
+ }
+ }
+ sele += "" + (((int) (speed * 10)) / 10.f) + "";
+ }
+
+ sele += "" + hint.getCommandString() + ";" + (int) (hint.distanceToNext) + "," + hint.formatGeometry() + "";
+ if (n.message != null && n.message.wayKeyValues != null && !n.message.wayKeyValues.equals(lastway)) {
+ sele += "" + n.message.wayKeyValues + "";
+ lastway = n.message.wayKeyValues;
+ }
+ if (n.message != null && n.message.nodeKeyValues != null) {
+ sele += "" + n.message.nodeKeyValues + "";
+ }
+ sele += "";
+
+ }
+ if (idx == 0 && hint == null) {
+ if (mwpt != null && mwpt.direct) {
+ sele += "beeline";
+ } else {
+ sele += "start";
+ }
+ sele += "Via";
+
+ } else if (idx == t.nodes.size() - 1 && hint == null) {
+
+ sele += "end";
+ sele += "Via";
+
+ } else {
+ if (mwpt != null && hint == null) {
+ if (mwpt.direct) {
+ // bNextDirect = true;
+ sele += "beeline";
+ } else {
+ sele += "" + mwpt.name + "";
+ }
+ sele += "Via";
+ bNextDirect = false;
+ }
+ }
+
+
+ if (hint == null) {
+ bNeedHeader = (t.showspeed || (n.message != null && n.message.wayKeyValues != null && !n.message.wayKeyValues.equals(lastway))) ||
+ (n.message != null && n.message.nodeKeyValues != null);
+ if (bNeedHeader) {
+ sele += "";
+ if (t.showspeed) {
+ double speed = 0;
+ if (nn != null) {
+ int dist = n.calcDistance(nn);
+ float dt = n.getTime() - nn.getTime();
+ if (dt != 0.f) {
+ speed = ((3.6f * dist) / dt + 0.5);
+ }
+ }
+ sele += "" + (((int) (speed * 10)) / 10.f) + "";
+ }
+ if (n.message != null && n.message.wayKeyValues != null && !n.message.wayKeyValues.equals(lastway)) {
+ sele += "" + n.message.wayKeyValues + "";
+ lastway = n.message.wayKeyValues;
+ }
+ if (n.message != null && n.message.nodeKeyValues != null) {
+ sele += "" + n.message.nodeKeyValues + "";
+ }
+ sele += "";
+ }
+ }
+ }
+
+ if (turnInstructionMode == 2) { // locus style new
+ if (hint != null) {
+ if (mwpt != null) {
+ if (!mwpt.name.startsWith("via") && !mwpt.name.startsWith("from") && !mwpt.name.startsWith("to")) {
+ sele += "" + mwpt.name + "";
+ }
+ if (mwpt.direct && bNextDirect) {
+ sele += "" + hint.getLocusSymbolString() + "pass_placeShaping";
+ // bNextDirect = false;
+ } else if (mwpt.direct) {
+ if (idx == 0)
+ sele += "pass_placeVia";
+ else
+ sele += "pass_placeShaping";
+ bNextDirect = true;
+ } else if (bNextDirect) {
+ sele += "beeline" + hint.getLocusSymbolString() + "Shaping";
+ bNextDirect = false;
+ } else {
+ sele += "" + hint.getLocusSymbolString() + "Via";
+ }
+ } else {
+ sele += "" + hint.getLocusSymbolString() + "";
+ }
+ } else {
+ if (idx == 0 && hint == null) {
+
+ int pos = sele.indexOf("" + mwpt.name + "";
+ if (mwpt != null && mwpt.direct) {
+ bNextDirect = true;
+ }
+ sele += "pass_place";
+ sele += "Via";
+
+ } else if (idx == t.nodes.size() - 1 && hint == null) {
+
+ int pos = sele.indexOf("" + mwpt.name + "";
+ if (bNextDirect) {
+ sele += "beeline";
+ }
+ sele += "pass_place";
+ sele += "Via";
+
+ } else {
+ if (mwpt != null) {
+ if (!mwpt.name.startsWith("via") && !mwpt.name.startsWith("from") && !mwpt.name.startsWith("to")) {
+ sele += "" + mwpt.name + "";
+ }
+ if (mwpt.direct && bNextDirect) {
+ sele += "beelinepass_placeShaping";
+ } else if (mwpt.direct) {
+ if (idx == 0)
+ sele += "pass_placeVia";
+ else
+ sele += "pass_placeShaping";
+ bNextDirect = true;
+ } else if (bNextDirect) {
+ sele += "beelinepass_placeShaping";
+ bNextDirect = false;
+ } else if (mwpt.name.startsWith("via") ||
+ mwpt.name.startsWith("from") ||
+ mwpt.name.startsWith("to")) {
+ if (bNextDirect) {
+ sele += "beelinepass_placeShaping";
+ } else {
+ sele += "pass_placeVia";
+ }
+ bNextDirect = false;
+ } else {
+ sele += "" + mwpt.name + "";
+ sele += "pass_placeVia";
+ }
+ }
+ }
+ }
+ }
+ sb.append(" ").append(sele).append("\n");
+
+ nn = n;
+ }
+
+ sb.append(" \n");
+ sb.append(" \n");
+ sb.append("\n");
+
+ return sb.toString();
+ }
+
+ public String formatAsWaypoint(OsmNodeNamed n) {
+ try {
+ StringWriter sw = new StringWriter(8192);
+ BufferedWriter bw = new BufferedWriter(sw);
+ formatGpxHeader(bw);
+ formatWaypointGpx(bw, n);
+ formatGpxFooter(bw);
+ bw.close();
+ sw.close();
+ return sw.toString();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void formatGpxHeader(BufferedWriter sb) throws IOException {
+ sb.append("\n");
+ sb.append("\n");
+ }
+
+ public void formatGpxFooter(BufferedWriter sb) throws IOException {
+ sb.append("\n");
+ }
+
+ public void formatWaypointGpx(BufferedWriter sb, OsmNodeNamed n) throws IOException {
+ sb.append(" ");
+ if (n.getSElev() != Short.MIN_VALUE) {
+ sb.append("").append("" + n.getElev()).append("");
+ }
+ if (n.name != null) {
+ sb.append("").append(StringUtils.escapeXml10(n.name)).append("");
+ }
+ if (n.nodeDescription != null && rc != null) {
+ sb.append("").append(rc.expctxWay.getKeyValueDescription(false, n.nodeDescription)).append("");
+ }
+ sb.append("\n");
+ }
+
+ public static String getWaypoint(int ilon, int ilat, String name, String desc) {
+ return "" + name + "" + (desc != null ? "" + desc + "" : "") + "";
+ }
+
+ public OsmTrack read(String filename) throws Exception {
+ File f = new File(filename);
+ if (!f.exists()) {
+ return null;
+ }
+ OsmTrack track = new OsmTrack();
+ BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(f)));
+
+ for (; ; ) {
+ String line = br.readLine();
+ if (line == null)
+ break;
+
+ int idx0 = line.indexOf("= 0) {
+ idx0 = line.indexOf(" lon=\"");
+ idx0 += 6;
+ int idx1 = line.indexOf('"', idx0);
+ int ilon = (int) ((Double.parseDouble(line.substring(idx0, idx1)) + 180.) * 1000000. + 0.5);
+ int idx2 = line.indexOf(" lat=\"");
+ if (idx2 < 0)
+ continue;
+ idx2 += 6;
+ int idx3 = line.indexOf('"', idx2);
+ int ilat = (int) ((Double.parseDouble(line.substring(idx2, idx3)) + 90.) * 1000000. + 0.5);
+ track.nodes.add(OsmPathElement.create(ilon, ilat, (short) 0, null, false));
+ }
+ }
+ br.close();
+ return track;
+ }
+
+}
diff --git a/brouter-core/src/main/java/btools/router/FormatJson.java b/brouter-core/src/main/java/btools/router/FormatJson.java
new file mode 100644
index 0000000..a2c5b7a
--- /dev/null
+++ b/brouter-core/src/main/java/btools/router/FormatJson.java
@@ -0,0 +1,246 @@
+package btools.router;
+
+import java.io.BufferedWriter;
+import java.io.StringWriter;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.List;
+import java.util.Locale;
+
+import btools.mapaccess.MatchedWaypoint;
+import btools.util.StringUtils;
+
+public class FormatJson extends Formatter {
+
+ public FormatJson(RoutingContext rc) {
+ super(rc);
+ }
+
+ @Override
+ public String format(OsmTrack t) {
+ int turnInstructionMode = t.voiceHints != null ? t.voiceHints.turnInstructionMode : 0;
+
+ StringBuilder sb = new StringBuilder(8192);
+
+ sb.append("{\n");
+ sb.append(" \"type\": \"FeatureCollection\",\n");
+ sb.append(" \"features\": [\n");
+ sb.append(" {\n");
+ sb.append(" \"type\": \"Feature\",\n");
+ sb.append(" \"properties\": {\n");
+ sb.append(" \"creator\": \"BRouter-" + t.version + "\",\n");
+ sb.append(" \"name\": \"").append(t.name).append("\",\n");
+ sb.append(" \"track-length\": \"").append(t.distance).append("\",\n");
+ sb.append(" \"filtered ascend\": \"").append(t.ascend).append("\",\n");
+ sb.append(" \"plain-ascend\": \"").append(t.plainAscend).append("\",\n");
+ sb.append(" \"total-time\": \"").append(t.getTotalSeconds()).append("\",\n");
+ sb.append(" \"total-energy\": \"").append(t.energy).append("\",\n");
+ sb.append(" \"cost\": \"").append(t.cost).append("\",\n");
+ if (t.voiceHints != null && !t.voiceHints.list.isEmpty()) {
+ sb.append(" \"voicehints\": [\n");
+ for (VoiceHint hint : t.voiceHints.list) {
+ sb.append(" [");
+ sb.append(hint.indexInTrack);
+ sb.append(',').append(hint.getJsonCommandIndex());
+ sb.append(',').append(hint.getExitNumber());
+ sb.append(',').append(hint.distanceToNext);
+ sb.append(',').append((int) hint.angle);
+
+ // not always include geometry because longer and only needed for comment style
+ if (turnInstructionMode == 4) { // comment style
+ sb.append(",\"").append(hint.formatGeometry()).append("\"");
+ }
+
+ sb.append("],\n");
+ }
+ sb.deleteCharAt(sb.lastIndexOf(","));
+ sb.append(" ],\n");
+ }
+ if (t.showSpeedProfile) { // set in profile
+ List sp = t.aggregateSpeedProfile();
+ if (sp.size() > 0) {
+ sb.append(" \"speedprofile\": [\n");
+ for (int i = sp.size() - 1; i >= 0; i--) {
+ sb.append(" [").append(sp.get(i)).append(i > 0 ? "],\n" : "]\n");
+ }
+ sb.append(" ],\n");
+ }
+ }
+ // ... traditional message list
+ {
+ sb.append(" \"messages\": [\n");
+ sb.append(" [\"").append(MESSAGES_HEADER.replaceAll("\t", "\", \"")).append("\"],\n");
+ for (String m : t.aggregateMessages()) {
+ sb.append(" [\"").append(m.replaceAll("\t", "\", \"")).append("\"],\n");
+ }
+ sb.deleteCharAt(sb.lastIndexOf(","));
+ sb.append(" ],\n");
+ }
+
+ if (t.getTotalSeconds() > 0) {
+ sb.append(" \"times\": [");
+ DecimalFormat decimalFormat = (DecimalFormat) NumberFormat.getInstance(Locale.ENGLISH);
+ decimalFormat.applyPattern("0.###");
+ for (OsmPathElement n : t.nodes) {
+ sb.append(decimalFormat.format(n.getTime())).append(",");
+ }
+ sb.deleteCharAt(sb.lastIndexOf(","));
+ sb.append("]\n");
+ } else {
+ sb.deleteCharAt(sb.lastIndexOf(","));
+ }
+
+ sb.append(" },\n");
+
+ if (t.iternity != null) {
+ sb.append(" \"iternity\": [\n");
+ for (String s : t.iternity) {
+ sb.append(" \"").append(s).append("\",\n");
+ }
+ sb.deleteCharAt(sb.lastIndexOf(","));
+ sb.append(" ],\n");
+ }
+ sb.append(" \"geometry\": {\n");
+ sb.append(" \"type\": \"LineString\",\n");
+ sb.append(" \"coordinates\": [\n");
+
+ OsmPathElement nn = null;
+ for (OsmPathElement n : t.nodes) {
+ String sele = n.getSElev() == Short.MIN_VALUE ? "" : ", " + n.getElev();
+ if (t.showspeed) { // hack: show speed instead of elevation
+ double speed = 0;
+ if (nn != null) {
+ int dist = n.calcDistance(nn);
+ float dt = n.getTime() - nn.getTime();
+ if (dt != 0.f) {
+ speed = ((3.6f * dist) / dt + 0.5);
+ }
+ }
+ sele = ", " + (((int) (speed * 10)) / 10.f);
+ }
+ sb.append(" [").append(formatILon(n.getILon())).append(", ").append(formatILat(n.getILat()))
+ .append(sele).append("],\n");
+ nn = n;
+ }
+ sb.deleteCharAt(sb.lastIndexOf(","));
+
+ sb.append(" ]\n");
+ sb.append(" }\n");
+ if (t.exportWaypoints || !t.pois.isEmpty()) {
+ sb.append(" },\n");
+ for (int i = 0; i <= t.pois.size() - 1; i++) {
+ OsmNodeNamed poi = t.pois.get(i);
+ addFeature(sb, "poi", poi.name, poi.ilat, poi.ilon);
+ if (i < t.matchedWaypoints.size() - 1) {
+ sb.append(",");
+ }
+ sb.append(" \n");
+ }
+ if (t.exportWaypoints) {
+ for (int i = 0; i <= t.matchedWaypoints.size() - 1; i++) {
+ String type;
+ if (i == 0) {
+ type = "from";
+ } else if (i == t.matchedWaypoints.size() - 1) {
+ type = "to";
+ } else {
+ type = "via";
+ }
+
+ MatchedWaypoint wp = t.matchedWaypoints.get(i);
+ addFeature(sb, type, wp.name, wp.waypoint.ilat, wp.waypoint.ilon);
+ if (i < t.matchedWaypoints.size() - 1) {
+ sb.append(",");
+ }
+ sb.append(" \n");
+ }
+ }
+ } else {
+ sb.append(" }\n");
+ }
+ sb.append(" ]\n");
+ sb.append("}\n");
+
+ return sb.toString();
+ }
+
+ private void addFeature(StringBuilder sb, String type, String name, int ilat, int ilon) {
+ sb.append(" {\n");
+ sb.append(" \"type\": \"Feature\",\n");
+ sb.append(" \"properties\": {\n");
+ sb.append(" \"name\": \"" + StringUtils.escapeJson(name) + "\",\n");
+ sb.append(" \"type\": \"" + type + "\"\n");
+ sb.append(" },\n");
+ sb.append(" \"geometry\": {\n");
+ sb.append(" \"type\": \"Point\",\n");
+ sb.append(" \"coordinates\": [\n");
+ sb.append(" " + formatILon(ilon) + ",\n");
+ sb.append(" " + formatILat(ilat) + "\n");
+ sb.append(" ]\n");
+ sb.append(" }\n");
+ sb.append(" }");
+ }
+
+ public String formatAsWaypoint(OsmNodeNamed n) {
+ try {
+ StringWriter sw = new StringWriter(8192);
+ BufferedWriter bw = new BufferedWriter(sw);
+ addJsonHeader(bw);
+ addJsonFeature(bw, "info", "wpinfo", n.ilon, n.ilat, n.getElev(), (n.nodeDescription != null ? rc.expctxWay.getKeyValueDescription(false, n.nodeDescription) : null));
+ addJsonFooter(bw);
+ bw.close();
+ sw.close();
+ return sw.toString();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void addJsonFeature(BufferedWriter sb, String type, String name, int ilon, int ilat, double elev, String desc) {
+ try {
+ sb.append(" {\n");
+ sb.append(" \"type\": \"Feature\",\n");
+ sb.append(" \"properties\": {\n");
+ sb.append(" \"creator\": \"BRouter-" + OsmTrack.version + "\",\n");
+ sb.append(" \"name\": \"" + StringUtils.escapeJson(name) + "\",\n");
+ sb.append(" \"type\": \"" + type + "\"");
+ if (desc != null) {
+ sb.append(",\n \"message\": \"" + desc + "\"\n");
+ } else {
+ sb.append("\n");
+ }
+ sb.append(" },\n");
+ sb.append(" \"geometry\": {\n");
+ sb.append(" \"type\": \"Point\",\n");
+ sb.append(" \"coordinates\": [\n");
+ sb.append(" " + formatILon(ilon) + ",\n");
+ sb.append(" " + formatILat(ilat) + ",\n");
+ sb.append(" " + elev + "\n");
+ sb.append(" ]\n");
+ sb.append(" }\n");
+ sb.append(" }\n");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static void addJsonHeader(BufferedWriter sb) {
+ try {
+ sb.append("{\n");
+ sb.append(" \"type\": \"FeatureCollection\",\n");
+ sb.append(" \"features\": [\n");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static void addJsonFooter(BufferedWriter sb) {
+ try {
+ sb.append(" ]\n");
+ sb.append("}\n");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/brouter-core/src/main/java/btools/router/FormatKml.java b/brouter-core/src/main/java/btools/router/FormatKml.java
new file mode 100644
index 0000000..5798c5c
--- /dev/null
+++ b/brouter-core/src/main/java/btools/router/FormatKml.java
@@ -0,0 +1,91 @@
+package btools.router;
+
+import java.util.List;
+
+import btools.mapaccess.MatchedWaypoint;
+import btools.util.StringUtils;
+
+public class FormatKml extends Formatter {
+ public FormatKml(RoutingContext rc) {
+ super(rc);
+ }
+
+ @Override
+ public String format(OsmTrack t) {
+ StringBuilder sb = new StringBuilder(8192);
+
+ sb.append("\n");
+
+ sb.append("\n");
+ sb.append(" \n");
+ sb.append(" KML Samples\n");
+ sb.append(" 1\n");
+ sb.append(" 3.497064\n");
+ sb.append(" 872\n");
+ sb.append(" To enable simple instructions add: 'instructions=1' as parameter to the URL\n");
+ sb.append(" \n");
+ sb.append(" Paths\n");
+ sb.append(" 0\n");
+ sb.append(" Examples of paths.\n");
+ sb.append(" \n");
+ sb.append(" Tessellated\n");
+ sb.append(" 0\n");
+ sb.append(" tag has a value of 1, the line will contour to the underlying terrain]]>\n");
+ sb.append(" \n");
+ sb.append(" 1\n");
+ sb.append(" ");
+
+ for (OsmPathElement n : t.nodes) {
+ sb.append(formatILon(n.getILon())).append(",").append(formatILat(n.getILat())).append("\n");
+ }
+
+ sb.append(" \n");
+ sb.append(" \n");
+ sb.append(" \n");
+ sb.append(" \n");
+ if (t.exportWaypoints || !t.pois.isEmpty()) {
+ if (!t.pois.isEmpty()) {
+ sb.append(" \n");
+ sb.append(" poi\n");
+ for (int i = 0; i < t.pois.size(); i++) {
+ OsmNodeNamed poi = t.pois.get(i);
+ createPlaceMark(sb, poi.name, poi.ilat, poi.ilon);
+ }
+ sb.append(" \n");
+ }
+
+ if (t.exportWaypoints) {
+ int size = t.matchedWaypoints.size();
+ createFolder(sb, "start", t.matchedWaypoints.subList(0, 1));
+ if (t.matchedWaypoints.size() > 2) {
+ createFolder(sb, "via", t.matchedWaypoints.subList(1, size - 1));
+ }
+ createFolder(sb, "end", t.matchedWaypoints.subList(size - 1, size));
+ }
+ }
+ sb.append(" \n");
+ sb.append("\n");
+
+ return sb.toString();
+ }
+
+ private void createFolder(StringBuilder sb, String type, List waypoints) {
+ sb.append(" \n");
+ sb.append(" " + type + "\n");
+ for (int i = 0; i < waypoints.size(); i++) {
+ MatchedWaypoint wp = waypoints.get(i);
+ createPlaceMark(sb, wp.name, wp.waypoint.ilat, wp.waypoint.ilon);
+ }
+ sb.append(" \n");
+ }
+
+ private void createPlaceMark(StringBuilder sb, String name, int ilat, int ilon) {
+ sb.append(" \n");
+ sb.append(" " + StringUtils.escapeXml10(name) + "\n");
+ sb.append(" \n");
+ sb.append(" " + formatILon(ilon) + "," + formatILat(ilat) + "\n");
+ sb.append(" \n");
+ sb.append(" \n");
+ }
+
+}
diff --git a/brouter-core/src/main/java/btools/router/Formatter.java b/brouter-core/src/main/java/btools/router/Formatter.java
new file mode 100644
index 0000000..09bdb1d
--- /dev/null
+++ b/brouter-core/src/main/java/btools/router/Formatter.java
@@ -0,0 +1,110 @@
+package btools.router;
+
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+public abstract class Formatter {
+
+ static final String MESSAGES_HEADER = "Longitude\tLatitude\tElevation\tDistance\tCostPerKm\tElevCost\tTurnCost\tNodeCost\tInitialCost\tWayTags\tNodeTags\tTime\tEnergy";
+
+ RoutingContext rc;
+
+ Formatter() {
+ }
+
+ Formatter(RoutingContext rc) {
+ this.rc = rc;
+ }
+
+ /**
+ * writes the track in gpx-format to a file
+ *
+ * @param filename the filename to write to
+ * @param t the track to write
+ */
+ public void write(String filename, OsmTrack t) throws Exception {
+ BufferedWriter bw = new BufferedWriter(new FileWriter(filename));
+ bw.write(format(t));
+ bw.close();
+ }
+
+ public OsmTrack read(String filename) throws Exception {
+ return null;
+ }
+
+ /**
+ * writes the track in a selected output format to a string
+ *
+ * @param t the track to format
+ * @return the formatted string
+ */
+ public abstract String format(OsmTrack t);
+
+
+ static String formatILon(int ilon) {
+ return formatPos(ilon - 180000000);
+ }
+
+ static String formatILat(int ilat) {
+ return formatPos(ilat - 90000000);
+ }
+
+ private static String formatPos(int p) {
+ boolean negative = p < 0;
+ if (negative)
+ p = -p;
+ char[] ac = new char[12];
+ int i = 11;
+ while (p != 0 || i > 3) {
+ ac[i--] = (char) ('0' + (p % 10));
+ p /= 10;
+ if (i == 5)
+ ac[i--] = '.';
+ }
+ if (negative)
+ ac[i--] = '-';
+ return new String(ac, i + 1, 11 - i);
+ }
+
+ public static String getFormattedTime2(int s) {
+ int seconds = (int) (s + 0.5);
+ int hours = seconds / 3600;
+ int minutes = (seconds - hours * 3600) / 60;
+ seconds = seconds - hours * 3600 - minutes * 60;
+ String time = "";
+ if (hours != 0)
+ time = "" + hours + "h ";
+ if (minutes != 0)
+ time = time + minutes + "m ";
+ if (seconds != 0)
+ time = time + seconds + "s";
+ return time;
+ }
+
+ static public String getFormattedEnergy(int energy) {
+ return format1(energy / 3600000.) + "kwh";
+ }
+
+ static private String format1(double n) {
+ String s = "" + (long) (n * 10 + 0.5);
+ int len = s.length();
+ return s.substring(0, len - 1) + "." + s.charAt(len - 1);
+ }
+
+
+ static final String dateformat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
+
+ static public String getFormattedTime3(float time) {
+ SimpleDateFormat TIMESTAMP_FORMAT = new SimpleDateFormat(dateformat, Locale.US);
+ TIMESTAMP_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
+ // yyyy-mm-ddThh:mm:ss.SSSZ
+ Date d = new Date((long) (time * 1000f));
+ return TIMESTAMP_FORMAT.format(d);
+ }
+
+
+}
diff --git a/brouter-core/src/main/java/btools/router/OsmTrack.java b/brouter-core/src/main/java/btools/router/OsmTrack.java
index ac3b51f..9ccff98 100644
--- a/brouter-core/src/main/java/btools/router/OsmTrack.java
+++ b/brouter-core/src/main/java/btools/router/OsmTrack.java
@@ -7,33 +7,20 @@ package btools.router;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.StringWriter;
-import java.text.DecimalFormat;
-import java.text.NumberFormat;
-import java.text.SimpleDateFormat;
import java.util.ArrayList;
-import java.util.Date;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
-import java.util.TimeZone;
import btools.mapaccess.MatchedWaypoint;
import btools.mapaccess.OsmPos;
import btools.util.CompactLongMap;
import btools.util.FrozenLongMap;
-import btools.util.StringUtils;
public final class OsmTrack {
final public static String version = "1.7.3";
@@ -66,7 +53,7 @@ public final class OsmTrack {
private CompactLongMap detourMap;
- private VoiceHintList voiceHints;
+ public VoiceHintList voiceHints;
public String message = null;
public List messageList = null;
@@ -178,7 +165,7 @@ public final class OsmTrack {
nodesMap = new FrozenLongMap<>(nodesMap);
}
- private List aggregateMessages() {
+ public List aggregateMessages() {
ArrayList res = new ArrayList<>();
MessageData current = null;
for (OsmPathElement n : nodes) {
@@ -200,7 +187,7 @@ public final class OsmTrack {
return res;
}
- private List aggregateSpeedProfile() {
+ public List aggregateSpeedProfile() {
ArrayList res = new ArrayList<>();
int vmax = -1;
int vmaxe = -1;
@@ -395,752 +382,9 @@ public final class OsmTrack {
public int plainAscend;
public int cost;
public int energy;
-
- /**
- * writes the track in gpx-format to a file
- *
- * @param filename the filename to write to
- */
- public void writeGpx(String filename) throws Exception {
- BufferedWriter bw = new BufferedWriter(new FileWriter(filename));
- formatAsGpx(bw);
- bw.close();
- }
-
- public String formatAsGpx() {
- try {
- StringWriter sw = new StringWriter(8192);
- BufferedWriter bw = new BufferedWriter(sw);
- formatAsGpx(bw);
- bw.close();
- return sw.toString();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- public String formatAsGpx(BufferedWriter sb) throws IOException {
- int turnInstructionMode = voiceHints != null ? voiceHints.turnInstructionMode : 0;
-
- sb.append("\n");
- if (turnInstructionMode != 9) {
- for (int i = messageList.size() - 1; i >= 0; i--) {
- String message = messageList.get(i);
- if (i < messageList.size() - 1)
- message = "(alt-index " + i + ": " + message + " )";
- if (message != null)
- sb.append("\n");
- }
- }
-
- if (turnInstructionMode == 4) { // comment style
- sb.append("\n");
- sb.append("\n");
- sb.append("\n");
- }
- sb.append("\n");
- } else {
- sb.append(" creator=\"BRouter-" + version + "\" version=\"1.1\">\n");
- }
- if (turnInstructionMode == 9) {
- sb.append(" \n");
- sb.append(" ").append(name).append("\n");
- sb.append(" \n");
- sb.append(" ").append(messageList.get(0)).append("\n");
- if (params != null && params.size() > 0) {
- sb.append(" e : params.entrySet()) {
- if (i++ != 0) sb.append("&");
- sb.append(e.getKey()).append("=").append(e.getValue());
- }
- sb.append("]]>\n");
- }
- sb.append(" \n");
- sb.append(" \n");
- }
- if (turnInstructionMode == 3 || turnInstructionMode == 8) { // osmand style, cruiser
- float lastRteTime = 0;
-
- sb.append(" \n");
-
- float rteTime = getVoiceHintTime(0);
- StringBuffer first = new StringBuffer();
- // define start point
- {
- first.append(" \n")
- .append(" start\n \n");
- if (rteTime != lastRteTime) { // add timing only if available
- double t = rteTime - lastRteTime;
- first.append(" \n");
- lastRteTime = rteTime;
- }
- first.append(" 0\n \n \n");
- }
- if (turnInstructionMode == 8) {
- if (matchedWaypoints.get(0).direct && voiceHints.list.get(0).indexInTrack == 0) {
- // has a voice hint do nothing, voice hint will do
- } else {
- sb.append(first.toString());
- }
- } else {
- sb.append(first.toString());
- }
-
- for (int i = 0; i < voiceHints.list.size(); i++) {
- VoiceHint hint = voiceHints.list.get(i);
- sb.append(" \n")
- .append(" ")
- .append(turnInstructionMode == 3 ? hint.getMessageString() : hint.getCruiserMessageString())
- .append("\n \n");
-
- rteTime = getVoiceHintTime(i + 1);
-
- if (rteTime != lastRteTime) { // add timing only if available
- double t = rteTime - lastRteTime;
- sb.append(" \n");
- lastRteTime = rteTime;
- }
- sb.append(" ")
- .append(turnInstructionMode == 3 ? hint.getCommandString() : hint.getCruiserCommandString())
- .append("\n ").append("" + (int) hint.angle)
- .append("\n ").append("" + hint.indexInTrack).append("\n \n \n");
- }
- sb.append(" \n")
- .append(" destination\n \n");
- sb.append(" \n");
- sb.append(" ").append("" + (nodes.size() - 1)).append("\n \n \n");
-
- sb.append("\n");
- }
-
- if (turnInstructionMode == 7) { // old locus style
- float lastRteTime = getVoiceHintTime(0);
-
- for (int i = 0; i < voiceHints.list.size(); i++) {
- VoiceHint hint = voiceHints.list.get(i);
- sb.append(" ")
- .append(hint.selev == Short.MIN_VALUE ? "" : "" + (hint.selev / 4.) + "")
- .append("").append(hint.getMessageString()).append("")
- .append("").append("" + hint.distanceToNext).append("");
- float rteTime = getVoiceHintTime(i + 1);
- if (rteTime != lastRteTime) { // add timing only if available
- double t = rteTime - lastRteTime;
- double speed = hint.distanceToNext / t;
- sb.append("").append("" + t).append("")
- .append("").append("" + speed).append("");
- lastRteTime = rteTime;
- }
- sb.append("").append("" + hint.getLocusAction()).append("")
- .append("\n");
- }
- }
- if (turnInstructionMode == 5) { // gpsies style
- for (VoiceHint hint : voiceHints.list) {
- sb.append(" ")
- .append("").append(hint.getMessageString()).append("")
- .append("").append(hint.getSymbolString().toLowerCase()).append("")
- .append("").append(hint.getSymbolString()).append("")
- .append("\n");
- }
- }
-
- if (turnInstructionMode == 6) { // orux style
- for (VoiceHint hint : voiceHints.list) {
- sb.append(" ")
- .append(hint.selev == Short.MIN_VALUE ? "" : "" + (hint.selev / 4.) + "")
- .append("\n" +
- " \n" +
- " ").append("" + hint.getOruxAction())
- .append("\n" +
- " \n" +
- " \n" +
- " \n");
- }
- }
-
- for (int i = 0; i <= pois.size() - 1; i++) {
- OsmNodeNamed poi = pois.get(i);
- sb.append(" \n")
- .append(" ").append(StringUtils.escapeXml10(poi.name)).append("\n")
- .append(" \n");
- }
-
- if (exportWaypoints) {
- for (int i = 0; i <= matchedWaypoints.size() - 1; i++) {
- MatchedWaypoint wt = matchedWaypoints.get(i);
- sb.append(" \n")
- .append(" ").append(StringUtils.escapeXml10(wt.name)).append("\n");
- if (i == 0) {
- sb.append(" from\n");
- } else if (i == matchedWaypoints.size() - 1) {
- sb.append(" to\n");
- } else {
- sb.append(" via\n");
- }
- sb.append(" \n");
- }
- }
- sb.append(" \n");
- if (turnInstructionMode == 9
- || turnInstructionMode == 2
- || turnInstructionMode == 8
- || turnInstructionMode == 4) { // Locus, comment, cruise, brouter style
- sb.append(" ").append(name).append("\n");
- sb.append(" ").append(voiceHints.getTransportMode()).append("\n");
- } else {
- sb.append(" ").append(name).append("\n");
- }
-
- if (turnInstructionMode == 7) {
- sb.append(" \n");
- sb.append(" ").append("" + voiceHints.getLocusRouteType()).append("\n");
- sb.append(" 1\n");
- sb.append(" \n");
- }
-
-
- // all points
- sb.append(" \n");
- String lastway = "";
- boolean bNextDirect = false;
- OsmPathElement nn = null;
- String aSpeed;
-
- for (int idx = 0; idx < nodes.size(); idx++) {
- OsmPathElement n = nodes.get(idx);
- String sele = n.getSElev() == Short.MIN_VALUE ? "" : "" + n.getElev() + "";
- VoiceHint hint = getVoiceHint(idx);
- MatchedWaypoint mwpt = getMatchedWaypoint(idx);
-
- if (showTime) {
- sele += "";
- }
- if (turnInstructionMode == 8) {
- if (mwpt != null &&
- !mwpt.name.startsWith("via") && !mwpt.name.startsWith("from") && !mwpt.name.startsWith("to")) {
- sele += "" + mwpt.name + "";
- }
- }
- boolean bNeedHeader = false;
- if (turnInstructionMode == 9) { // trkpt/sym style
-
- if (hint != null) {
-
- if (mwpt != null &&
- !mwpt.name.startsWith("via") && !mwpt.name.startsWith("from") && !mwpt.name.startsWith("to")) {
- sele += "" + mwpt.name + "";
- }
- sele += "" + hint.getCruiserMessageString() + "";
- sele += "" + hint.getCommandString(hint.cmd) + "";
- if (mwpt != null) {
- sele += "Via";
- }
- sele += "";
- if (showspeed) {
- double speed = 0;
- if (nn != null) {
- int dist = n.calcDistance(nn);
- float dt = n.getTime() - nn.getTime();
- if (dt != 0.f) {
- speed = ((3.6f * dist) / dt + 0.5);
- }
- }
- sele += "" + (((int) (speed * 10)) / 10.f) + "";
- }
-
- sele += "" + hint.getCommandString() + ";" + (int) (hint.distanceToNext) + "," + hint.formatGeometry() + "";
- if (n.message != null && n.message.wayKeyValues != null && !n.message.wayKeyValues.equals(lastway)) {
- sele += "" + n.message.wayKeyValues + "";
- lastway = n.message.wayKeyValues;
- }
- if (n.message != null && n.message.nodeKeyValues != null) {
- sele += "" + n.message.nodeKeyValues + "";
- }
- sele += "";
-
- }
- if (idx == 0 && hint == null) {
- if (mwpt != null && mwpt.direct) {
- sele += "beeline";
- } else {
- sele += "start";
- }
- sele += "Via";
-
- } else if (idx == nodes.size() - 1 && hint == null) {
-
- sele += "end";
- sele += "Via";
-
- } else {
- if (mwpt != null && hint == null) {
- if (mwpt.direct) {
- // bNextDirect = true;
- sele += "beeline";
- } else {
- sele += "" + mwpt.name + "";
- }
- sele += "Via";
- bNextDirect = false;
- }
- }
-
-
- if (hint == null) {
- bNeedHeader = (showspeed || (n.message != null && n.message.wayKeyValues != null && !n.message.wayKeyValues.equals(lastway))) ||
- (n.message != null && n.message.nodeKeyValues != null);
- if (bNeedHeader) {
- sele += "";
- if (showspeed) {
- double speed = 0;
- if (nn != null) {
- int dist = n.calcDistance(nn);
- float dt = n.getTime() - nn.getTime();
- if (dt != 0.f) {
- speed = ((3.6f * dist) / dt + 0.5);
- }
- }
- sele += "" + (((int) (speed * 10)) / 10.f) + "";
- }
- if (n.message != null && n.message.wayKeyValues != null && !n.message.wayKeyValues.equals(lastway)) {
- sele += "" + n.message.wayKeyValues + "";
- lastway = n.message.wayKeyValues;
- }
- if (n.message != null && n.message.nodeKeyValues != null) {
- sele += "" + n.message.nodeKeyValues + "";
- }
- sele += "";
- }
- }
- }
-
- if (turnInstructionMode == 2) { // locus style new
- if (hint != null) {
- if (mwpt != null) {
- if (!mwpt.name.startsWith("via") && !mwpt.name.startsWith("from") && !mwpt.name.startsWith("to")) {
- sele += "" + mwpt.name + "";
- }
- if (mwpt.direct && bNextDirect) {
- sele += "" + hint.getLocusSymbolString() + "pass_placeShaping";
- // bNextDirect = false;
- } else if (mwpt.direct) {
- if (idx == 0)
- sele += "pass_placeVia";
- else
- sele += "pass_placeShaping";
- bNextDirect = true;
- } else if (bNextDirect) {
- sele += "beeline" + hint.getLocusSymbolString() + "Shaping";
- bNextDirect = false;
- } else {
- sele += "" + hint.getLocusSymbolString() + "Via";
- }
- } else {
- sele += "" + hint.getLocusSymbolString() + "";
- }
- } else {
- if (idx == 0 && hint == null) {
-
- int pos = sele.indexOf("" + mwpt.name + "";
- if (mwpt != null && mwpt.direct) {
- bNextDirect = true;
- }
- sele += "pass_place";
- sele += "Via";
-
- } else if (idx == nodes.size() - 1 && hint == null) {
-
- int pos = sele.indexOf("" + mwpt.name + "";
- if (bNextDirect) {
- sele += "beeline";
- }
- sele += "pass_place";
- sele += "Via";
-
- } else {
- if (mwpt != null) {
- if (!mwpt.name.startsWith("via") && !mwpt.name.startsWith("from") && !mwpt.name.startsWith("to")) {
- sele += "" + mwpt.name + "";
- }
- if (mwpt.direct && bNextDirect) {
- sele += "beelinepass_placeShaping";
- } else if (mwpt.direct) {
- if (idx == 0)
- sele += "pass_placeVia";
- else
- sele += "pass_placeShaping";
- bNextDirect = true;
- } else if (bNextDirect) {
- sele += "beelinepass_placeShaping";
- bNextDirect = false;
- } else if (mwpt.name.startsWith("via") ||
- mwpt.name.startsWith("from") ||
- mwpt.name.startsWith("to")) {
- if (bNextDirect) {
- sele += "beelinepass_placeShaping";
- } else {
- sele += "pass_placeVia";
- }
- bNextDirect = false;
- } else {
- sele += "" + mwpt.name + "";
- sele += "pass_placeVia";
- }
- }
- }
- }
- }
- sb.append(" ").append(sele).append("\n");
-
- nn = n;
- }
-
- sb.append(" \n");
- sb.append(" \n");
- sb.append("\n");
-
- return sb.toString();
- }
-
- static public String formatAsGpxWaypoint(OsmNodeNamed n) {
- try {
- StringWriter sw = new StringWriter(8192);
- BufferedWriter bw = new BufferedWriter(sw);
- formatGpxHeader(bw);
- formatWaypointGpx(bw, n);
- formatGpxFooter(bw);
- bw.close();
- sw.close();
- return sw.toString();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- static public void formatGpxHeader(BufferedWriter sb) throws IOException {
- sb.append("\n");
- sb.append("\n");
- }
-
- static public void formatGpxFooter(BufferedWriter sb) throws IOException {
- sb.append("\n");
- }
-
- static public void formatWaypointGpx(BufferedWriter sb, OsmNodeNamed n) throws IOException {
- sb.append(" ");
- if (n.getSElev() != Short.MIN_VALUE) {
- sb.append("").append("" + n.getElev()).append("");
- }
- if (n.name != null) {
- sb.append("").append(StringUtils.escapeXml10(n.name)).append("");
- }
- if (n.nodeDescription != null) {
- sb.append("").append("hat desc").append("");
- }
- sb.append("\n");
- }
-
- public void writeKml(String filename) throws Exception {
- BufferedWriter bw = new BufferedWriter(new FileWriter(filename));
-
- bw.write(formatAsKml());
- bw.close();
- }
-
- public String formatAsKml() {
- StringBuilder sb = new StringBuilder(8192);
-
- sb.append("\n");
-
- sb.append("\n");
- sb.append(" \n");
- sb.append(" KML Samples\n");
- sb.append(" 1\n");
- sb.append(" 3.497064\n");
- sb.append(" 872\n");
- sb.append(" To enable simple instructions add: 'instructions=1' as parameter to the URL\n");
- sb.append(" \n");
- sb.append(" Paths\n");
- sb.append(" 0\n");
- sb.append(" Examples of paths.\n");
- sb.append(" \n");
- sb.append(" Tessellated\n");
- sb.append(" 0\n");
- sb.append(" tag has a value of 1, the line will contour to the underlying terrain]]>\n");
- sb.append(" \n");
- sb.append(" 1\n");
- sb.append(" ");
-
- for (OsmPathElement n : nodes) {
- sb.append(formatILon(n.getILon())).append(",").append(formatILat(n.getILat())).append("\n");
- }
-
- sb.append(" \n");
- sb.append(" \n");
- sb.append(" \n");
- sb.append(" \n");
- if (exportWaypoints || !pois.isEmpty()) {
- if (!pois.isEmpty()) {
- sb.append(" \n");
- sb.append(" poi\n");
- for (int i = 0; i < pois.size(); i++) {
- OsmNodeNamed poi = pois.get(i);
- createPlaceMark(sb, poi.name, poi.ilat, poi.ilon);
- }
- sb.append(" \n");
- }
-
- if (exportWaypoints) {
- int size = matchedWaypoints.size();
- createFolder(sb, "start", matchedWaypoints.subList(0, 1));
- if (matchedWaypoints.size() > 2) {
- createFolder(sb, "via", matchedWaypoints.subList(1, size - 1));
- }
- createFolder(sb, "end", matchedWaypoints.subList(size - 1, size));
- }
- }
- sb.append(" \n");
- sb.append("\n");
-
- return sb.toString();
- }
-
- private void createFolder(StringBuilder sb, String type, List waypoints) {
- sb.append(" \n");
- sb.append(" " + type + "\n");
- for (int i = 0; i < waypoints.size(); i++) {
- MatchedWaypoint wp = waypoints.get(i);
- createPlaceMark(sb, wp.name, wp.waypoint.ilat, wp.waypoint.ilon);
- }
- sb.append(" \n");
- }
-
- private void createPlaceMark(StringBuilder sb, String name, int ilat, int ilon) {
- sb.append(" \n");
- sb.append(" " + StringUtils.escapeXml10(name) + "\n");
- sb.append(" \n");
- sb.append(" " + formatILon(ilon) + "," + formatILat(ilat) + "\n");
- sb.append(" \n");
- sb.append(" \n");
- }
-
public List iternity;
- public void writeJson(String filename) throws Exception {
- BufferedWriter bw = new BufferedWriter(new FileWriter(filename));
-
- bw.write(formatAsGeoJson());
- bw.close();
- }
-
-
- public String formatAsGeoJson() {
- int turnInstructionMode = voiceHints != null ? voiceHints.turnInstructionMode : 0;
-
- StringBuilder sb = new StringBuilder(8192);
-
- sb.append("{\n");
- sb.append(" \"type\": \"FeatureCollection\",\n");
- sb.append(" \"features\": [\n");
- sb.append(" {\n");
- sb.append(" \"type\": \"Feature\",\n");
- sb.append(" \"properties\": {\n");
- sb.append(" \"creator\": \"BRouter-" + version + "\",\n");
- sb.append(" \"name\": \"").append(name).append("\",\n");
- sb.append(" \"track-length\": \"").append(distance).append("\",\n");
- sb.append(" \"filtered ascend\": \"").append(ascend).append("\",\n");
- sb.append(" \"plain-ascend\": \"").append(plainAscend).append("\",\n");
- sb.append(" \"total-time\": \"").append(getTotalSeconds()).append("\",\n");
- sb.append(" \"total-energy\": \"").append(energy).append("\",\n");
- sb.append(" \"cost\": \"").append(cost).append("\",\n");
- if (voiceHints != null && !voiceHints.list.isEmpty()) {
- sb.append(" \"voicehints\": [\n");
- for (VoiceHint hint : voiceHints.list) {
- sb.append(" [");
- sb.append(hint.indexInTrack);
- sb.append(',').append(hint.getJsonCommandIndex());
- sb.append(',').append(hint.getExitNumber());
- sb.append(',').append(hint.distanceToNext);
- sb.append(',').append((int) hint.angle);
-
- // not always include geometry because longer and only needed for comment style
- if (turnInstructionMode == 4) { // comment style
- sb.append(",\"").append(hint.formatGeometry()).append("\"");
- }
-
- sb.append("],\n");
- }
- sb.deleteCharAt(sb.lastIndexOf(","));
- sb.append(" ],\n");
- }
- if (showSpeedProfile) { // set in profile
- List sp = aggregateSpeedProfile();
- if (sp.size() > 0) {
- sb.append(" \"speedprofile\": [\n");
- for (int i = sp.size() - 1; i >= 0; i--) {
- sb.append(" [").append(sp.get(i)).append(i > 0 ? "],\n" : "]\n");
- }
- sb.append(" ],\n");
- }
- }
- // ... traditional message list
- {
- sb.append(" \"messages\": [\n");
- sb.append(" [\"").append(MESSAGES_HEADER.replaceAll("\t", "\", \"")).append("\"],\n");
- for (String m : aggregateMessages()) {
- sb.append(" [\"").append(m.replaceAll("\t", "\", \"")).append("\"],\n");
- }
- sb.deleteCharAt(sb.lastIndexOf(","));
- sb.append(" ],\n");
- }
-
- if (getTotalSeconds() > 0) {
- sb.append(" \"times\": [");
- DecimalFormat decimalFormat = (DecimalFormat) NumberFormat.getInstance(Locale.ENGLISH);
- decimalFormat.applyPattern("0.###");
- for (OsmPathElement n : nodes) {
- sb.append(decimalFormat.format(n.getTime())).append(",");
- }
- sb.deleteCharAt(sb.lastIndexOf(","));
- sb.append("]\n");
- } else {
- sb.deleteCharAt(sb.lastIndexOf(","));
- }
-
- sb.append(" },\n");
-
- if (iternity != null) {
- sb.append(" \"iternity\": [\n");
- for (String s : iternity) {
- sb.append(" \"").append(s).append("\",\n");
- }
- sb.deleteCharAt(sb.lastIndexOf(","));
- sb.append(" ],\n");
- }
- sb.append(" \"geometry\": {\n");
- sb.append(" \"type\": \"LineString\",\n");
- sb.append(" \"coordinates\": [\n");
-
- OsmPathElement nn = null;
- for (OsmPathElement n : nodes) {
- String sele = n.getSElev() == Short.MIN_VALUE ? "" : ", " + n.getElev();
- if (showspeed) { // hack: show speed instead of elevation
- double speed = 0;
- if (nn != null) {
- int dist = n.calcDistance(nn);
- float dt = n.getTime() - nn.getTime();
- if (dt != 0.f) {
- speed = ((3.6f * dist) / dt + 0.5);
- }
- }
- sele = ", " + (((int) (speed * 10)) / 10.f);
- }
- sb.append(" [").append(formatILon(n.getILon())).append(", ").append(formatILat(n.getILat()))
- .append(sele).append("],\n");
- nn = n;
- }
- sb.deleteCharAt(sb.lastIndexOf(","));
-
- sb.append(" ]\n");
- sb.append(" }\n");
- if (exportWaypoints || !pois.isEmpty()) {
- sb.append(" },\n");
- for (int i = 0; i <= pois.size() - 1; i++) {
- OsmNodeNamed poi = pois.get(i);
- addFeature(sb, "poi", poi.name, poi.ilat, poi.ilon);
- if (i < matchedWaypoints.size() - 1) {
- sb.append(",");
- }
- sb.append(" \n");
- }
- if (exportWaypoints) {
- for (int i = 0; i <= matchedWaypoints.size() - 1; i++) {
- String type;
- if (i == 0) {
- type = "from";
- } else if (i == matchedWaypoints.size() - 1) {
- type = "to";
- } else {
- type = "via";
- }
-
- MatchedWaypoint wp = matchedWaypoints.get(i);
- addFeature(sb, type, wp.name, wp.waypoint.ilat, wp.waypoint.ilon);
- if (i < matchedWaypoints.size() - 1) {
- sb.append(",");
- }
- sb.append(" \n");
- }
- }
- } else {
- sb.append(" }\n");
- }
- sb.append(" ]\n");
- sb.append("}\n");
-
- return sb.toString();
- }
-
- private void addFeature(StringBuilder sb, String type, String name, int ilat, int ilon) {
- sb.append(" {\n");
- sb.append(" \"type\": \"Feature\",\n");
- sb.append(" \"properties\": {\n");
- sb.append(" \"name\": \"" + StringUtils.escapeJson(name) + "\",\n");
- sb.append(" \"type\": \"" + type + "\"\n");
- sb.append(" },\n");
- sb.append(" \"geometry\": {\n");
- sb.append(" \"type\": \"Point\",\n");
- sb.append(" \"coordinates\": [\n");
- sb.append(" " + formatILon(ilon) + ",\n");
- sb.append(" " + formatILat(ilat) + "\n");
- sb.append(" ]\n");
- sb.append(" }\n");
- sb.append(" }");
- }
-
- private VoiceHint getVoiceHint(int i) {
+ public VoiceHint getVoiceHint(int i) {
if (voiceHints == null) return null;
for (VoiceHint hint : voiceHints.list) {
if (hint.indexInTrack == i) {
@@ -1150,7 +394,7 @@ public final class OsmTrack {
return null;
}
- private MatchedWaypoint getMatchedWaypoint(int idx) {
+ public MatchedWaypoint getMatchedWaypoint(int idx) {
if (matchedWaypoints == null) return null;
for (MatchedWaypoint wp : matchedWaypoints) {
if (idx == wp.indexInTrack) {
@@ -1168,128 +412,11 @@ public final class OsmTrack {
return vnode0 < vnode1 ? vnode0 : vnode1;
}
- private int getTotalSeconds() {
+ public int getTotalSeconds() {
float s = nodes.size() < 2 ? 0 : nodes.get(nodes.size() - 1).getTime() - nodes.get(0).getTime();
return (int) (s + 0.5);
}
- public String getFormattedTime() {
- return format1(getTotalSeconds() / 60.) + "m";
- }
-
- public String getFormattedTime2() {
- int seconds = (int) (getTotalSeconds() + 0.5);
- int hours = seconds / 3600;
- int minutes = (seconds - hours * 3600) / 60;
- seconds = seconds - hours * 3600 - minutes * 60;
- String time = "";
- if (hours != 0)
- time = "" + hours + "h ";
- if (minutes != 0)
- time = time + minutes + "m ";
- if (seconds != 0)
- time = time + seconds + "s";
- return time;
- }
-
- SimpleDateFormat TIMESTAMP_FORMAT;
-
- public String getFormattedTime3(float time) {
- if (TIMESTAMP_FORMAT == null) {
- TIMESTAMP_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
- TIMESTAMP_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
- }
- // yyyy-mm-ddThh:mm:ss.SSSZ
- Date d = new Date((long) (time * 1000f));
- return TIMESTAMP_FORMAT.format(d);
- }
-
- public String getFormattedEnergy() {
- return format1(energy / 3600000.) + "kwh";
- }
-
- private static String formatILon(int ilon) {
- return formatPos(ilon - 180000000);
- }
-
- private static String formatILat(int ilat) {
- return formatPos(ilat - 90000000);
- }
-
- private static String formatPos(int p) {
- boolean negative = p < 0;
- if (negative)
- p = -p;
- char[] ac = new char[12];
- int i = 11;
- while (p != 0 || i > 3) {
- ac[i--] = (char) ('0' + (p % 10));
- p /= 10;
- if (i == 5)
- ac[i--] = '.';
- }
- if (negative)
- ac[i--] = '-';
- return new String(ac, i + 1, 11 - i);
- }
-
- private String format1(double n) {
- String s = "" + (long) (n * 10 + 0.5);
- int len = s.length();
- return s.substring(0, len - 1) + "." + s.charAt(len - 1);
- }
-
- public void dumpMessages(String filename, RoutingContext rc) throws Exception {
- BufferedWriter bw = filename == null ? null : new BufferedWriter(new FileWriter(filename));
- writeMessages(bw, rc);
- }
-
- public void writeMessages(BufferedWriter bw, RoutingContext rc) throws Exception {
- dumpLine(bw, MESSAGES_HEADER);
- for (String m : aggregateMessages()) {
- dumpLine(bw, m);
- }
- if (bw != null)
- bw.close();
- }
-
- private void dumpLine(BufferedWriter bw, String s) throws Exception {
- if (bw == null) {
- System.out.println(s);
- } else {
- bw.write(s);
- bw.write("\n");
- }
- }
-
- public void readGpx(String filename) throws Exception {
- File f = new File(filename);
- if (!f.exists())
- return;
- BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(f)));
-
- for (; ; ) {
- String line = br.readLine();
- if (line == null)
- break;
-
- int idx0 = line.indexOf("= 0) {
- idx0 += 12;
- int idx1 = line.indexOf('"', idx0);
- int ilon = (int) ((Double.parseDouble(line.substring(idx0, idx1)) + 180.) * 1000000. + 0.5);
- int idx2 = line.indexOf(" lat=\"");
- if (idx2 < 0)
- continue;
- idx2 += 6;
- int idx3 = line.indexOf('"', idx2);
- int ilat = (int) ((Double.parseDouble(line.substring(idx2, idx3)) + 90.) * 1000000. + 0.5);
- nodes.add(OsmPathElement.create(ilon, ilat, (short) 0, null, false));
- }
- }
- br.close();
- }
-
public boolean equalsTrack(OsmTrack t) {
if (nodes.size() != t.nodes.size())
return false;
@@ -1398,7 +525,7 @@ public final class OsmTrack {
return 2;
}
- private float getVoiceHintTime(int i) {
+ public float getVoiceHintTime(int i) {
if (voiceHints.list.isEmpty()) {
return 0f;
}
diff --git a/brouter-core/src/main/java/btools/router/RoutingEngine.java b/brouter-core/src/main/java/btools/router/RoutingEngine.java
index baff3dc..105ed09 100644
--- a/brouter-core/src/main/java/btools/router/RoutingEngine.java
+++ b/brouter-core/src/main/java/btools/router/RoutingEngine.java
@@ -192,34 +192,70 @@ public class RoutingEngine extends Thread {
track.message = "track-length = " + track.distance + " filtered ascend = " + track.ascend
+ " plain-ascend = " + track.plainAscend + " cost=" + track.cost;
if (track.energy != 0) {
- track.message += " energy=" + track.getFormattedEnergy() + " time=" + track.getFormattedTime2();
+ track.message += " energy=" + Formatter.getFormattedEnergy(track.energy) + " time=" + Formatter.getFormattedTime2(track.getTotalSeconds());
}
track.name = "brouter_" + routingContext.getProfileName() + "_" + i;
messageList.add(track.message);
track.messageList = messageList;
if (outfileBase != null) {
- String filename = outfileBase + i + ".gpx";
- OsmTrack oldTrack = new OsmTrack();
- oldTrack.readGpx(filename);
- if (track.equalsTrack(oldTrack)) {
+ String filename = outfileBase + i + "." + routingContext.outputFormat;
+ OsmTrack oldTrack = null;
+ switch (routingContext.outputFormat) {
+ case "gpx":
+ oldTrack = new FormatGpx(routingContext).read(filename);
+ break;
+ case "geojson": // read only gpx at the moment
+ case "json":
+ // oldTrack = new FormatJson(routingContext).read(filename);
+ break;
+ case "kml":
+ // oldTrack = new FormatJson(routingContext).read(filename);
+ break;
+ default:
+ break;
+ }
+ if (oldTrack != null && track.equalsTrack(oldTrack)) {
continue;
}
oldTrack = null;
track.exportWaypoints = routingContext.exportWaypoints;
- // doesn't work at the moment
- // use routingContext.outputFormat
- track.writeGpx(filename);
+ filename = outfileBase + i + "." + routingContext.outputFormat;
+ switch (routingContext.outputFormat) {
+ case "gpx":
+ outputMessage = new FormatGpx(routingContext).format(track);
+ break;
+ case "geojson":
+ case "json":
+ outputMessage = new FormatJson(routingContext).format(track);
+ break;
+ case "kml":
+ outputMessage = new FormatKml(routingContext).format(track);
+ break;
+ case "csv":
+ default:
+ outputMessage = null;
+ break;
+ }
+ if (outputMessage != null) {
+ File out = new File(filename);
+ FileWriter fw = new FileWriter(filename);
+ fw.write(outputMessage);
+ fw.close();
+ outputMessage = null;
+ }
+
foundTrack = track;
alternativeIndex = i;
outfile = filename;
} else {
if (i == routingContext.getAlternativeIdx(0, 3)) {
if ("CSV".equals(System.getProperty("reportFormat"))) {
- track.dumpMessages(null, routingContext);
+ String filename = outfileBase + i + ".csv";
+ new FormatCsv(routingContext).write(filename, track);
} else {
if (!quite) {
- System.out.println(track.formatAsGpx());
+ System.out.println(new FormatGpx(routingContext).format(track));
}
}
foundTrack = track;
@@ -229,7 +265,7 @@ public class RoutingEngine extends Thread {
}
if (logfileBase != null) {
String logfilename = logfileBase + i + ".csv";
- track.dumpMessages(logfilename, routingContext);
+ new FormatCsv(routingContext).write(logfilename, track);
}
break;
}
@@ -308,15 +344,31 @@ public class RoutingEngine extends Thread {
OsmNodeNamed n = new OsmNodeNamed(listOne.get(0).crosspoint);
n.selev = startNode != null ? startNode.getSElev() : Short.MIN_VALUE;
- // doesn't work at the moment
- // use routingContext.outputFormat
- outputMessage = OsmTrack.formatAsGpxWaypoint(n);
+ switch (routingContext.outputFormat) {
+ case "gpx":
+ outputMessage = new FormatGpx(routingContext).formatAsWaypoint(n);
+ break;
+ case "geojson":
+ case "json":
+ outputMessage = new FormatJson(routingContext).formatAsWaypoint(n);
+ break;
+ case "kml":
+ case "csv":
+ default:
+ outputMessage = null;
+ break;
+ }
if (outfileBase != null) {
- String filename = outfileBase + ".gpx";
+ String filename = outfileBase + "." + routingContext.outputFormat;
File out = new File(filename);
FileWriter fw = new FileWriter(filename);
fw.write(outputMessage);
fw.close();
+ outputMessage = null;
+ } else {
+ if (!quite && outputMessage != null) {
+ System.out.println(outputMessage);
+ }
}
long endTime = System.currentTimeMillis();
logInfo("execution time = " + (endTime - startTime) / 1000. + " seconds");
@@ -951,7 +1003,7 @@ public class RoutingEngine extends Thread {
if (track == null) {
for (int cfi = 0; cfi < airDistanceCostFactors.length; cfi++) {
- if (cfi > 0) lastAirDistanceCostFactor = airDistanceCostFactors[cfi-1];
+ if (cfi > 0) lastAirDistanceCostFactor = airDistanceCostFactors[cfi - 1];
airDistanceCostFactor = airDistanceCostFactors[cfi];
if (airDistanceCostFactor < 0.) {
@@ -1447,7 +1499,7 @@ public class RoutingEngine extends Thread {
boolean inRadius = boundary == null || boundary.isInBoundary(nextNode, bestPath.cost);
- if (inRadius && (isFinalLink || bestPath.cost + bestPath.airdistance <= (lastAirDistanceCostFactor != 0. ? maxTotalCost*lastAirDistanceCostFactor : maxTotalCost) + addDiff)) {
+ if (inRadius && (isFinalLink || bestPath.cost + bestPath.airdistance <= (lastAirDistanceCostFactor != 0. ? maxTotalCost * lastAirDistanceCostFactor : maxTotalCost) + addDiff)) {
// add only if this may beat an existing path for that link
OsmLinkHolder dominator = link.getFirstLinkHolder(currentNode);
while (!trafficSim && dominator != null) {
@@ -1628,7 +1680,7 @@ public class RoutingEngine extends Thread {
}
public String getTime() {
- return foundTrack.getFormattedTime2();
+ return Formatter.getFormattedTime2(foundTrack.getTotalSeconds());
}
public OsmTrack getFoundTrack() {
diff --git a/brouter-core/src/main/java/btools/router/RoutingParamCollector.java b/brouter-core/src/main/java/btools/router/RoutingParamCollector.java
index adc08fe..99f5b3b 100644
--- a/brouter-core/src/main/java/btools/router/RoutingParamCollector.java
+++ b/brouter-core/src/main/java/btools/router/RoutingParamCollector.java
@@ -14,8 +14,9 @@ public class RoutingParamCollector {
/**
* get a list of points and optional extra info for the points
- * @param lonLats - linked list separated by ';' or '|'
- * @return - a list
+ *
+ * @param lonLats linked list separated by ';' or '|'
+ * @return a list
*/
public List getWayPointList(String lonLats) {
if (lonLats == null) throw new IllegalArgumentException("lonlats parameter not set");
@@ -49,9 +50,10 @@ public class RoutingParamCollector {
/**
* get a list of points (old style, positions only)
- * @param lons - array with longitudes
- * @param lats - array with latitudes
- * @return - a list
+ *
+ * @param lons array with longitudes
+ * @param lats array with latitudes
+ * @return a list
*/
public List readPositions(double[] lons, double[] lats) {
List wplist = new ArrayList<>();
@@ -93,9 +95,10 @@ public class RoutingParamCollector {
/**
* read a url like parameter list linked with '&'
- * @param url - parameter list
- * @return - a hashmap of the parameter
- * @throws UnsupportedEncodingException
+ *
+ * @param url parameter list
+ * @return a hashmap of the parameter
+ * @throws UnsupportedEncodingException
*/
public Map getUrlParams(String url) throws UnsupportedEncodingException {
HashMap params = new HashMap<>();
@@ -117,9 +120,10 @@ public class RoutingParamCollector {
/**
* fill a parameter map into the routing context
- * @param rctx - the context
- * @param wplist - the list of way points needed for 'straight' parameter
- * @param params - the list of parameters
+ *
+ * @param rctx the context
+ * @param wplist the list of way points needed for 'straight' parameter
+ * @param params the list of parameters
*/
public void setParams(RoutingContext rctx, List wplist, Map params) {
if (params != null) {
@@ -129,11 +133,15 @@ public class RoutingParamCollector {
if (params.containsKey("profile")) {
rctx.localFunction = params.get("profile");
}
- if (params.containsKey("nogoLats")) {
+ if (params.containsKey("nogoLats") && params.get("nogoLats").length() > 0) {
List nogoList = readNogos(params.get("nogoLons"), params.get("nogoLats"), params.get("nogoRadi"));
if (nogoList != null) {
RoutingContext.prepareNogoPoints(nogoList);
- rctx.nogopoints = nogoList;
+ if (rctx.nogopoints == null) {
+ rctx.nogopoints = nogoList;
+ } else {
+ rctx.nogopoints.addAll(nogoList);
+ }
}
params.remove("nogoLats");
params.remove("nogoLons");
@@ -143,7 +151,11 @@ public class RoutingParamCollector {
List nogoList = readNogoList(params.get("nogos"));
if (nogoList != null) {
RoutingContext.prepareNogoPoints(nogoList);
- rctx.nogopoints = nogoList;
+ if (rctx.nogopoints == null) {
+ rctx.nogopoints = nogoList;
+ } else {
+ rctx.nogopoints.addAll(nogoList);
+ }
}
params.remove("nogos");
}
@@ -196,6 +208,12 @@ public class RoutingParamCollector {
rctx.turnInstructionMode = Integer.parseInt(value);
} else if (key.equals("timode")) {
rctx.turnInstructionMode = Integer.parseInt(value);
+ } else if (key.equals("turnInstructionFormat")) {
+ if ("osmand".equalsIgnoreCase(value)) {
+ rctx.turnInstructionMode = 3;
+ } else if ("locus".equalsIgnoreCase(value)) {
+ rctx.turnInstructionMode = 2;
+ }
} else if (key.equals("exportWaypoints")) {
rctx.exportWaypoints = (Integer.parseInt(value) == 1);
} else if (key.equals("format")) {
@@ -213,8 +231,9 @@ public class RoutingParamCollector {
/**
* fill profile parameter list
- * @param rctx - the routing context
- * @param params - the list of parameters
+ *
+ * @param rctx the routing context
+ * @param params the list of parameters
*/
public void setProfileParams(RoutingContext rctx, Map params) {
if (params != null) {
diff --git a/brouter-routing-app/build.gradle b/brouter-routing-app/build.gradle
index 9cd72f4..2300600 100644
--- a/brouter-routing-app/build.gradle
+++ b/brouter-routing-app/build.gradle
@@ -20,8 +20,6 @@ android {
minSdkVersion 14
targetSdkVersion 33
- resConfigs "en"
-
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
diff --git a/brouter-routing-app/src/main/java/btools/routingapp/BInstallerActivity.java b/brouter-routing-app/src/main/java/btools/routingapp/BInstallerActivity.java
index c49a6be..f9ffe61 100644
--- a/brouter-routing-app/src/main/java/btools/routingapp/BInstallerActivity.java
+++ b/brouter-routing-app/src/main/java/btools/routingapp/BInstallerActivity.java
@@ -171,7 +171,7 @@ public class BInstallerActivity extends AppCompatActivity {
}
mButtonDownload.setText(getString(R.string.action_download, getSegmentsPlural(selectedTilesDownload.size())));
mButtonDownload.setEnabled(true);
- mSummaryInfo.setText(getString(R.string.summary_segments, Formatter.formatFileSize(this, tileSize), Formatter.formatFileSize(this, getAvailableSpace(mBaseDir.getAbsolutePath()))));
+ mSummaryInfo.setText(String.format(getString(R.string.summary_segments), Formatter.formatFileSize(this, tileSize), Formatter.formatFileSize(this, getAvailableSpace(mBaseDir.getAbsolutePath()))));
} else if (selectedTilesUpdate.size() > 0) {
mButtonDownload.setText(getString(R.string.action_update, getSegmentsPlural(selectedTilesUpdate.size())));
mButtonDownload.setEnabled(true);
diff --git a/brouter-routing-app/src/main/java/btools/routingapp/BRouterService.java b/brouter-routing-app/src/main/java/btools/routingapp/BRouterService.java
index 95dbadd..90b875c 100644
--- a/brouter-routing-app/src/main/java/btools/routingapp/BRouterService.java
+++ b/brouter-routing-app/src/main/java/btools/routingapp/BRouterService.java
@@ -19,6 +19,7 @@ import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.zip.GZIPOutputStream;
@@ -39,10 +40,6 @@ public class BRouterService extends Service {
BRouterWorker worker = new BRouterWorker();
- for (String key : params.keySet()) {
- // Log.d("BS", "income " + key + " = " + params.get(key));
- }
-
int engineMode = 0;
if (params.containsKey("engineMode")) {
engineMode = params.getInt("engineMode", 0);
@@ -103,7 +100,7 @@ public class BRouterService extends Service {
boolean canCompress = "true".equals(params.getString("acceptCompressedResult"));
try {
String gpxMessage = worker.getTrackFromParams(params);
- if (canCompress && gpxMessage.startsWith("<")) {
+ if (canCompress) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write("z64".getBytes(Charset.forName("UTF-8"))); // marker prefix
@@ -277,8 +274,13 @@ public class BRouterService extends Service {
private void logBundle(Bundle params) {
if (AppLogger.isLogging()) {
for (String k : params.keySet()) {
- Object val = "remoteProfile".equals(k) ? "<..cut..>" : params.getString(k);
- String desc = "key=" + k + (val == null ? "" : " class=" + val.getClass() + " val=" + val.toString());
+ Object val = "remoteProfile".equals(k) ? "<..cut..>" : params.get(k);
+ String desc = "key=" + k + (val == null ? "" : " class=" + val.getClass() + " val=");
+ if (val instanceof double[]) {
+ desc += Arrays.toString(params.getDoubleArray(k));
+ } else {
+ desc += val.toString();
+ }
AppLogger.log(desc);
}
}
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 7e37818..64e73d5 100644
--- a/brouter-routing-app/src/main/java/btools/routingapp/BRouterWorker.java
+++ b/brouter-routing-app/src/main/java/btools/routingapp/BRouterWorker.java
@@ -6,16 +6,20 @@ import android.os.Bundle;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
-import java.util.ArrayList;
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
-import java.util.StringTokenizer;
+import java.util.Map;
+import btools.router.FormatGpx;
+import btools.router.FormatJson;
+import btools.router.FormatKml;
import btools.router.OsmNodeNamed;
-import btools.router.OsmNogoPolygon;
import btools.router.OsmTrack;
import btools.router.RoutingContext;
import btools.router.RoutingEngine;
+import btools.router.RoutingParamCollector;
public class BRouterWorker {
private static final int OUTPUT_FORMAT_GPX = 0;
@@ -39,6 +43,72 @@ public class BRouterWorker {
engineMode = params.getInt("engineMode", 0);
}
+ RoutingContext rc = new RoutingContext();
+ rc.rawTrackPath = rawTrackPath;
+ rc.localFunction = profilePath;
+
+ RoutingParamCollector routingParamCollector = new RoutingParamCollector();
+
+ // parameter pre control
+ if (params.containsKey("lonlats")) {
+ waypoints = routingParamCollector.getWayPointList(params.getString("lonlats"));
+ params.remove("lonlats");
+ }
+ if (params.containsKey("lats")) {
+ double[] lats = params.getDoubleArray("lats");
+ double[] lons = params.getDoubleArray("lons");
+ waypoints = routingParamCollector.readPositions(lons, lats);
+ params.remove("lons");
+ params.remove("lats");
+ }
+
+ if (waypoints == null) {
+ throw new IllegalArgumentException("no points!");
+ }
+ if (engineMode == 0) {
+ if (waypoints.size() < 2) {
+ throw new IllegalArgumentException("we need two lat/lon points at least!");
+ }
+ } else {
+ if (waypoints.size() < 1) {
+ throw new IllegalArgumentException("we need two lat/lon points at least!");
+ }
+ }
+
+ if (nogoList != null && nogoList.size() > 0) {
+ // forward already read nogos from filesystem
+ if (rc.nogopoints == null) {
+ rc.nogopoints = nogoList;
+ } else {
+ rc.nogopoints.addAll(nogoList);
+ }
+
+ }
+
+ Map theParams = new HashMap<>();
+ for (String key : params.keySet()) {
+ Object value = params.get(key);
+ if (value instanceof double[]) {
+ String s = Arrays.toString(params.getDoubleArray(key));
+ s = s.replace("[", "").replace("]", "");
+ theParams.put(key, s);
+ } else {
+ theParams.put(key, value.toString());
+ }
+ }
+ routingParamCollector.setParams(rc, waypoints, theParams);
+
+ if (params.containsKey("extraParams")) {
+ Map profileparams = null;
+ try {
+ profileparams = routingParamCollector.getUrlParams(params.getString("extraParams"));
+ routingParamCollector.setProfileParams(rc, profileparams);
+ } catch (UnsupportedEncodingException e) {
+ // ignore
+ }
+ }
+
+
String pathToFileResult = params.getString("pathToFileResult");
if (pathToFileResult != null) {
@@ -52,100 +122,9 @@ public class BRouterWorker {
long maxRunningTime = 60000;
String sMaxRunningTime = params.getString("maxRunningTime");
if (sMaxRunningTime != null) {
- maxRunningTime = Integer.parseInt(sMaxRunningTime) * 1000;
+ maxRunningTime = Integer.parseInt(sMaxRunningTime) * 1000L;
}
- RoutingContext rc = new RoutingContext();
- rc.rawTrackPath = rawTrackPath;
- rc.localFunction = profilePath;
-
- String tiFormat = params.getString("turnInstructionFormat");
- if (tiFormat != null) {
- if ("osmand".equalsIgnoreCase(tiFormat)) {
- rc.turnInstructionMode = 3;
- } else if ("locus".equalsIgnoreCase(tiFormat)) {
- rc.turnInstructionMode = 2;
- }
- }
- if (params.containsKey("timode")) {
- rc.turnInstructionMode = params.getInt("timode");
- }
-
- if (params.containsKey("direction")) {
- rc.startDirection = params.getInt("direction");
- }
- if (params.containsKey("heading")) {
- rc.startDirection = params.getInt("heading");
- rc.forceUseStartDirection = true;
- }
- if (params.containsKey("alternativeidx")) {
- rc.alternativeIdx = params.getInt("alternativeidx");
- }
-
- readNogos(params); // add interface provided nogos
- if (nogoList != null) {
- RoutingContext.prepareNogoPoints(nogoList);
- if (rc.nogopoints == null) {
- rc.nogopoints = nogoList;
- } else {
- rc.nogopoints.addAll(nogoList);
- }
- }
- if (rc.nogopoints == null) {
- rc.nogopoints = nogoPolygonsList;
- } else if (nogoPolygonsList != null) {
- rc.nogopoints.addAll(nogoPolygonsList);
- }
- List poisList = readPoisList(params);
- rc.poipoints = poisList;
-
- if (params.containsKey("lats")) {
- waypoints = readPositions(params);
- }
- if (params.containsKey("lonlats")) {
- waypoints = readLonlats(params, engineMode);
- }
-
- if (waypoints == null) return "no pts ";
-
- if (params.containsKey("straight")) {
- try {
- String straight = params.getString("straight");
- String[] sa = straight.split(",");
- for (int i = 0; i < sa.length; i++) {
- int v = Integer.parseInt(sa[i]);
- if (waypoints.size() > v) waypoints.get(v).direct = true;
- }
- } catch (NumberFormatException e) {
- }
- }
-
- String extraParams = null;
- if (params.containsKey("extraParams")) { // add user params
- extraParams = params.getString("extraParams");
- }
- if (extraParams != null && this.profileParams != null) {
- // don't overwrite incoming values
- extraParams = this.profileParams + "&" + extraParams;
- } else if (this.profileParams != null) {
- extraParams = this.profileParams;
- }
-
- if (params.containsKey("extraParams")) { // add user params
- if (rc.keyValues == null) rc.keyValues = new HashMap<>();
- StringTokenizer tk = new StringTokenizer(extraParams, "?&");
- while (tk.hasMoreTokens()) {
- String t = tk.nextToken();
- StringTokenizer tk2 = new StringTokenizer(t, "=");
- if (tk2.hasMoreTokens()) {
- String key = tk2.nextToken();
- if (tk2.hasMoreTokens()) {
- String value = tk2.nextToken();
- rc.keyValues.put(key, value);
- }
- }
- }
- }
try {
writeTimeoutData(rc);
@@ -170,50 +149,46 @@ public class BRouterWorker {
return cr.getErrorMessage();
}
- String format = params.getString("trackFormat");
int writeFromat = OUTPUT_FORMAT_GPX;
- if (format != null) {
- if ("kml".equals(format)) writeFromat = OUTPUT_FORMAT_KML;
- if ("json".equals(format)) writeFromat = OUTPUT_FORMAT_JSON;
+ if (rc.outputFormat != null) {
+ if ("kml".equals(rc.outputFormat)) writeFromat = OUTPUT_FORMAT_KML;
+ if ("json".equals(rc.outputFormat)) writeFromat = OUTPUT_FORMAT_JSON;
}
-
- OsmTrack track = cr.getFoundTrack();
+ OsmTrack track = null;
+ track = cr.getFoundTrack();
if (track != null) {
- if (params.containsKey("exportWaypoints")) {
- track.exportWaypoints = (params.getInt("exportWaypoints", 0) == 1);
- }
+ track.exportWaypoints = rc.exportWaypoints;
if (pathToFileResult == null) {
switch (writeFromat) {
- case OUTPUT_FORMAT_GPX:
- return track.formatAsGpx();
case OUTPUT_FORMAT_KML:
- return track.formatAsKml();
+ return new FormatKml(rc).format(track);
case OUTPUT_FORMAT_JSON:
- return track.formatAsGeoJson();
+ return new FormatJson(rc).format(track);
+ case OUTPUT_FORMAT_GPX:
default:
- return track.formatAsGpx();
+ return new FormatGpx(rc).format(track);
}
}
- try {
- switch (writeFromat) {
- case OUTPUT_FORMAT_GPX:
- track.writeGpx(pathToFileResult);
- break;
- case OUTPUT_FORMAT_KML:
- track.writeKml(pathToFileResult);
- break;
- case OUTPUT_FORMAT_JSON:
- track.writeJson(pathToFileResult);
- break;
- default:
- track.writeGpx(pathToFileResult);
- break;
- }
- } catch (Exception e) {
- return "error writing file: " + e;
- }
+
}
+ try {
+ switch (writeFromat) {
+ case OUTPUT_FORMAT_KML:
+ new FormatKml(rc).write(pathToFileResult, track);
+ break;
+ case OUTPUT_FORMAT_JSON:
+ new FormatJson(rc).write(pathToFileResult, track);
+ break;
+ case OUTPUT_FORMAT_GPX:
+ default:
+ new FormatGpx(rc).write(pathToFileResult, track);
+ break;
+ }
+ } catch (Exception e) {
+ return "error writing file: " + e;
+ }
+
} else { // get other infos
if (cr.getErrorMessage() != null) {
return cr.getErrorMessage();
@@ -223,204 +198,6 @@ public class BRouterWorker {
return null;
}
- private List readPositions(Bundle params) {
- List wplist = new ArrayList<>();
-
- double[] lats = params.getDoubleArray("lats");
- double[] lons = params.getDoubleArray("lons");
-
- if (lats == null || lats.length < 2 || lons == null || lons.length < 2) {
- throw new IllegalArgumentException("we need two lat/lon points at least!");
- }
-
- for (int i = 0; i < lats.length && i < lons.length; i++) {
- OsmNodeNamed n = new OsmNodeNamed();
- n.name = "via" + i;
- n.ilon = (int) ((lons[i] + 180.) * 1000000. + 0.5);
- n.ilat = (int) ((lats[i] + 90.) * 1000000. + 0.5);
- wplist.add(n);
- }
- if (wplist.get(0).name.startsWith("via")) wplist.get(0).name = "from";
- if (wplist.get(wplist.size() - 1).name.startsWith("via"))
- wplist.get(wplist.size() - 1).name = "to";
-
- return wplist;
- }
-
- private List readLonlats(Bundle params, int mode) {
- List wplist = new ArrayList<>();
-
- String lonLats = params.getString("lonlats");
- if (lonLats == null) throw new IllegalArgumentException("lonlats parameter not set");
-
- String[] coords;
- if (mode == 0) {
- coords = lonLats.split("\\|");
- if (coords.length < 2)
- throw new IllegalArgumentException("we need two lat/lon points at least!");
- } else {
- coords = new String[1];
- coords[0] = lonLats;
- }
- for (int i = 0; i < coords.length; i++) {
- String[] lonLat = coords[i].split(",");
- if (lonLat.length < 2)
- throw new IllegalArgumentException("we need a lat and lon point at least!");
- wplist.add(readPosition(lonLat[0], lonLat[1], "via" + i));
- if (lonLat.length > 2) {
- if (lonLat[2].equals("d")) {
- wplist.get(wplist.size() - 1).direct = true;
- } else {
- wplist.get(wplist.size() - 1).name = lonLat[2];
- }
- }
- }
-
- if (wplist.get(0).name.startsWith("via")) wplist.get(0).name = "from";
- if (wplist.get(wplist.size() - 1).name.startsWith("via"))
- wplist.get(wplist.size() - 1).name = "to";
-
- return wplist;
- }
-
- private static OsmNodeNamed readPosition(String vlon, String vlat, String name) {
- if (vlon == null) throw new IllegalArgumentException("lon " + name + " not found in input");
- if (vlat == null) throw new IllegalArgumentException("lat " + name + " not found in input");
-
- return readPosition(Double.parseDouble(vlon), Double.parseDouble(vlat), name);
- }
-
- private static OsmNodeNamed readPosition(double lon, double lat, String name) {
- OsmNodeNamed n = new OsmNodeNamed();
- n.name = name;
- n.ilon = (int) ((lon + 180.) * 1000000. + 0.5);
- n.ilat = (int) ((lat + 90.) * 1000000. + 0.5);
- return n;
- }
-
-
- private void readNogos(Bundle params) {
- if (params.containsKey("nogoLats")) {
- double[] lats = params.getDoubleArray("nogoLats");
- double[] lons = params.getDoubleArray("nogoLons");
- double[] radi = params.getDoubleArray("nogoRadi");
-
- if (lats == null || lons == null || radi == null) return;
-
- for (int i = 0; i < lats.length && i < lons.length && i < radi.length; i++) {
- OsmNodeNamed n = new OsmNodeNamed();
- n.name = "nogo" + (int) radi[i];
- n.ilon = (int) ((lons[i] + 180.) * 1000000. + 0.5);
- n.ilat = (int) ((lats[i] + 90.) * 1000000. + 0.5);
- n.isNogo = true;
- n.nogoWeight = Double.NaN;
- AppLogger.log("added interface provided nogo: " + n);
- nogoList.add(n);
- }
- }
- if (params.containsKey("nogos")) {
- nogoList = readNogoList(params);
- }
- if (params.containsKey("polylines") ||
- params.containsKey("polygons")) {
- nogoPolygonsList = readNogoPolygons(params);
- }
- }
-
- private List readNogoList(Bundle params) {
- // lon,lat,radius|...
- String nogos = params.getString("nogos");
- if (nogos == null) return null;
-
- String[] lonLatRadList = nogos.split("\\|");
-
- List nogoList = new ArrayList<>();
- for (int i = 0; i < lonLatRadList.length; i++) {
- String[] lonLatRad = lonLatRadList[i].split(",");
- String nogoWeight = "NaN";
- if (lonLatRad.length > 3) {
- nogoWeight = lonLatRad[3];
- }
- nogoList.add(readNogo(lonLatRad[0], lonLatRad[1], lonLatRad[2], nogoWeight));
- }
-
- return nogoList;
- }
-
- private static OsmNodeNamed readNogo(String lon, String lat, String radius, String nogoWeight) {
- double weight = "undefined".equals(nogoWeight) ? Double.NaN : Double.parseDouble(nogoWeight);
- return readNogo(Double.parseDouble(lon), Double.parseDouble(lat), Integer.parseInt(radius), weight);
- }
-
- private static OsmNodeNamed readNogo(double lon, double lat, int radius, double nogoWeight) {
- OsmNodeNamed n = new OsmNodeNamed();
- n.name = "nogo" + radius;
- n.ilon = (int) ((lon + 180.) * 1000000. + 0.5);
- n.ilat = (int) ((lat + 90.) * 1000000. + 0.5);
- n.isNogo = true;
- n.nogoWeight = nogoWeight;
- return n;
- }
-
- private List readNogoPolygons(Bundle params) {
- List result = new ArrayList<>();
- parseNogoPolygons(params.getString("polylines"), result, false);
- parseNogoPolygons(params.getString("polygons"), result, true);
- return result.size() > 0 ? result : null;
- }
-
- private static void parseNogoPolygons(String polygons, List result, boolean closed) {
- if (polygons != null) {
- String[] polygonList = polygons.split("\\|");
- for (int i = 0; i < polygonList.length; i++) {
- String[] lonLatList = polygonList[i].split(",");
- if (lonLatList.length > 1) {
- OsmNogoPolygon polygon = new OsmNogoPolygon(closed);
- polygon.name = "nogo" + i;
- int j;
- for (j = 0; j < 2 * (lonLatList.length / 2) - 1; ) {
- String slon = lonLatList[j++];
- String slat = lonLatList[j++];
- int lon = (int) ((Double.parseDouble(slon) + 180.) * 1000000. + 0.5);
- int lat = (int) ((Double.parseDouble(slat) + 90.) * 1000000. + 0.5);
- polygon.addVertex(lon, lat);
- }
-
- String nogoWeight = "NaN";
- if (j < lonLatList.length) {
- nogoWeight = lonLatList[j];
- }
- polygon.nogoWeight = Double.parseDouble(nogoWeight);
-
- if (polygon.points.size() > 0) {
- polygon.calcBoundingCircle();
- result.add(polygon);
- }
- }
- }
- }
- }
-
- private List readPoisList(Bundle params) {
- // lon,lat,name|...
- String pois = params.getString("pois");
- if (pois == null) return null;
-
- String[] lonLatNameList = pois.split("\\|");
-
- List poisList = new ArrayList<>();
- for (int i = 0; i < lonLatNameList.length; i++) {
- String[] lonLatName = lonLatNameList[i].split(",");
-
- OsmNodeNamed n = new OsmNodeNamed();
- n.ilon = (int) ((Double.parseDouble(lonLatName[0]) + 180.) * 1000000. + 0.5);
- n.ilat = (int) ((Double.parseDouble(lonLatName[1]) + 90.) * 1000000. + 0.5);
- n.name = lonLatName[2];
- poisList.add(n);
- }
-
- return poisList;
- }
private void writeTimeoutData(RoutingContext rc) throws Exception {
String timeoutFile = baseDir + "/brouter/modes/timeoutdata.txt";
@@ -431,7 +208,7 @@ public class BRouterWorker {
bw.write(rc.rawTrackPath);
bw.write("\n");
writeWPList(bw, waypoints);
- writeWPList(bw, nogoList);
+ writeWPList(bw, rc.nogopoints);
bw.close();
}
diff --git a/brouter-routing-app/src/main/res/values-ar/strings.xml b/brouter-routing-app/src/main/res/values-ar/strings.xml
new file mode 100644
index 0000000..43e2663
--- /dev/null
+++ b/brouter-routing-app/src/main/res/values-ar/strings.xml
@@ -0,0 +1,16 @@
+
+
+
+ - %d قطعة
+ - %d قطع
+
+ إلغاء التنزيل
+ استيراد ملف تعريف
+ تنزيل %s
+ حذف %s
+ تحديث %s
+ حدد القطع
+ إيقاف التنزيل
+ الحجم=%1$s\nالحجم المتوفر=%2$s
+ تحميل القطع
+
diff --git a/brouter-routing-app/src/main/res/values-ca/strings.xml b/brouter-routing-app/src/main/res/values-ca/strings.xml
new file mode 100644
index 0000000..13aeaea
--- /dev/null
+++ b/brouter-routing-app/src/main/res/values-ca/strings.xml
@@ -0,0 +1,16 @@
+
+
+
+ - %d segment
+ - %d segments
+
+ Cancel·lar descàrrega
+ Importar perfil
+ Descàrrega %s
+ Eliminar %s
+ Actualitzar %s
+ Seleccionar segments
+ Aturar Descàrrega
+ Espai=%1$s\nLliure=%2$s
+ Descarregar segments
+
diff --git a/brouter-routing-app/src/main/res/values-de/strings.xml b/brouter-routing-app/src/main/res/values-de/strings.xml
new file mode 100644
index 0000000..85002f5
--- /dev/null
+++ b/brouter-routing-app/src/main/res/values-de/strings.xml
@@ -0,0 +1,16 @@
+
+
+
+ - %d Segment
+ - %d Segmente
+
+ Download abbrechen
+ Profil importieren
+ %s downloaden
+ %s löschen
+ %s aktualisieren
+ Segmente auswählen
+ Download stoppen
+ Größe=%1$s\nFrei=%2$s
+ Segmente herunterladen
+
diff --git a/brouter-routing-app/src/main/res/values-el/strings.xml b/brouter-routing-app/src/main/res/values-el/strings.xml
new file mode 100644
index 0000000..0ef6b6c
--- /dev/null
+++ b/brouter-routing-app/src/main/res/values-el/strings.xml
@@ -0,0 +1,16 @@
+
+
+
+ - %d τμήμα
+ - %d τμήματα
+
+ Ακύρωση λήψης
+ Εισαγωγή προφίλ
+ Λήψη %s
+ Διαγραφή %s
+ Ενημέρωση %s
+ Επιλογή τμημάτων
+ Διακοπή λήψης
+ Μέγεθος=%1$s\nΕλεύθερο=%2$s
+ Λήψη τμημάτων
+
diff --git a/brouter-routing-app/src/main/res/values-es/strings.xml b/brouter-routing-app/src/main/res/values-es/strings.xml
new file mode 100644
index 0000000..3929ff0
--- /dev/null
+++ b/brouter-routing-app/src/main/res/values-es/strings.xml
@@ -0,0 +1,16 @@
+
+
+
+ - %d segmento
+ - %d segmentos
+
+ Cancelar descarga
+ Importar perfil
+ Descargar %s
+ Eliminar %s
+ Actualizar %s
+ Seleccionar segmentos
+ Detener descarga
+ Tamaño=%1$s\nGratis=%2$s
+ Descargar segmentos
+
diff --git a/brouter-routing-app/src/main/res/values-fr/strings.xml b/brouter-routing-app/src/main/res/values-fr/strings.xml
new file mode 100644
index 0000000..b390687
--- /dev/null
+++ b/brouter-routing-app/src/main/res/values-fr/strings.xml
@@ -0,0 +1,16 @@
+
+
+
+ - %d segment
+ - %d segments
+
+ Annuler le téléchargement
+ Importer le profil
+ Télécharger %s
+ Supprimer %s
+ Mettre à jour %s
+ Sélectionner les segments
+ Arrêter le téléchargement
+ Taille=%1$s\nGratuit=%2$s
+ Télécharger les segments
+
diff --git a/brouter-routing-app/src/main/res/values-it/strings.xml b/brouter-routing-app/src/main/res/values-it/strings.xml
new file mode 100644
index 0000000..10f29fe
--- /dev/null
+++ b/brouter-routing-app/src/main/res/values-it/strings.xml
@@ -0,0 +1,16 @@
+
+
+
+ - %d segmento
+ - %d segmenti
+
+ Annulla download
+ Importa profilo
+ Scarica %s
+ Elimina %s
+ Aggiorna %s
+ Seleziona segmenti
+ Interrompi download
+ Taglia=%1$s\nGratis=%2$s
+ Scarica segmenti
+
diff --git a/brouter-routing-app/src/main/res/values-nl/strings.xml b/brouter-routing-app/src/main/res/values-nl/strings.xml
new file mode 100644
index 0000000..300d668
--- /dev/null
+++ b/brouter-routing-app/src/main/res/values-nl/strings.xml
@@ -0,0 +1,16 @@
+
+
+
+ - %d segment
+ - %d segmenten
+
+ Download annuleren
+ Profiel importeren
+ Downloaden %s
+ Verwijderen %s
+ Bijwerken %s
+ Segmenten selecteren
+ Download stoppen
+ Grootte=%1$s\nGratis=%2$s
+ Segmenten downloaden
+
diff --git a/brouter-routing-app/src/main/res/values-pl/strings.xml b/brouter-routing-app/src/main/res/values-pl/strings.xml
new file mode 100644
index 0000000..2de0f3c
--- /dev/null
+++ b/brouter-routing-app/src/main/res/values-pl/strings.xml
@@ -0,0 +1,16 @@
+
+
+
+ - %d segment
+ - %d segmenty/ów
+
+ Anuluj pobieranie
+ Importuj profil
+ Pobierz %s
+ Usuń %s
+ Zaktualizuj %s
+ Wybierz segmenty
+ Zatrzymaj pobieranie
+ Rozmiar=%1$s\nDostępne=%2$s
+ Pobieranie segmentów
+
diff --git a/brouter-routing-app/src/main/res/values/donottranslate-strings.xml b/brouter-routing-app/src/main/res/values/donottranslate-strings.xml
new file mode 100644
index 0000000..254dd8f
--- /dev/null
+++ b/brouter-routing-app/src/main/res/values/donottranslate-strings.xml
@@ -0,0 +1,7 @@
+
+
+ BRouter
+ filename.brf
+ brouter_download
+ Downloads
+
diff --git a/brouter-routing-app/src/main/res/values/strings.xml b/brouter-routing-app/src/main/res/values/strings.xml
index 168a26a..3ddedd0 100644
--- a/brouter-routing-app/src/main/res/values/strings.xml
+++ b/brouter-routing-app/src/main/res/values/strings.xml
@@ -1,37 +1,16 @@
-
-
-
-
+
+
- %d segment
- %d segments
- BRouter
- Cancel Download
- Import Profile
- filename.brf
- Starting download…
- Cancelling…
+ Cancel download
+ Import profile
Download %s
Delete %s
Update %s
Select segments
- Stop Download
- Size=%s\nFree=%s
- brouter_download
- Download Segments
- Downloads
+ Stop download
+ Size=%1$s\nFree=%2$s
+ Download segments
diff --git a/brouter-server/src/main/java/btools/server/BRouter.java b/brouter-server/src/main/java/btools/server/BRouter.java
index dbfff6d..a6dfe10 100644
--- a/brouter-server/src/main/java/btools/server/BRouter.java
+++ b/brouter-server/src/main/java/btools/server/BRouter.java
@@ -1,11 +1,7 @@
package btools.server;
-import java.io.BufferedOutputStream;
-import java.io.DataOutputStream;
import java.io.File;
-import java.io.FileOutputStream;
import java.net.URLDecoder;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -14,11 +10,10 @@ import btools.router.OsmTrack;
import btools.router.RoutingContext;
import btools.router.RoutingEngine;
import btools.router.RoutingParamCollector;
-import btools.router.SearchBoundary;
public class BRouter {
public static void main(String[] args) throws Exception {
- if (args.length == 3) { // cgi-input-mode
+ if (args.length == 3 || args.length == 4) { // cgi-input-mode
try {
System.setProperty("segmentBaseDir", args[0]);
System.setProperty("profileBaseDir", args[1]);
@@ -28,19 +23,27 @@ public class BRouter {
int lonIdx = queryString.indexOf("lonlats=");
int sepIdx = queryString.indexOf("&", lonIdx);
- String lonlats = queryString.substring(lonIdx+8, sepIdx);
+ String lonlats = queryString.substring(lonIdx + 8, sepIdx);
RoutingContext rc = new RoutingContext();
RoutingParamCollector routingParamCollector = new RoutingParamCollector();
List wplist = routingParamCollector.getWayPointList(lonlats);
Map params = routingParamCollector.getUrlParams(queryString);
+ int engineMode = 0;
+ if (params.containsKey("engineMode")) {
+ engineMode = Integer.parseInt(params.get("engineMode"));
+ }
routingParamCollector.setParams(rc, wplist, params);
- // cgi-header
- System.out.println("Content-type: text/plain");
- System.out.println();
-
+ String exportName = null;
+ if (args.length == 4) {
+ exportName = args[3];
+ } else {
+ // cgi-header
+ System.out.println("Content-type: text/plain");
+ System.out.println();
+ }
long maxRunningTime = 60000; // the cgi gets a 1 Minute timeout
String sMaxRunningTime = System.getProperty("maxRunningTime");
@@ -48,9 +51,7 @@ public class BRouter {
maxRunningTime = Integer.parseInt(sMaxRunningTime) * 1000;
}
-
- RoutingEngine re = new RoutingEngine(null, null, new File(args[0]), wplist, rc);
-
+ RoutingEngine re = new RoutingEngine(exportName, null, new File(args[0]), wplist, rc, engineMode);
re.doRun(maxRunningTime);
if (re.getErrorMessage() != null) {
System.out.println(re.getErrorMessage());
@@ -65,96 +66,53 @@ public class BRouter {
System.out.println("Find routes in an OSM map");
System.out.println("usage: java -jar brouter.jar [parameter-list] [profile-parameter-list] ");
System.out.println(" or: java -cp %CLASSPATH% btools.server.BRouter > [parameter-list] [profile-parameter-list]");
- System.out.println(" or: java -jar brouter.jar ");
+ System.out.println(" or: java -jar brouter.jar [output-filename]");
System.exit(0);
}
- RoutingEngine re = null;
- if ("seed".equals(args[3])) {
- List wplist = new ArrayList<>();
- wplist.add(readPosition(args, 1, "from"));
- int searchRadius = Integer.parseInt(args[4]); // if = 0 search a 5x5 square
- String filename = SearchBoundary.getFileName(wplist.get(0));
- DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("traffic/" + filename)));
-
- for (int direction = 0; direction < 8; direction++) {
- RoutingContext rc = readRoutingContext(args);
- SearchBoundary boundary = new SearchBoundary(wplist.get(0), searchRadius, direction / 2);
- rc.trafficOutputStream = dos;
- rc.inverseDirection = (direction & 1) != 0;
- re = new RoutingEngine("mytrack", "mylog", new File(args[0]), wplist, rc);
- re.boundary = boundary;
- re.airDistanceCostFactor = rc.trafficDirectionFactor;
- rc.countTraffic = true;
- re.doSearch();
- if (re.getErrorMessage() != null) {
- break;
- }
- }
- dos.close();
- } else {
- int engineMode = 0;
- try {
- engineMode = Integer.parseInt(args[2]);
- } catch (NumberFormatException e) {
- }
-
- RoutingParamCollector routingParamCollector = new RoutingParamCollector();
- List wplist = routingParamCollector.getWayPointList(args[4]);
-
- System.setProperty("segmentBaseDir", args[0]);
- System.setProperty("profileBaseDir", args[1]);
- String moreParams = null;
- String profileParams = null;
- if (args.length >= 6) {
- moreParams = args[5];
- }
- if (args.length == 7) {
- profileParams = args[6];
- }
-
- RoutingContext rc = new RoutingContext();
- rc.localFunction = args[3];
- if (moreParams != null) {
- Map params = routingParamCollector.getUrlParams(moreParams);
- routingParamCollector.setParams(rc, wplist, params);
- }
- if (profileParams != null) {
- Map params = routingParamCollector.getUrlParams(profileParams);
- routingParamCollector.setProfileParams(rc, params);
- }
- try {
- if (engineMode==RoutingEngine.BROUTER_ENGINEMODE_GETELEV) {
- re = new RoutingEngine("testinfo", null, new File(args[0]), wplist, rc, engineMode);
- } else {
- re = new RoutingEngine("testtrack", null, new File(args[0]), wplist, rc, engineMode);
- }
- re.doRun(0);
- } catch (Exception e) {
- System.out.println(e.getMessage());
- }
+ int engineMode = 0;
+ try {
+ engineMode = Integer.parseInt(args[2]);
+ } catch (NumberFormatException e) {
}
- }
+ RoutingParamCollector routingParamCollector = new RoutingParamCollector();
+ List wplist = routingParamCollector.getWayPointList(args[4]);
- private static OsmNodeNamed readPosition(String[] args, int idx, String name) {
- OsmNodeNamed n = new OsmNodeNamed();
- n.name = name;
- n.ilon = (int) ((Double.parseDouble(args[idx]) + 180.) * 1000000. + 0.5);
- n.ilat = (int) ((Double.parseDouble(args[idx + 1]) + 90.) * 1000000. + 0.5);
- return n;
- }
-
- private static RoutingContext readRoutingContext(String[] args) {
- RoutingContext c = new RoutingContext();
- if (args.length > 5) {
- c.localFunction = args[5];
- if (args.length > 6) {
- c.setAlternativeIdx(Integer.parseInt(args[6]));
- }
+ System.setProperty("segmentBaseDir", args[0]);
+ System.setProperty("profileBaseDir", args[1]);
+ String moreParams = null;
+ String profileParams = null;
+ if (args.length >= 6) {
+ moreParams = args[5];
}
- c.memoryclass = (int) (Runtime.getRuntime().maxMemory() / 1024 / 1024);
- // c.startDirection= Integer.valueOf( 150 );
- return c;
+ if (args.length == 7) {
+ profileParams = args[6];
+ }
+
+ RoutingContext rc = new RoutingContext();
+ rc.localFunction = args[3];
+ if (moreParams != null) {
+ Map params = routingParamCollector.getUrlParams(moreParams);
+ routingParamCollector.setParams(rc, wplist, params);
+ }
+ if (profileParams != null) {
+ Map params = routingParamCollector.getUrlParams(profileParams);
+ routingParamCollector.setProfileParams(rc, params);
+ }
+ try {
+ RoutingEngine re = null;
+ if (engineMode == RoutingEngine.BROUTER_ENGINEMODE_GETELEV) {
+ re = new RoutingEngine("testinfo", null, new File(args[0]), wplist, rc, engineMode);
+ } else {
+ re = new RoutingEngine("testtrack", null, new File(args[0]), wplist, rc, engineMode);
+ }
+ re.doRun(0);
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ }
+
}
+
+
}
diff --git a/brouter-server/src/main/java/btools/server/RouteServer.java b/brouter-server/src/main/java/btools/server/RouteServer.java
index c0e5846..ba421f9 100644
--- a/brouter-server/src/main/java/btools/server/RouteServer.java
+++ b/brouter-server/src/main/java/btools/server/RouteServer.java
@@ -29,6 +29,7 @@ import btools.router.OsmTrack;
import btools.router.ProfileCache;
import btools.router.RoutingContext;
import btools.router.RoutingEngine;
+import btools.router.RoutingParamCollector;
import btools.server.request.ProfileUploadHandler;
import btools.server.request.RequestHandler;
import btools.server.request.ServerHandler;
@@ -146,7 +147,9 @@ public class RouteServer extends Thread implements Comparable {
}
String url = getline.split(" ")[1];
- Map params = getUrlParams(url);
+
+ RoutingParamCollector routingParamCollector = new RoutingParamCollector();
+ Map params = routingParamCollector.getUrlParams(url);
long maxRunningTime = getMaxRunningTime();
@@ -186,33 +189,17 @@ public class RouteServer extends Thread implements Comparable {
return;
}
RoutingContext rc = handler.readRoutingContext();
- List wplist = handler.readWayPointList();
+ List wplist = routingParamCollector.getWayPointList(params.get("lonlats"));
if (wplist.size() < 10) {
SuspectManager.nearRecentWps.add(wplist);
}
int engineMode = 0;
- for (Map.Entry e : params.entrySet()) {
- if ("engineMode".equals(e.getKey())) {
- engineMode = Integer.parseInt(e.getValue());
- } else if ("timode".equals(e.getKey())) {
- rc.turnInstructionMode = Integer.parseInt(e.getValue());
- } else if ("heading".equals(e.getKey())) {
- rc.startDirection = Integer.parseInt(e.getValue());
- rc.forceUseStartDirection = true;
- } else if (e.getKey().startsWith("profile:")) {
- if (rc.keyValues == null) {
- rc.keyValues = new HashMap<>();
- }
- rc.keyValues.put(e.getKey().substring(8), e.getValue());
- } else if (e.getKey().equals("straight")) {
- String[] sa = e.getValue().split(",");
- for (int i = 0; i < sa.length; i++) {
- int v = Integer.parseInt(sa[i]);
- if (wplist.size() > v) wplist.get(v).direct = true;
- }
- }
+ if (params.containsKey("engineMode")) {
+ engineMode = Integer.parseInt(params.get("engineMode"));
}
+ routingParamCollector.setParams(rc, wplist, params);
+
cr = new RoutingEngine(null, null, serviceContext.segmentDir, wplist, rc, engineMode);
cr.quite = true;
cr.doRun(maxRunningTime);
@@ -224,18 +211,29 @@ public class RouteServer extends Thread implements Comparable {
} else {
OsmTrack track = cr.getFoundTrack();
+ if (engineMode == 2) {
+ // no zip for this engineMode
+ encodings = null;
+ }
String headers = encodings == null || encodings.indexOf("gzip") < 0 ? null : "Content-Encoding: gzip\n";
writeHttpHeader(bw, handler.getMimeType(), handler.getFileName(), headers, HTTP_STATUS_OK);
- if (track != null) {
- if (headers != null) { // compressed
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- Writer w = new OutputStreamWriter(new GZIPOutputStream(baos), "UTF-8");
- w.write(handler.formatTrack(track));
- w.close();
- bw.flush();
- clientSocket.getOutputStream().write(baos.toByteArray());
- } else {
- bw.write(handler.formatTrack(track));
+ if (engineMode == 0) {
+ if (track != null) {
+ if (headers != null) { // compressed
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ Writer w = new OutputStreamWriter(new GZIPOutputStream(baos), "UTF-8");
+ w.write(handler.formatTrack(track));
+ w.close();
+ bw.flush();
+ clientSocket.getOutputStream().write(baos.toByteArray());
+ } else {
+ bw.write(handler.formatTrack(track));
+ }
+ }
+ } else if (engineMode == 2) {
+ String s = cr.getFoundInfo();
+ if (s != null) {
+ bw.write(s);
}
}
}
diff --git a/brouter-server/src/main/java/btools/server/request/RequestHandler.java b/brouter-server/src/main/java/btools/server/request/RequestHandler.java
index 5364c5b..6fbb816 100644
--- a/brouter-server/src/main/java/btools/server/request/RequestHandler.java
+++ b/brouter-server/src/main/java/btools/server/request/RequestHandler.java
@@ -1,9 +1,7 @@
package btools.server.request;
-import java.util.List;
import java.util.Map;
-import btools.router.OsmNodeNamed;
import btools.router.OsmTrack;
import btools.router.RoutingContext;
import btools.server.ServiceContext;
@@ -19,8 +17,6 @@ public abstract class RequestHandler {
public abstract RoutingContext readRoutingContext();
- public abstract List readWayPointList();
-
public abstract String formatTrack(OsmTrack track);
public abstract String getMimeType();
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 fb8f520..505fd2b 100644
--- a/brouter-server/src/main/java/btools/server/request/ServerHandler.java
+++ b/brouter-server/src/main/java/btools/server/request/ServerHandler.java
@@ -1,14 +1,12 @@
package btools.server.request;
-import java.io.BufferedWriter;
import java.io.File;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Map;
-import btools.router.OsmNodeNamed;
-import btools.router.OsmNogoPolygon;
+import btools.router.FormatCsv;
+import btools.router.FormatGpx;
+import btools.router.FormatJson;
+import btools.router.FormatKml;
import btools.router.OsmTrack;
import btools.router.RoutingContext;
import btools.server.ServiceContext;
@@ -62,59 +60,9 @@ public class ServerHandler extends RequestHandler {
}
rc.localFunction = profile;
- rc.setAlternativeIdx(Integer.parseInt(params.get("alternativeidx")));
-
- List poisList = readPoisList();
- rc.poipoints = poisList;
-
- List nogoList = readNogoList();
- List nogoPolygonsList = readNogoPolygons();
-
- if (nogoList != null) {
- RoutingContext.prepareNogoPoints(nogoList);
- rc.nogopoints = nogoList;
- }
-
- if (rc.nogopoints == null) {
- rc.nogopoints = nogoPolygonsList;
- } else if (nogoPolygonsList != null) {
- rc.nogopoints.addAll(nogoPolygonsList);
- }
-
return rc;
}
- @Override
- public List readWayPointList() {
- // lon,lat|...
- String lonLats = params.get("lonlats");
- if (lonLats == null) throw new IllegalArgumentException("lonlats parameter not set");
-
- String[] coords = lonLats.split("\\|");
- if (coords.length < 2)
- throw new IllegalArgumentException("we need two lat/lon points at least!");
-
- List wplist = new ArrayList<>();
- for (int i = 0; i < coords.length; i++) {
- String[] lonLat = coords[i].split(",");
- if (lonLat.length < 2)
- throw new IllegalArgumentException("we need two lat/lon points at least!");
- wplist.add(readPosition(lonLat[0], lonLat[1], "via" + i));
- if (lonLat.length > 2) {
- if (lonLat[2].equals("d")) {
- wplist.get(wplist.size()-1).direct = true;
- } else {
- wplist.get(wplist.size()-1).name = lonLat[2];
- }
- }
- }
-
- if (wplist.get(0).name.startsWith("via")) wplist.get(0).name = "from";
- if (wplist.get(wplist.size() - 1).name.startsWith("via")) wplist.get(wplist.size() - 1).name = "to";
-
- return wplist;
- }
-
@Override
public String formatTrack(OsmTrack track) {
String result;
@@ -130,23 +78,17 @@ public class ServerHandler extends RequestHandler {
}
if (format == null || "gpx".equals(format)) {
- result = track.formatAsGpx();
+ result = new FormatGpx(rc).format(track);
} else if ("kml".equals(format)) {
- result = track.formatAsKml();
+ result = new FormatKml(rc).format(track);
} else if ("geojson".equals(format)) {
- result = track.formatAsGeoJson();
+ result = new FormatJson(rc).format(track);
} else if ("csv".equals(format)) {
- try {
- StringWriter sw = new StringWriter();
- BufferedWriter bw = new BufferedWriter(sw);
- track.writeMessages(bw, rc);
- return sw.toString();
- } catch (Exception ex) {
- return "Error: " + ex.getMessage();
- }
+ result = new FormatCsv(rc).format(track);
} else {
System.out.println("unknown track format '" + format + "', using default");
- result = track.formatAsGpx();
+ //result = track.formatAsGpx();
+ result = new FormatGpx(rc).format(track);
}
return result;
@@ -191,115 +133,4 @@ public class ServerHandler extends RequestHandler {
return params.get("trackname") == null ? null : params.get("trackname").replaceAll("[^a-zA-Z0-9 \\._\\-]+", "");
}
- private static OsmNodeNamed readPosition(String vlon, String vlat, String name) {
- if (vlon == null) throw new IllegalArgumentException("lon " + name + " not found in input");
- if (vlat == null) throw new IllegalArgumentException("lat " + name + " not found in input");
-
- return readPosition(Double.parseDouble(vlon), Double.parseDouble(vlat), name);
- }
-
- private static OsmNodeNamed readPosition(double lon, double lat, String name) {
- OsmNodeNamed n = new OsmNodeNamed();
- n.name = name;
- n.ilon = (int) ((lon + 180.) * 1000000. + 0.5);
- n.ilat = (int) ((lat + 90.) * 1000000. + 0.5);
- return n;
- }
-
- private List readPoisList() {
- // lon,lat,name|...
- String pois = params.get("pois");
- if (pois == null) return null;
-
- String[] lonLatNameList = pois.split("\\|");
-
- List poisList = new ArrayList<>();
- for (int i = 0; i < lonLatNameList.length; i++) {
- String[] lonLatName = lonLatNameList[i].split(",");
-
- if (lonLatName.length != 3)
- continue;
-
- OsmNodeNamed n = new OsmNodeNamed();
- n.ilon = (int) ((Double.parseDouble(lonLatName[0]) + 180.) * 1000000. + 0.5);
- n.ilat = (int) ((Double.parseDouble(lonLatName[1]) + 90.) * 1000000. + 0.5);
- n.name = lonLatName[2];
- poisList.add(n);
- }
-
- return poisList;
- }
-
- private List readNogoList() {
- // lon,lat,radius|...
- String nogos = params.get("nogos");
- if (nogos == null) return null;
-
- String[] lonLatRadList = nogos.split("\\|");
-
- List nogoList = new ArrayList<>();
- for (int i = 0; i < lonLatRadList.length; i++) {
- String[] lonLatRad = lonLatRadList[i].split(",");
- String nogoWeight = "NaN";
- if (lonLatRad.length > 3) {
- nogoWeight = lonLatRad[3];
- }
- nogoList.add(readNogo(lonLatRad[0], lonLatRad[1], lonLatRad[2], nogoWeight));
- }
-
- return nogoList;
- }
-
- private static OsmNodeNamed readNogo(String lon, String lat, String radius, String nogoWeight) {
- double weight = "undefined".equals(nogoWeight) ? Double.NaN : Double.parseDouble(nogoWeight);
- return readNogo(Double.parseDouble(lon), Double.parseDouble(lat), Integer.parseInt(radius), weight);
- }
-
- private static OsmNodeNamed readNogo(double lon, double lat, int radius, double nogoWeight) {
- OsmNodeNamed n = new OsmNodeNamed();
- n.name = "nogo" + radius;
- n.ilon = (int) ((lon + 180.) * 1000000. + 0.5);
- n.ilat = (int) ((lat + 90.) * 1000000. + 0.5);
- n.isNogo = true;
- n.nogoWeight = nogoWeight;
- return n;
- }
-
- private List readNogoPolygons() {
- List result = new ArrayList<>();
- parseNogoPolygons(params.get("polylines"), result, false);
- parseNogoPolygons(params.get("polygons"), result, true);
- return result.size() > 0 ? result : null;
- }
-
- private static void parseNogoPolygons(String polygons, List result, boolean closed) {
- if (polygons != null) {
- String[] polygonList = polygons.split("\\|");
- for (int i = 0; i < polygonList.length; i++) {
- String[] lonLatList = polygonList[i].split(",");
- if (lonLatList.length > 1) {
- OsmNogoPolygon polygon = new OsmNogoPolygon(closed);
- int j;
- for (j = 0; j < 2 * (lonLatList.length / 2) - 1; ) {
- String slon = lonLatList[j++];
- String slat = lonLatList[j++];
- int lon = (int) ((Double.parseDouble(slon) + 180.) * 1000000. + 0.5);
- int lat = (int) ((Double.parseDouble(slat) + 90.) * 1000000. + 0.5);
- polygon.addVertex(lon, lat);
- }
-
- String nogoWeight = "NaN";
- if (j < lonLatList.length) {
- nogoWeight = lonLatList[j];
- }
- polygon.nogoWeight = Double.parseDouble(nogoWeight);
-
- if (polygon.points.size() > 0) {
- polygon.calcBoundingCircle();
- result.add(polygon);
- }
- }
- }
- }
- }
}
diff --git a/docs/Gemfile b/docs/Gemfile
index 7bfae82..587276e 100644
--- a/docs/Gemfile
+++ b/docs/Gemfile
@@ -27,3 +27,5 @@ end
# Performance-booster for watching directories on Windows
gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin]
+
+gem "webrick", "~> 1.8"
diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock
index 96e2833..068424c 100644
--- a/docs/Gemfile.lock
+++ b/docs/Gemfile.lock
@@ -249,6 +249,7 @@ GEM
unf_ext
unf_ext (0.0.8.2)
unicode-display_width (1.8.0)
+ webrick (1.8.1)
PLATFORMS
x86_64-linux
@@ -258,6 +259,7 @@ DEPENDENCIES
tzinfo (~> 1.2)
tzinfo-data
wdm (~> 0.1.1)
+ webrick (~> 1.8)
BUNDLED WITH
- 2.4.13
+ 2.4.20
diff --git a/docs/_README.md b/docs/_README.md
new file mode 100644
index 0000000..cdda75c
--- /dev/null
+++ b/docs/_README.md
@@ -0,0 +1,15 @@
+# BRouter Docs
+
+This documentation can be used to generate a static website using [jekyll](https://jekyllrb.com/).
+
+## Dependencies
+
+jekyll uses ruby and therefore installs dependencies using gem. It is recommended to use bundler to manage those dependencies.
+
+`bundle install` installs all dependencies. To update dependencies use `bundle update`.
+
+## Preview
+
+jekyll provides a built-in webserver which can be used for fast feedback during editing.
+
+`bundle exec jekyll serve`
diff --git a/docs/developers/environmental_considerations_and_pseudo_tags.md b/docs/developers/environmental_considerations_and_pseudo_tags.md
index 84a3344..aa4ef90 100644
--- a/docs/developers/environmental_considerations_and_pseudo_tags.md
+++ b/docs/developers/environmental_considerations_and_pseudo_tags.md
@@ -1,87 +1,108 @@
-Environmental considerations (penalties for traffic, noise, town, no river, no forest) are possible due to the creation of pseudo tags during processing OSM data by spatial SQL queries in https://github.com/abrensch/brouter/blob/master/misc/scripts/mapcreation/brouter.sql. During this processing, roads are extended by a 32 m buffer creating 64 m wide lines. Then it is calculated what percentage of such line is at a specific distance to a noise source or within a forest, for example. The percentage is converted to a factor and the factor is assigned to a class. Ways that pass through different environments and are represented by a single OSM way can be problematic because the class is always based on the average environment along an entire OSM way. For traffic, calculations are on another level of complexity.
+---
+parent: Developers
+---
+
+# Environmental considerations
+
+Environmental considerations (penalties for traffic, noise, town, no river, no forest) are possible due to the creation of pseudo tags during processing OSM data by spatial SQL queries in [brouter.sql](https://github.com/abrensch/brouter/blob/master/misc/scripts/mapcreation/brouter.sql). During this processing, roads are extended by a 32 m buffer creating 64 m wide lines. Then it is calculated what percentage of such line is at a specific distance to a noise source or within a forest, for example. The percentage is converted to a factor and the factor is assigned to a class. Ways that pass through different environments and are represented by a single OSM way can be problematic because the class is always based on the average environment along an entire OSM way. For traffic, calculations are on another level of complexity.
+
+### noise_class
+
+For proximity of noisy roads (secondary and higher). The noise factor represents the proportion of a road's buffer area that lies within the 64-meter buffer of noisy roads. This proportion is reduced:
-### consider_noise, noise_penalty
-For proximity of noisy roads (secondary and higher). The noise factor represents the proportion of a road's buffer area that lies within the 64-meter buffer of noisy roads. This proportion is reduced:
- for motorways and trunk roads with max speed < 105 by 1.5
-- for primary roads 2 times
-- 3 times if maxspeed is 75 - 105 for primary and secondary
-- other secondary roads 5 times
+- for primary roads 2 times
+- 3 times if maxspeed is 75 - 105 for primary and secondary
+- other secondary roads 5 times
-Noise class is roughly proportional to the noise factor:
+`noise_class` is roughly proportional to the noise factor:
-noise_factor = noise class
-- < 0.1 = '1'
-- < 0.25 = '2'
-- < 0.4 = '3'
-- < 0.55 = '4'
-- < 0.8 = '5'
-- ELSE = '6'
+| `noise_factor` | `noise_class` |
+| -------------- | ------------- |
+| < 0.1 | 1 |
+| < 0.25 | 2 |
+| < 0.4 | 3 |
+| < 0.55 | 4 |
+| < 0.8 | 5 |
+| ELSE | 6 |
-To be classified as noise class 6, a way must be less than 13 m on average from the middle of the carriageway of a motorway with a maximum speed exceeding 105. For a class 5, the distance must be up to 35 meters. (1 - noise factor) * 64 m for a given class determines the distance
+To be classified as noise class 6, a way must be less than 13 m on average from the middle of the carriageway of a motorway with a maximum speed exceeding 105. For a class 5, the distance must be up to 35 meters. (1 - noise_factor) \* 64 m for a given class determines the distance
-**Max noise class:**
-| Max speed | Motorway, trunk |Primary|Secondary |
-|--- |:---: |:---: |:---: |
-| >105 |6 |4 | 3 |
-| 105 |5 |4 |3 |
-| 75 |5 |3 |2 |
+| highway | maxspeed | max `noise_class` |
+| -------------- | -------- | ----------------- |
+| motorway,trunk | > 105 | 6 |
+| motorway,trunk | 105 | 5 |
+| motorway,trunk | 75 | 5 |
+| primary | > 105 | 4 |
+| primary | 105 | 4 |
+| primary | 75 | 3 |
+| secondary | > 105 | 3 |
+| secondary | 105 | 3 |
+| secondary | 75 | 2 |
+### river_class
-### consider_river, no_river_penalty
OSM data recognized as river:
+
- waterway: river, canal
- natural: water (except wastewater)
Waterways have 32 m wide buffers. Water areas have 77 m wide buffers.
-river_see = river class
-- < 0.17 = '1'
-- < 0.35 = '2'
-- < 0.57 = '3'
-- < 0.80 = '4'
-- < 0.95 = '5'
-- ELSE = '6'
+| `river_see` | `river_class` |
+| ----------- | ------------- |
+| < 0.1 | 1 |
+| < 0.3 | 2 |
+| < 0.5 | 3 |
+| < 0.8 | 4 |
+| < 0.9 | 5 |
+| ELSE | 6 |
+
+### forest_class
+
+OSM data recognized as forest:
-### consider_forest, no_forest_penalty
-OSM data recognized as forest:
- landuse: forest, allotments, flowerbed, orchard, vineyard, recreation_ground, village_green
- leisure: garden, park, nature_reserve
-
+
No forest buffers are used.
Imagine you trace the way with a pencil drawing lines 62 meters wide. Then estimated_forest_class=6 corresponds to the case that at least 98% of the line is in the woodland. This number is called a green factor.
-green_factor = forest class
-- < 0.1 = NULL
-- < 0.2 = '1'
-- < 0.4 = '2'
-- < 0.6 = '3'
-- < 0.8 = '4'
-- < 0.98 = '5'
-- ELSE = '6'
+| `green_factor` | `forest_class` |
+| -------------- | -------------- |
+| < 0.1 | NULL |
+| < 0.2 | 1 |
+| < 0.4 | 2 |
+| < 0.6 | 3 |
+| < 0.8 | 4 |
+| < 0.98 | 5 |
+| ELSE | 6 |
+### town_class
-
-### consider_town, town_penalty
Town_class is determined by population data from OSM.
-Class
-- 1 = 50-80 k people
-- 2 = 80-150 k people
-- 3 = 150 - 400 k people
-- 4 = 400 - 1,000 k people
-- 5 = 1 - 2 million people
-- 6 = > 2 million people
+| population | `town_class` |
+| ------------------ | ------------ |
+| < 80 k people | 1 |
+| < 150 k people | 2 |
+| < 400 k people | 3 |
+| < 1 million people | 4 |
+| < 2 million people | 5 |
+| > 2 million people | 6 |
+
+### traffic_class
-### consider_traffic, traffic_penalty
(modified copy from the sql file).
OSM data used to estimate the traffic:
-- population of towns (+ distance from position to the towns)
-- size of industrial areas (landuse=industrial) and distance to them. Not considered: solar & wind farms.
-- airports international
-- motorway and trunk road density - traffic on motorways decreases traffic on primary/secondary/tertiary. Calculated on a grid (100 km^2)
-- density of highways (tertiary and higher) calculated on a grid (100 km^2). Traffic decreases when more such roads are available. Exceptions: near junctions between motorways and other roads the traffic increases on these roads.
-- mountain-ranges calculated as density of peaks > 400 m traffic is generally on highways in such regions higher as only generated by the local population or industrial areas
+
+- population of towns (+ distance from position to the towns)
+- size of industrial areas (landuse=industrial) and distance to them. Not considered: solar & wind farms.
+- airports international
+- motorway and trunk road density - traffic on motorways decreases traffic on primary/secondary/tertiary. Calculated on a grid (100 km^2)
+- density of highways (tertiary and higher) calculated on a grid (100 km^2). Traffic decreases when more such roads are available. Exceptions: near junctions between motorways and other roads the traffic increases on these roads.
+- mountain-ranges calculated as density of peaks > 400 m traffic is generally on highways in such regions higher as only generated by the local population or industrial areas
- calculate traffic from the population (for each segment of type primary secondary tertiary)
-- SUM of (population of each town < 100 km) / ( town-radius + 2500 + dist(segment-position to the town) ** 2 )
-- town-radius is calculated as sqrt(population)
+- SUM of (population of each town < 100 km) / ( town-radius + 2500 + dist(segment-position to the town) \*\* 2 )
+- town-radius is calculated as sqrt(population)