Compare commits

...

10 Commits

Author SHA1 Message Date
afischerdev
e031835592
Merge pull request #780 from devemux86/dependencies
Some checks failed
Docker / build (push) Failing after 2m24s
Java CI with Gradle / build (push) Has been cancelled
Update Android app dependencies

@devemux86
Many thanks for cooperation
2025-04-17 14:37:44 +02:00
Emux
bffcae48ea
Update Android app dependencies 2025-04-17 14:10:42 +03:00
afischerdev
89be5f58dd
Merge pull request #776 from afischerdev/merge_via
Added export for corrected Via Points
2025-04-12 16:19:39 +02:00
afischerdev
64560d26c0
Merge pull request #774 from afischerdev/avoid-uturns
Added a switch to avoid u-turns
2025-04-12 16:14:25 +02:00
afischerdev
7e117d9675 added export formats 2025-04-05 18:09:15 +02:00
afischerdev
2682981da9 added export for corrected via points 2025-04-05 18:08:46 +02:00
afischerdev
e3361cc113
Merge pull request #775 from Nitue/rfc7230-header-delimiter
RFC7230 compliant HTTP header delimiter

@Nitue
Thank you for your cooperation
2025-04-05 13:00:46 +02:00
afischerdev
02733ffbec reactivated end distance control 2025-04-05 12:29:55 +02:00
Nitue
acbda6c3e7 RFC7230 compliant HTTP header delimiter
Changes HTTP header endings from LF to CRLF.

RFC7230 states that headers are separated by CRLF. Brouter currently
uses only LF. Most recipients probably accept LF only, but some are
strict about this.
2025-04-05 01:00:57 +03:00
afischerdev
68b6edc580 added switch to avoid u-turns 2025-04-02 18:58:31 +02:00
11 changed files with 107 additions and 26 deletions

View File

@ -197,25 +197,28 @@ public class FormatGpx extends Formatter {
for (int i = 0; i <= t.pois.size() - 1; i++) { for (int i = 0; i <= t.pois.size() - 1; i++) {
OsmNodeNamed poi = t.pois.get(i); OsmNodeNamed poi = t.pois.get(i);
formatWaypointGpx(sb, poi); formatWaypointGpx(sb, poi, "poi");
} }
if (t.exportWaypoints) { if (t.exportWaypoints) {
for (int i = 0; i <= t.matchedWaypoints.size() - 1; i++) { for (int i = 0; i <= t.matchedWaypoints.size() - 1; i++) {
MatchedWaypoint wt = t.matchedWaypoints.get(i); MatchedWaypoint wt = t.matchedWaypoints.get(i);
sb.append(" <wpt lon=\"").append(formatILon(wt.waypoint.ilon)).append("\" lat=\"")
.append(formatILat(wt.waypoint.ilat)).append("\">\n")
.append(" <name>").append(StringUtils.escapeXml10(wt.name)).append("</name>\n");
if (i == 0) { if (i == 0) {
sb.append(" <type>from</type>\n"); formatWaypointGpx(sb, wt, "from");
} else if (i == t.matchedWaypoints.size() - 1) { } else if (i == t.matchedWaypoints.size() - 1) {
sb.append(" <type>to</type>\n"); formatWaypointGpx(sb, wt, "to");
} else { } else {
sb.append(" <type>via</type>\n"); formatWaypointGpx(sb, wt, "via");
}
sb.append(" </wpt>\n");
} }
} }
}
if (t.exportCorrectedWaypoints && t.correctedWaypoints != null) {
for (int i = 0; i <= t.correctedWaypoints.size() - 1; i++) {
OsmNodeNamed n = t.correctedWaypoints.get(i);
formatWaypointGpx(sb, n, "via_corr");
}
}
sb.append(" <trk>\n"); sb.append(" <trk>\n");
if (turnInstructionMode == 9 if (turnInstructionMode == 9
|| turnInstructionMode == 2 || turnInstructionMode == 2
@ -454,7 +457,7 @@ public class FormatGpx extends Formatter {
StringWriter sw = new StringWriter(8192); StringWriter sw = new StringWriter(8192);
BufferedWriter bw = new BufferedWriter(sw); BufferedWriter bw = new BufferedWriter(sw);
formatGpxHeader(bw); formatGpxHeader(bw);
formatWaypointGpx(bw, n); formatWaypointGpx(bw, n, null);
formatGpxFooter(bw); formatGpxFooter(bw);
bw.close(); bw.close();
sw.close(); sw.close();
@ -477,7 +480,7 @@ public class FormatGpx extends Formatter {
sb.append("</gpx>\n"); sb.append("</gpx>\n");
} }
public void formatWaypointGpx(BufferedWriter sb, OsmNodeNamed n) throws IOException { public void formatWaypointGpx(BufferedWriter sb, OsmNodeNamed n, String type) throws IOException {
sb.append(" <wpt lon=\"").append(formatILon(n.ilon)).append("\" lat=\"") sb.append(" <wpt lon=\"").append(formatILon(n.ilon)).append("\" lat=\"")
.append(formatILat(n.ilat)).append("\">"); .append(formatILat(n.ilat)).append("\">");
if (n.getSElev() != Short.MIN_VALUE) { if (n.getSElev() != Short.MIN_VALUE) {
@ -489,6 +492,24 @@ public class FormatGpx extends Formatter {
if (n.nodeDescription != null && rc != null) { if (n.nodeDescription != null && rc != null) {
sb.append("<desc>").append(rc.expctxWay.getKeyValueDescription(false, n.nodeDescription)).append("</desc>"); sb.append("<desc>").append(rc.expctxWay.getKeyValueDescription(false, n.nodeDescription)).append("</desc>");
} }
if (type != null) {
sb.append("<type>").append(type).append("</type>");
}
sb.append("</wpt>\n");
}
public void formatWaypointGpx(BufferedWriter sb, MatchedWaypoint wp, String type) throws IOException {
sb.append(" <wpt lon=\"").append(formatILon(wp.waypoint.ilon)).append("\" lat=\"")
.append(formatILat(wp.waypoint.ilat)).append("\">");
if (wp.waypoint.getSElev() != Short.MIN_VALUE) {
sb.append("<ele>").append("" + wp.waypoint.getElev()).append("</ele>");
}
if (wp.name != null) {
sb.append("<name>").append(StringUtils.escapeXml10(wp.name)).append("</name>");
}
if (type != null) {
sb.append("<type>").append(type).append("</type>");
}
sb.append("</wpt>\n"); sb.append("</wpt>\n");
} }

View File

@ -126,7 +126,7 @@ public class FormatJson extends Formatter {
sb.append(" ]\n"); sb.append(" ]\n");
sb.append(" }\n"); sb.append(" }\n");
if (t.exportWaypoints || !t.pois.isEmpty()) { if (t.exportWaypoints || t.exportCorrectedWaypoints || !t.pois.isEmpty()) {
sb.append(" },\n"); sb.append(" },\n");
for (int i = 0; i <= t.pois.size() - 1; i++) { for (int i = 0; i <= t.pois.size() - 1; i++) {
OsmNodeNamed poi = t.pois.get(i); OsmNodeNamed poi = t.pois.get(i);
@ -137,6 +137,7 @@ public class FormatJson extends Formatter {
sb.append(" \n"); sb.append(" \n");
} }
if (t.exportWaypoints) { if (t.exportWaypoints) {
if (!t.pois.isEmpty()) sb.append(" ,\n");
for (int i = 0; i <= t.matchedWaypoints.size() - 1; i++) { for (int i = 0; i <= t.matchedWaypoints.size() - 1; i++) {
String type; String type;
if (i == 0) { if (i == 0) {
@ -155,6 +156,19 @@ public class FormatJson extends Formatter {
sb.append(" \n"); sb.append(" \n");
} }
} }
if (t.exportCorrectedWaypoints) {
if (t.exportWaypoints) sb.append(" ,\n");
for (int i = 0; i <= t.correctedWaypoints.size() - 1; i++) {
String type = "via_corr";
OsmNodeNamed wp = t.correctedWaypoints.get(i);
addFeature(sb, type, wp.name, wp.ilat, wp.ilon, wp.getSElev());
if (i < t.correctedWaypoints.size() - 1) {
sb.append(",");
}
sb.append(" \n");
}
}
} else { } else {
sb.append(" }\n"); sb.append(" }\n");
} }

View File

@ -43,7 +43,7 @@ public class FormatKml extends Formatter {
sb.append(" </LineString>\n"); sb.append(" </LineString>\n");
sb.append(" </Placemark>\n"); sb.append(" </Placemark>\n");
sb.append(" </Folder>\n"); sb.append(" </Folder>\n");
if (t.exportWaypoints || !t.pois.isEmpty()) { if (t.exportWaypoints || t.exportCorrectedWaypoints || !t.pois.isEmpty()) {
if (!t.pois.isEmpty()) { if (!t.pois.isEmpty()) {
sb.append(" <Folder>\n"); sb.append(" <Folder>\n");
sb.append(" <name>poi</name>\n"); sb.append(" <name>poi</name>\n");
@ -62,6 +62,10 @@ public class FormatKml extends Formatter {
} }
createFolder(sb, "end", t.matchedWaypoints.subList(size - 1, size)); createFolder(sb, "end", t.matchedWaypoints.subList(size - 1, size));
} }
if (t.exportCorrectedWaypoints) {
int size = t.correctedWaypoints.size();
createViaFolder(sb, "via_cor", t.correctedWaypoints.subList(0, size));
}
} }
sb.append(" </Document>\n"); sb.append(" </Document>\n");
sb.append("</kml>\n"); sb.append("</kml>\n");
@ -79,6 +83,16 @@ public class FormatKml extends Formatter {
sb.append(" </Folder>\n"); sb.append(" </Folder>\n");
} }
private void createViaFolder(StringBuilder sb, String type, List<OsmNodeNamed> waypoints) {
sb.append(" <Folder>\n");
sb.append(" <name>" + type + "</name>\n");
for (int i = 0; i < waypoints.size(); i++) {
OsmNodeNamed wp = waypoints.get(i);
createPlaceMark(sb, wp.name, wp.ilat, wp.ilon);
}
sb.append(" </Folder>\n");
}
private void createPlaceMark(StringBuilder sb, String name, int ilat, int ilon) { private void createPlaceMark(StringBuilder sb, String name, int ilat, int ilon) {
sb.append(" <Placemark>\n"); sb.append(" <Placemark>\n");
sb.append(" <name>" + StringUtils.escapeXml10(name) + "</name>\n"); sb.append(" <name>" + StringUtils.escapeXml10(name) + "</name>\n");

View File

@ -61,7 +61,9 @@ public final class OsmTrack {
public String name = "unset"; public String name = "unset";
protected List<MatchedWaypoint> matchedWaypoints; protected List<MatchedWaypoint> matchedWaypoints;
protected List<OsmNodeNamed> correctedWaypoints;
public boolean exportWaypoints = false; public boolean exportWaypoints = false;
public boolean exportCorrectedWaypoints = false;
public void addNode(OsmPathElement node) { public void addNode(OsmPathElement node) {
nodes.add(0, node); nodes.add(0, node);

View File

@ -77,6 +77,7 @@ public final class RoutingContext {
public double waypointCatchingRange; public double waypointCatchingRange;
public boolean correctMisplacedViaPoints; public boolean correctMisplacedViaPoints;
public double correctMisplacedViaPointsDistance; public double correctMisplacedViaPointsDistance;
public boolean continueStraight;
public boolean useDynamicDistance; public boolean useDynamicDistance;
public boolean buildBeelineOnRange; public boolean buildBeelineOnRange;
@ -126,6 +127,8 @@ public final class RoutingContext {
correctMisplacedViaPoints = 0.f != expctxGlobal.getVariableValue("correctMisplacedViaPoints", 1.f); correctMisplacedViaPoints = 0.f != expctxGlobal.getVariableValue("correctMisplacedViaPoints", 1.f);
correctMisplacedViaPointsDistance = expctxGlobal.getVariableValue("correctMisplacedViaPointsDistance", 0.f); // 0 == don't use distance correctMisplacedViaPointsDistance = expctxGlobal.getVariableValue("correctMisplacedViaPointsDistance", 0.f); // 0 == don't use distance
continueStraight = 0.f != expctxGlobal.getVariableValue("continueStraight", 0.f);
// process tags not used in the profile (to have them in the data-tab) // process tags not used in the profile (to have them in the data-tab)
processUnusedTags = 0.f != expctxGlobal.getVariableValue("processUnusedTags", 0.f); processUnusedTags = 0.f != expctxGlobal.getVariableValue("processUnusedTags", 0.f);
@ -221,6 +224,7 @@ public final class RoutingContext {
public String outputFormat = "gpx"; public String outputFormat = "gpx";
public boolean exportWaypoints = false; public boolean exportWaypoints = false;
public boolean exportCorrectedWaypoints = false;
public OsmPrePath firstPrePath; public OsmPrePath firstPrePath;

View File

@ -41,6 +41,7 @@ public class RoutingEngine extends Thread {
private boolean finished = false; private boolean finished = false;
protected List<OsmNodeNamed> waypoints = null; protected List<OsmNodeNamed> waypoints = null;
protected List<OsmNodeNamed> correctedWaypoints = null;
List<OsmNodeNamed> extraWaypoints = null; List<OsmNodeNamed> extraWaypoints = null;
protected List<MatchedWaypoint> matchedWaypoints; protected List<MatchedWaypoint> matchedWaypoints;
private int linksProcessed = 0; private int linksProcessed = 0;
@ -262,6 +263,7 @@ public class RoutingEngine extends Thread {
} }
oldTrack = null; oldTrack = null;
track.exportWaypoints = routingContext.exportWaypoints; track.exportWaypoints = routingContext.exportWaypoints;
track.exportCorrectedWaypoints = routingContext.exportCorrectedWaypoints;
filename = outfileBase + i + "." + routingContext.outputFormat; filename = outfileBase + i + "." + routingContext.outputFormat;
switch (routingContext.outputFormat) { switch (routingContext.outputFormat) {
case "gpx": case "gpx":
@ -975,6 +977,10 @@ public class RoutingEngine extends Thread {
hasDirectRouting = true; hasDirectRouting = true;
} }
} }
for (MatchedWaypoint mwp : matchedWaypoints) {
//System.out.println(FormatGpx.getWaypoint(mwp.waypoint.ilon, mwp.waypoint.ilat, mwp.name, null));
//System.out.println(FormatGpx.getWaypoint(mwp.crosspoint.ilon, mwp.crosspoint.ilat, mwp.name+"_cp", null));
}
routingContext.hasDirectRouting = hasDirectRouting; routingContext.hasDirectRouting = hasDirectRouting;
@ -995,7 +1001,7 @@ public class RoutingEngine extends Thread {
} else { } else {
seg = searchTrack(matchedWaypoints.get(i), matchedWaypoints.get(i + 1), i == matchedWaypoints.size() - 2 ? nearbyTrack : null, refTracks[i]); seg = searchTrack(matchedWaypoints.get(i), matchedWaypoints.get(i + 1), i == matchedWaypoints.size() - 2 ? nearbyTrack : null, refTracks[i]);
wptIndex = i; wptIndex = i;
if (engineMode == BROUTER_ENGINEMODE_ROUNDTRIP) { if (routingContext.continueStraight) {
if (i < matchedWaypoints.size() - 2) { if (i < matchedWaypoints.size() - 2) {
OsmNode lastPoint = seg.containsNode(matchedWaypoints.get(i+1).node1) ? matchedWaypoints.get(i+1).node1 : matchedWaypoints.get(i+1).node2; OsmNode lastPoint = seg.containsNode(matchedWaypoints.get(i+1).node1) ? matchedWaypoints.get(i+1).node1 : matchedWaypoints.get(i+1).node2;
OsmNodeNamed nogo = new OsmNodeNamed(lastPoint); OsmNodeNamed nogo = new OsmNodeNamed(lastPoint);
@ -1030,6 +1036,7 @@ public class RoutingEngine extends Thread {
matchedWaypoints.get(matchedWaypoints.size() - 1).indexInTrack = totaltrack.nodes.size() - 1; matchedWaypoints.get(matchedWaypoints.size() - 1).indexInTrack = totaltrack.nodes.size() - 1;
totaltrack.matchedWaypoints = matchedWaypoints; totaltrack.matchedWaypoints = matchedWaypoints;
totaltrack.correctedWaypoints = correctedWaypoints;
totaltrack.processVoiceHints(routingContext); totaltrack.processVoiceHints(routingContext);
totaltrack.prepareSpeedProfile(routingContext); totaltrack.prepareSpeedProfile(routingContext);
@ -1137,7 +1144,12 @@ public class RoutingEngine extends Thread {
indexfore++; indexfore++;
if (routingContext.correctMisplacedViaPointsDistance > 0 && if (routingContext.correctMisplacedViaPointsDistance > 0 &&
wayDistance > routingContext.correctMisplacedViaPointsDistance) break; wayDistance > routingContext.correctMisplacedViaPointsDistance) {
removeVoiceHintList.clear();
removeBackList.clear();
removeForeList.clear();
return false;
}
} }
@ -1183,6 +1195,13 @@ public class RoutingEngine extends Thread {
setNewVoiceHint(t, last, lastJunctions, newJunction, newTarget); setNewVoiceHint(t, last, lastJunctions, newJunction, newTarget);
if (correctedWaypoints == null) correctedWaypoints = new ArrayList<>();
OsmNodeNamed n = new OsmNodeNamed();
n.ilon = newJunction.getILon();
n.ilat = newJunction.getILat();
n.name = startWp.name + "_corr";
correctedWaypoints.add(n);
return true; return true;
} }
return false; return false;

View File

@ -227,6 +227,8 @@ public class RoutingParamCollector {
} }
} else if (key.equals("exportWaypoints")) { } else if (key.equals("exportWaypoints")) {
rctx.exportWaypoints = (Integer.parseInt(value) == 1); rctx.exportWaypoints = (Integer.parseInt(value) == 1);
} else if (key.equals("exportCorrectedWaypoints")) {
rctx.exportCorrectedWaypoints = (Integer.parseInt(value) == 1);
} else if (key.equals("format")) { } else if (key.equals("format")) {
rctx.outputFormat = ((String) value).toLowerCase(); rctx.outputFormat = ((String) value).toLowerCase();
} else if (key.equals("trackFormat")) { } else if (key.equals("trackFormat")) {

View File

@ -101,8 +101,8 @@ repositories {
dependencies { dependencies {
implementation 'androidx.appcompat:appcompat:1.7.0' implementation 'androidx.appcompat:appcompat:1.7.0'
implementation "androidx.constraintlayout:constraintlayout:2.1.4" implementation "androidx.constraintlayout:constraintlayout:2.2.1"
implementation 'androidx.work:work-runtime:2.9.0' implementation 'androidx.work:work-runtime:2.10.0'
implementation 'com.google.android.material:material:1.12.0' implementation 'com.google.android.material:material:1.12.0'
implementation project(':brouter-mapaccess') implementation project(':brouter-mapaccess')
@ -115,7 +115,7 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit:1.2.1' androidTestImplementation 'androidx.test.ext:junit:1.2.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
androidTestImplementation 'androidx.work:work-testing:2.9.0' androidTestImplementation 'androidx.work:work-testing:2.10.0'
} }
gradle.projectsEvaluated { gradle.projectsEvaluated {

View File

@ -161,6 +161,7 @@ public class BRouterWorker {
track = cr.getFoundTrack(); track = cr.getFoundTrack();
if (track != null) { if (track != null) {
track.exportWaypoints = rc.exportWaypoints; track.exportWaypoints = rc.exportWaypoints;
track.exportCorrectedWaypoints = rc.exportCorrectedWaypoints;
if (pathToFileResult == null) { if (pathToFileResult == null) {
switch (writeFromat) { switch (writeFromat) {
case OUTPUT_FORMAT_KML: case OUTPUT_FORMAT_KML:

View File

@ -160,8 +160,8 @@ public class RouteServer extends Thread implements Comparable<RouteServer> {
} else if (url.startsWith(PROFILE_UPLOAD_URL)) { } else if (url.startsWith(PROFILE_UPLOAD_URL)) {
if (getline.startsWith("OPTIONS")) { if (getline.startsWith("OPTIONS")) {
// handle CORS preflight request (Safari) // handle CORS preflight request (Safari)
String corsHeaders = "Access-Control-Allow-Methods: GET, POST\n" String corsHeaders = "Access-Control-Allow-Methods: GET, POST\r\n"
+ "Access-Control-Allow-Headers: Content-Type\n"; + "Access-Control-Allow-Headers: Content-Type\r\n";
writeHttpHeader(bw, "text/plain", null, corsHeaders, HTTP_STATUS_OK); writeHttpHeader(bw, "text/plain", null, corsHeaders, HTTP_STATUS_OK);
bw.flush(); bw.flush();
return; return;
@ -220,7 +220,7 @@ public class RouteServer extends Thread implements Comparable<RouteServer> {
// no zip for this engineMode // no zip for this engineMode
encodings = null; encodings = null;
} }
String headers = encodings == null || encodings.indexOf("gzip") < 0 ? null : "Content-Encoding: gzip\n"; String headers = encodings == null || encodings.indexOf("gzip") < 0 ? null : "Content-Encoding: gzip\r\n";
writeHttpHeader(bw, handler.getMimeType(), handler.getFileName(), headers, HTTP_STATUS_OK); writeHttpHeader(bw, handler.getMimeType(), handler.getFileName(), headers, HTTP_STATUS_OK);
if (engineMode == RoutingEngine.BROUTER_ENGINEMODE_ROUTING || if (engineMode == RoutingEngine.BROUTER_ENGINEMODE_ROUTING ||
engineMode == RoutingEngine.BROUTER_ENGINEMODE_ROUNDTRIP) { engineMode == RoutingEngine.BROUTER_ENGINEMODE_ROUNDTRIP) {
@ -407,17 +407,17 @@ public class RouteServer extends Thread implements Comparable<RouteServer> {
private static void writeHttpHeader(BufferedWriter bw, String mimeType, String fileName, String headers, String status) throws IOException { private static void writeHttpHeader(BufferedWriter bw, String mimeType, String fileName, String headers, String status) throws IOException {
// http-header // http-header
bw.write(String.format("HTTP/1.1 %s\n", status)); bw.write(String.format("HTTP/1.1 %s\r\n", status));
bw.write("Connection: close\n"); bw.write("Connection: close\r\n");
bw.write("Content-Type: " + mimeType + "; charset=utf-8\n"); bw.write("Content-Type: " + mimeType + "; charset=utf-8\r\n");
if (fileName != null) { if (fileName != null) {
bw.write("Content-Disposition: attachment; filename=\"" + fileName + "\"\n"); bw.write("Content-Disposition: attachment; filename=\"" + fileName + "\"\r\n");
} }
bw.write("Access-Control-Allow-Origin: *\n"); bw.write("Access-Control-Allow-Origin: *\r\n");
if (headers != null) { if (headers != null) {
bw.write(headers); bw.write(headers);
} }
bw.write("\n"); bw.write("\r\n");
} }
private static void cleanupThreadQueue(Queue<RouteServer> threadQueue) { private static void cleanupThreadQueue(Queue<RouteServer> threadQueue) {

View File

@ -78,6 +78,10 @@ public class ServerHandler extends RequestHandler {
if (exportWaypointsStr != null && Integer.parseInt(exportWaypointsStr) != 0) { if (exportWaypointsStr != null && Integer.parseInt(exportWaypointsStr) != 0) {
track.exportWaypoints = true; track.exportWaypoints = true;
} }
exportWaypointsStr = params.get("exportCorrectedWaypoints");
if (exportWaypointsStr != null && Integer.parseInt(exportWaypointsStr) != 0) {
track.exportCorrectedWaypoints = true;
}
if (format == null || "gpx".equals(format)) { if (format == null || "gpx".equals(format)) {
result = new FormatGpx(rc).format(track); result = new FormatGpx(rc).format(track);