Merge branch 'abrensch:master' into master
This commit is contained in:
commit
c616bccabe
145 changed files with 6174 additions and 3408 deletions
98
.github/workflows/docker-publish.yml
vendored
Normal file
98
.github/workflows/docker-publish.yml
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
name: Docker
|
||||
|
||||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '21 9 * * *'
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
# Publish semver tags as releases.
|
||||
tags: [ 'v*.*.*' ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
|
||||
env:
|
||||
# Use docker.io for Docker Hub if empty
|
||||
REGISTRY: ghcr.io
|
||||
# github.repository as <account>/<repo>
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
# This is used to complete the identity challenge
|
||||
# with sigstore/fulcio when running outside of PRs.
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Install the cosign tool except on PR
|
||||
# https://github.com/sigstore/cosign-installer
|
||||
- name: Install cosign
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: sigstore/cosign-installer@6e04d228eb30da1757ee4e1dd75a0ec73a653e06 #v3.1.1
|
||||
with:
|
||||
cosign-release: 'v2.1.1'
|
||||
|
||||
# Set up BuildKit Docker container builder to be able to build
|
||||
# multi-platform images and export cache
|
||||
# https://github.com/docker/setup-buildx-action
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
|
||||
|
||||
# Login against a Docker registry except on PR
|
||||
# https://github.com/docker/login-action
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Extract metadata (tags, labels) for Docker
|
||||
# https://github.com/docker/metadata-action
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
|
||||
# Build and push Docker image with Buildx (don't push on PR)
|
||||
# https://github.com/docker/build-push-action
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
# Sign the resulting Docker image digest except on PRs.
|
||||
# This will only write to the public Rekor transparency log when the Docker
|
||||
# repository is public to avoid leaking data. If you would like to publish
|
||||
# transparency data even for private images, pass --force to cosign below.
|
||||
# https://github.com/sigstore/cosign
|
||||
# - name: Sign the published Docker image
|
||||
# if: ${{ github.event_name != 'pull_request' }}
|
||||
# env:
|
||||
# # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable
|
||||
# TAGS: ${{ steps.meta.outputs.tags }}
|
||||
# DIGEST: ${{ steps.build-and-push.outputs.digest }}
|
||||
# # This step uses the identity token to provision an ephemeral certificate
|
||||
# # against the sigstore community Fulcio instance.
|
||||
# run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST}
|
||||
14
.github/workflows/gradle-publish.yml
vendored
14
.github/workflows/gradle-publish.yml
vendored
|
|
@ -4,7 +4,7 @@
|
|||
name: Gradle Package
|
||||
|
||||
on:
|
||||
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
|
|
@ -18,13 +18,13 @@ jobs:
|
|||
packages: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v3
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
|
||||
settings-path: ${{ github.workspace }} # location for the settings.xml file
|
||||
|
||||
|
|
@ -38,7 +38,7 @@ jobs:
|
|||
ORG_GRADLE_PROJECT_RELEASE_STORE_FILE: ${{ secrets.BROUTER_KEYSTORE_FILE }}
|
||||
ORG_GRADLE_PROJECT_RELEASE_KEY_ALIAS: ${{ secrets.BROUTER_KEY_ALIAS }}
|
||||
ORG_GRADLE_PROJECT_RELEASE_KEY_PASSWORD: ${{ secrets.BROUTER_KEY_PASSWORD }}
|
||||
ORG_GRADLE_PROJECT_RELEASE_STORE_PASSWORD: ${{ secrets.BROUTER_STORE_PASSWORD }}
|
||||
ORG_GRADLE_PROJECT_RELEASE_STORE_PASSWORD: ${{ secrets.BROUTER_STORE_PASSWORD }}
|
||||
run: gradle build
|
||||
|
||||
# The USERNAME and TOKEN need to correspond to the credentials environment variables used in
|
||||
|
|
|
|||
12
.github/workflows/gradle.yml
vendored
12
.github/workflows/gradle.yml
vendored
|
|
@ -15,12 +15,12 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
environment: BRouter
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'zulu'
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
cache: gradle
|
||||
- name: Create local.properties
|
||||
run: touch local.properties
|
||||
|
|
@ -37,7 +37,7 @@ jobs:
|
|||
ORG_GRADLE_PROJECT_RELEASE_STORE_PASSWORD: ${{ secrets.BROUTER_STORE_PASSWORD }}
|
||||
run: ./gradlew build
|
||||
- name: Upload ZIP
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ZIP
|
||||
path: brouter-server/build/distributions/brouter-*.zip
|
||||
|
|
|
|||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,6 +1,7 @@
|
|||
*.iml
|
||||
.gradle
|
||||
.idea/
|
||||
build
|
||||
/local.properties
|
||||
/.idea/caches
|
||||
/.idea/gradle.xml
|
||||
|
|
@ -10,7 +11,6 @@
|
|||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
|
|
|
|||
14
Dockerfile
Normal file
14
Dockerfile
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
FROM gradle:jdk17-jammy as build
|
||||
|
||||
RUN mkdir /tmp/brouter
|
||||
WORKDIR /tmp/brouter
|
||||
COPY . .
|
||||
RUN ./gradlew clean build
|
||||
|
||||
FROM openjdk:17.0.1-jdk-slim
|
||||
COPY --from=build /tmp/brouter/brouter-server/build/libs/brouter-*-all.jar /brouter.jar
|
||||
COPY --from=build /tmp/brouter/misc/scripts/standalone/server.sh /bin/
|
||||
COPY --from=build /tmp/brouter/misc/* /profiles2
|
||||
|
||||
CMD /bin/server.sh
|
||||
|
||||
52
README.md
52
README.md
|
|
@ -137,6 +137,58 @@ The API endpoints exposed by this HTTP server are documented in the
|
|||
[`brouter-server/src/main/java/btools/server/request/ServerHandler.java`](brouter-server/src/main/java/btools/server/request/ServerHandler.java)
|
||||
file.
|
||||
|
||||
The server emits log data for each routing request on stdout. For each routing
|
||||
request a line with the following eight fields is printed. The fields are
|
||||
separated by whitespace.
|
||||
|
||||
- timestamp, in ISO8601 format, e.g. `2024-05-14T21:11:26.499+02:00`
|
||||
- current server session count (integer number 1-999) or "new" when a new
|
||||
IP address is detected
|
||||
- IP address (IPv4 or IPv6), prefixed by `ip=`
|
||||
- duration of routing request in ms, prefixed by `ms=`
|
||||
- divider `->`
|
||||
- HTTP request method
|
||||
- HTTP request URL
|
||||
- HTTP request version
|
||||
|
||||
Example log output:
|
||||
|
||||
```
|
||||
2024-05-14T21:11:26.499+02:00 new ip=127.0.0.1 ms=189 -> GET /brouter?lonlats=13.377485,52.516247%7C13.351221,52.515004&profile=trekking&alternativeidx=0&format=geojson HTTP/1.1
|
||||
2024-05-14T21:11:33.229+02:00 1 ip=127.0.0.1 ms=65 -> GET /brouter?lonlats=13.377485,52.516247%7C13.351221,52.515004&profile=trekking&alternativeidx=0&format=geojson HTTP/1.1
|
||||
```
|
||||
|
||||
## BRouter with Docker
|
||||
|
||||
To build the Docker image run (in the project's top level directory):
|
||||
|
||||
```
|
||||
docker build -t brouter .
|
||||
```
|
||||
|
||||
Download the segment files as described in the previous chapter. The folder containing the
|
||||
segment files can be mounted into the container. Run BRouter as follows:
|
||||
|
||||
```
|
||||
docker run --rm \
|
||||
-v ./misc/scripts/segments4:/segments4 \
|
||||
-p 17777:17777 \
|
||||
--name brouter \
|
||||
brouter
|
||||
```
|
||||
|
||||
This will start brouter with a set of default routing profiles. It will be accessible on port 17777.
|
||||
|
||||
If you want to provide your own routing profiles, you can also mount the folder containing the custom profiles:
|
||||
|
||||
```
|
||||
docker run --rm \
|
||||
-v ./misc/scripts/segments4:/segments4 \
|
||||
-v /path/to/custom/profiles:/profiles2 \
|
||||
-p 17777:17777 \
|
||||
--name brouter \
|
||||
brouter
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
|
|
|
|||
1
brouter-codec/.gitignore
vendored
1
brouter-codec/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
/build/
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
plugins {
|
||||
id 'java-library'
|
||||
id 'brouter.library-conventions'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':brouter-util')
|
||||
testImplementation 'junit:junit:4.13.1'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<manifest package="btools.codec" />
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package btools.codec;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import btools.util.ByteDataReader;
|
||||
import btools.util.IByteArrayUnifier;
|
||||
|
|
@ -287,7 +288,7 @@ public final class MicroCache2 extends MicroCache {
|
|||
|
||||
@Override
|
||||
public int encodeMicroCache(byte[] buffer) {
|
||||
HashMap<Long, Integer> idMap = new HashMap<>();
|
||||
Map<Long, Integer> idMap = new HashMap<>();
|
||||
for (int n = 0; n < size; n++) { // loop over nodes
|
||||
idMap.put(expandId(faid[n]), n);
|
||||
}
|
||||
|
|
@ -418,7 +419,7 @@ public final class MicroCache2 extends MicroCache {
|
|||
nlinks++;
|
||||
|
||||
if (isInternal) {
|
||||
int nodeIdx = idx.intValue();
|
||||
int nodeIdx = idx;
|
||||
if (dodebug) System.out.println("*** target nodeIdx=" + nodeIdx);
|
||||
if (nodeIdx == n) throw new RuntimeException("ups: self ref?");
|
||||
nodeIdxDiff.encodeSignedValue(nodeIdx - n);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import java.util.Comparator;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
|
||||
import btools.util.BitCoderContext;
|
||||
|
||||
|
|
@ -58,7 +59,7 @@ public final class TagValueCoder {
|
|||
TagValueSet dummy = new TagValueSet(nextTagValueSetId++);
|
||||
identityMap.put(dummy, dummy);
|
||||
}
|
||||
PriorityQueue<TagValueSet> queue = new PriorityQueue<>(2 * identityMap.size(), new TagValueSet.FrequencyComparator());
|
||||
Queue<TagValueSet> queue = new PriorityQueue<>(2 * identityMap.size(), new TagValueSet.FrequencyComparator());
|
||||
queue.addAll(identityMap.values());
|
||||
while (queue.size() > 1) {
|
||||
TagValueSet node = new TagValueSet(nextTagValueSetId++);
|
||||
|
|
|
|||
1
brouter-core/.gitignore
vendored
1
brouter-core/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
/build/
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
plugins {
|
||||
id 'java-library'
|
||||
id 'brouter.library-conventions'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
|
@ -7,7 +7,6 @@ dependencies {
|
|||
implementation project(':brouter-util')
|
||||
implementation project(':brouter-expressions')
|
||||
implementation project(':brouter-codec')
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
}
|
||||
|
||||
// MapcreatorTest generates segments which are used in tests
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<manifest package="btools.router" />
|
||||
43
brouter-core/src/main/java/btools/router/FormatCsv.java
Normal file
43
brouter-core/src/main/java/btools/router/FormatCsv.java
Normal file
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
534
brouter-core/src/main/java/btools/router/FormatGpx.java
Normal file
534
brouter-core/src/main/java/btools/router/FormatGpx.java
Normal file
|
|
@ -0,0 +1,534 @@
|
|||
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("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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("<!-- ").append(message).append(" -->\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (turnInstructionMode == 4) { // comment style
|
||||
sb.append("<!-- $transport-mode$").append(t.voiceHints.getTransportMode()).append("$ -->\n");
|
||||
sb.append("<!-- cmd idx lon lat d2next geometry -->\n");
|
||||
sb.append("<!-- $turn-instruction-start$\n");
|
||||
for (VoiceHint hint : t.voiceHints.list) {
|
||||
sb.append(String.format(" $turn$%6s;%6d;%10s;%10s;%6d;%s$\n", hint.getCommandString(), hint.indexInTrack,
|
||||
formatILon(hint.ilon), formatILat(hint.ilat), (int) (hint.distanceToNext), hint.formatGeometry()));
|
||||
}
|
||||
sb.append(" $turn-instruction-end$ -->\n");
|
||||
}
|
||||
sb.append("<gpx \n");
|
||||
sb.append(" xmlns=\"http://www.topografix.com/GPX/1/1\" \n");
|
||||
sb.append(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n");
|
||||
if (turnInstructionMode == 9) { // BRouter style
|
||||
sb.append(" xmlns:brouter=\"Not yet documented\" \n");
|
||||
}
|
||||
if (turnInstructionMode == 7) { // old locus style
|
||||
sb.append(" xmlns:locus=\"http://www.locusmap.eu\" \n");
|
||||
}
|
||||
sb.append(" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\" \n");
|
||||
|
||||
if (turnInstructionMode == 3) {
|
||||
sb.append(" creator=\"OsmAndRouter\" version=\"1.1\">\n");
|
||||
} else {
|
||||
sb.append(" creator=\"BRouter-" + t.version + "\" version=\"1.1\">\n");
|
||||
}
|
||||
if (turnInstructionMode == 9) {
|
||||
sb.append(" <metadata>\n");
|
||||
sb.append(" <name>").append(t.name).append("</name>\n");
|
||||
sb.append(" <extensions>\n");
|
||||
sb.append(" <brouter:info>").append(t.messageList.get(0)).append("</brouter:info>\n");
|
||||
if (t.params != null && t.params.size() > 0) {
|
||||
sb.append(" <brouter:params><![CDATA[");
|
||||
int i = 0;
|
||||
for (Map.Entry<String, String> e : t.params.entrySet()) {
|
||||
if (i++ != 0) sb.append("&");
|
||||
sb.append(e.getKey()).append("=").append(e.getValue());
|
||||
}
|
||||
sb.append("]]></brouter:params>\n");
|
||||
}
|
||||
sb.append(" </extensions>\n");
|
||||
sb.append(" </metadata>\n");
|
||||
}
|
||||
if (turnInstructionMode == 3 || turnInstructionMode == 8) { // osmand style, cruiser
|
||||
float lastRteTime = 0;
|
||||
|
||||
sb.append(" <rte>\n");
|
||||
|
||||
float rteTime = t.getVoiceHintTime(0);
|
||||
StringBuffer first = new StringBuffer();
|
||||
// define start point
|
||||
{
|
||||
first.append(" <rtept lat=\"").append(formatILat(t.nodes.get(0).getILat())).append("\" lon=\"")
|
||||
.append(formatILon(t.nodes.get(0).getILon())).append("\">\n")
|
||||
.append(" <desc>start</desc>\n <extensions>\n");
|
||||
if (rteTime != lastRteTime) { // add timing only if available
|
||||
double ti = rteTime - lastRteTime;
|
||||
first.append(" <time>").append("" + (int) (ti + 0.5)).append("</time>\n");
|
||||
lastRteTime = rteTime;
|
||||
}
|
||||
first.append(" <offset>0</offset>\n </extensions>\n </rtept>\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(" <rtept lat=\"").append(formatILat(hint.ilat)).append("\" lon=\"")
|
||||
.append(formatILon(hint.ilon)).append("\">\n")
|
||||
.append(" <desc>")
|
||||
.append(turnInstructionMode == 3 ? hint.getMessageString() : hint.getCruiserMessageString())
|
||||
.append("</desc>\n <extensions>\n");
|
||||
|
||||
rteTime = t.getVoiceHintTime(i + 1);
|
||||
|
||||
if (rteTime != lastRteTime) { // add timing only if available
|
||||
double ti = rteTime - lastRteTime;
|
||||
sb.append(" <time>").append("" + (int) (ti + 0.5)).append("</time>\n");
|
||||
lastRteTime = rteTime;
|
||||
}
|
||||
sb.append(" <turn>")
|
||||
.append(turnInstructionMode == 3 ? hint.getCommandString() : hint.getCruiserCommandString())
|
||||
.append("</turn>\n <turn-angle>").append("" + (int) hint.angle)
|
||||
.append("</turn-angle>\n <offset>").append("" + hint.indexInTrack).append("</offset>\n </extensions>\n </rtept>\n");
|
||||
}
|
||||
sb.append(" <rtept lat=\"").append(formatILat(t.nodes.get(t.nodes.size() - 1).getILat())).append("\" lon=\"")
|
||||
.append(formatILon(t.nodes.get(t.nodes.size() - 1).getILon())).append("\">\n")
|
||||
.append(" <desc>destination</desc>\n <extensions>\n");
|
||||
sb.append(" <time>0</time>\n");
|
||||
sb.append(" <offset>").append("" + (t.nodes.size() - 1)).append("</offset>\n </extensions>\n </rtept>\n");
|
||||
|
||||
sb.append("</rte>\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(" <wpt lon=\"").append(formatILon(hint.ilon)).append("\" lat=\"")
|
||||
.append(formatILat(hint.ilat)).append("\">")
|
||||
.append(hint.selev == Short.MIN_VALUE ? "" : "<ele>" + (hint.selev / 4.) + "</ele>")
|
||||
.append("<name>")
|
||||
.append(hint.getMessageString())
|
||||
.append("</name>")
|
||||
.append("<extensions><locus:rteDistance>").append("" + hint.distanceToNext).append("</locus:rteDistance>");
|
||||
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("<locus:rteTime>").append("" + ti).append("</locus:rteTime>")
|
||||
.append("<locus:rteSpeed>").append("" + speed).append("</locus:rteSpeed>");
|
||||
lastRteTime = rteTime;
|
||||
}
|
||||
sb.append("<locus:rtePointAction>").append("" + hint.getLocusAction()).append("</locus:rtePointAction></extensions>")
|
||||
.append("</wpt>\n");
|
||||
}
|
||||
}
|
||||
if (turnInstructionMode == 5) { // gpsies style
|
||||
for (VoiceHint hint : t.voiceHints.list) {
|
||||
sb.append(" <wpt lon=\"").append(formatILon(hint.ilon)).append("\" lat=\"")
|
||||
.append(formatILat(hint.ilat)).append("\">")
|
||||
.append("<name>").append(hint.getMessageString()).append("</name>")
|
||||
.append("<sym>").append(hint.getSymbolString().toLowerCase()).append("</sym>")
|
||||
.append("<type>").append(hint.getSymbolString()).append("</type>")
|
||||
.append("</wpt>\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (turnInstructionMode == 6) { // orux style
|
||||
for (VoiceHint hint : t.voiceHints.list) {
|
||||
sb.append(" <wpt lat=\"").append(formatILat(hint.ilat)).append("\" lon=\"")
|
||||
.append(formatILon(hint.ilon)).append("\">")
|
||||
.append(hint.selev == Short.MIN_VALUE ? "" : "<ele>" + (hint.selev / 4.) + "</ele>")
|
||||
.append("<extensions>\n" +
|
||||
" <om:oruxmapsextensions xmlns:om=\"http://www.oruxmaps.com/oruxmapsextensions/1/0\">\n" +
|
||||
" <om:ext type=\"ICON\" subtype=\"0\">").append("" + hint.getOruxAction())
|
||||
.append("</om:ext>\n" +
|
||||
" </om:oruxmapsextensions>\n" +
|
||||
" </extensions>\n" +
|
||||
" </wpt>\n");
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i <= t.pois.size() - 1; i++) {
|
||||
OsmNodeNamed poi = t.pois.get(i);
|
||||
sb.append(" <wpt lon=\"").append(formatILon(poi.ilon)).append("\" lat=\"")
|
||||
.append(formatILat(poi.ilat)).append("\">\n")
|
||||
.append(" <name>").append(StringUtils.escapeXml10(poi.name)).append("</name>\n")
|
||||
.append(" </wpt>\n");
|
||||
}
|
||||
|
||||
if (t.exportWaypoints) {
|
||||
for (int i = 0; i <= t.matchedWaypoints.size() - 1; 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) {
|
||||
sb.append(" <type>from</type>\n");
|
||||
} else if (i == t.matchedWaypoints.size() - 1) {
|
||||
sb.append(" <type>to</type>\n");
|
||||
} else {
|
||||
sb.append(" <type>via</type>\n");
|
||||
}
|
||||
sb.append(" </wpt>\n");
|
||||
}
|
||||
}
|
||||
sb.append(" <trk>\n");
|
||||
if (turnInstructionMode == 9
|
||||
|| turnInstructionMode == 2
|
||||
|| turnInstructionMode == 8
|
||||
|| turnInstructionMode == 4) { // Locus, comment, cruise, brouter style
|
||||
sb.append(" <src>").append(t.name).append("</src>\n");
|
||||
sb.append(" <type>").append(t.voiceHints.getTransportMode()).append("</type>\n");
|
||||
} else {
|
||||
sb.append(" <name>").append(t.name).append("</name>\n");
|
||||
}
|
||||
|
||||
if (turnInstructionMode == 7) {
|
||||
sb.append(" <extensions>\n");
|
||||
sb.append(" <locus:rteComputeType>").append("" + t.voiceHints.getLocusRouteType()).append("</locus:rteComputeType>\n");
|
||||
sb.append(" <locus:rteSimpleRoundabouts>1</locus:rteSimpleRoundabouts>\n");
|
||||
sb.append(" </extensions>\n");
|
||||
}
|
||||
|
||||
|
||||
// all points
|
||||
sb.append(" <trkseg>\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 ? "" : "<ele>" + n.getElev() + "</ele>";
|
||||
VoiceHint hint = t.getVoiceHint(idx);
|
||||
MatchedWaypoint mwpt = t.getMatchedWaypoint(idx);
|
||||
|
||||
if (t.showTime) {
|
||||
sele += "<time>" + getFormattedTime3(n.getTime()) + "</time>";
|
||||
}
|
||||
if (turnInstructionMode == 8) {
|
||||
if (mwpt != null &&
|
||||
!mwpt.name.startsWith("via") && !mwpt.name.startsWith("from") && !mwpt.name.startsWith("to")) {
|
||||
sele += "<name>" + mwpt.name + "</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 += "<name>" + mwpt.name + "</name>";
|
||||
}
|
||||
sele += "<desc>" + hint.getCruiserMessageString() + "</desc>";
|
||||
sele += "<sym>" + hint.getCommandString(hint.cmd) + "</sym>";
|
||||
if (mwpt != null) {
|
||||
sele += "<type>Via</type>";
|
||||
}
|
||||
sele += "<extensions>";
|
||||
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 += "<brouter:speed>" + (((int) (speed * 10)) / 10.f) + "</brouter:speed>";
|
||||
}
|
||||
|
||||
sele += "<brouter:voicehint>" + hint.getCommandString() + ";" + (int) (hint.distanceToNext) + "," + hint.formatGeometry() + "</brouter:voicehint>";
|
||||
if (n.message != null && n.message.wayKeyValues != null && !n.message.wayKeyValues.equals(lastway)) {
|
||||
sele += "<brouter:way>" + n.message.wayKeyValues + "</brouter:way>";
|
||||
lastway = n.message.wayKeyValues;
|
||||
}
|
||||
if (n.message != null && n.message.nodeKeyValues != null) {
|
||||
sele += "<brouter:node>" + n.message.nodeKeyValues + "</brouter:node>";
|
||||
}
|
||||
sele += "</extensions>";
|
||||
|
||||
}
|
||||
if (idx == 0 && hint == null) {
|
||||
if (mwpt != null && mwpt.direct) {
|
||||
sele += "<desc>beeline</desc>";
|
||||
} else {
|
||||
sele += "<desc>start</desc>";
|
||||
}
|
||||
sele += "<type>Via</type>";
|
||||
|
||||
} else if (idx == t.nodes.size() - 1 && hint == null) {
|
||||
|
||||
sele += "<desc>end</desc>";
|
||||
sele += "<type>Via</type>";
|
||||
|
||||
} else {
|
||||
if (mwpt != null && hint == null) {
|
||||
if (mwpt.direct) {
|
||||
// bNextDirect = true;
|
||||
sele += "<desc>beeline</desc>";
|
||||
} else {
|
||||
sele += "<desc>" + mwpt.name + "</desc>";
|
||||
}
|
||||
sele += "<type>Via</type>";
|
||||
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 += "<extensions>";
|
||||
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 += "<brouter:speed>" + (((int) (speed * 10)) / 10.f) + "</brouter:speed>";
|
||||
}
|
||||
if (n.message != null && n.message.wayKeyValues != null && !n.message.wayKeyValues.equals(lastway)) {
|
||||
sele += "<brouter:way>" + n.message.wayKeyValues + "</brouter:way>";
|
||||
lastway = n.message.wayKeyValues;
|
||||
}
|
||||
if (n.message != null && n.message.nodeKeyValues != null) {
|
||||
sele += "<brouter:node>" + n.message.nodeKeyValues + "</brouter:node>";
|
||||
}
|
||||
sele += "</extensions>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 += "<name>" + mwpt.name + "</name>";
|
||||
}
|
||||
if (mwpt.direct && bNextDirect) {
|
||||
sele += "<src>" + hint.getLocusSymbolString() + "</src><sym>pass_place</sym><type>Shaping</type>";
|
||||
// bNextDirect = false;
|
||||
} else if (mwpt.direct) {
|
||||
if (idx == 0)
|
||||
sele += "<sym>pass_place</sym><type>Via</type>";
|
||||
else
|
||||
sele += "<sym>pass_place</sym><type>Shaping</type>";
|
||||
bNextDirect = true;
|
||||
} else if (bNextDirect) {
|
||||
sele += "<src>beeline</src><sym>" + hint.getLocusSymbolString() + "</sym><type>Shaping</type>";
|
||||
bNextDirect = false;
|
||||
} else {
|
||||
sele += "<sym>" + hint.getLocusSymbolString() + "</sym><type>Via</type>";
|
||||
}
|
||||
} else {
|
||||
sele += "<sym>" + hint.getLocusSymbolString() + "</sym>";
|
||||
}
|
||||
} else {
|
||||
if (idx == 0 && hint == null) {
|
||||
|
||||
int pos = sele.indexOf("<sym");
|
||||
if (pos != -1) {
|
||||
sele = sele.substring(0, pos);
|
||||
}
|
||||
if (mwpt != null && !mwpt.name.startsWith("from"))
|
||||
sele += "<name>" + mwpt.name + "</name>";
|
||||
if (mwpt != null && mwpt.direct) {
|
||||
bNextDirect = true;
|
||||
}
|
||||
sele += "<sym>pass_place</sym>";
|
||||
sele += "<type>Via</type>";
|
||||
|
||||
} else if (idx == t.nodes.size() - 1 && hint == null) {
|
||||
|
||||
int pos = sele.indexOf("<sym");
|
||||
if (pos != -1) {
|
||||
sele = sele.substring(0, pos);
|
||||
}
|
||||
if (mwpt != null && mwpt.name != null && !mwpt.name.startsWith("to"))
|
||||
sele += "<name>" + mwpt.name + "</name>";
|
||||
if (bNextDirect) {
|
||||
sele += "<src>beeline</src>";
|
||||
}
|
||||
sele += "<sym>pass_place</sym>";
|
||||
sele += "<type>Via</type>";
|
||||
|
||||
} else {
|
||||
if (mwpt != null) {
|
||||
if (!mwpt.name.startsWith("via") && !mwpt.name.startsWith("from") && !mwpt.name.startsWith("to")) {
|
||||
sele += "<name>" + mwpt.name + "</name>";
|
||||
}
|
||||
if (mwpt.direct && bNextDirect) {
|
||||
sele += "<src>beeline</src><sym>pass_place</sym><type>Shaping</type>";
|
||||
} else if (mwpt.direct) {
|
||||
if (idx == 0)
|
||||
sele += "<sym>pass_place</sym><type>Via</type>";
|
||||
else
|
||||
sele += "<sym>pass_place</sym><type>Shaping</type>";
|
||||
bNextDirect = true;
|
||||
} else if (bNextDirect) {
|
||||
sele += "<src>beeline</src><sym>pass_place</sym><type>Shaping</type>";
|
||||
bNextDirect = false;
|
||||
} else if (mwpt.name.startsWith("via") ||
|
||||
mwpt.name.startsWith("from") ||
|
||||
mwpt.name.startsWith("to")) {
|
||||
if (bNextDirect) {
|
||||
sele += "<src>beeline</src><sym>pass_place</sym><type>Shaping</type>";
|
||||
} else {
|
||||
sele += "<sym>pass_place</sym><type>Via</type>";
|
||||
}
|
||||
bNextDirect = false;
|
||||
} else {
|
||||
sele += "<name>" + mwpt.name + "</name>";
|
||||
sele += "<sym>pass_place</sym><type>Via</type>";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append(" <trkpt lon=\"").append(formatILon(n.getILon())).append("\" lat=\"")
|
||||
.append(formatILat(n.getILat())).append("\">").append(sele).append("</trkpt>\n");
|
||||
|
||||
nn = n;
|
||||
}
|
||||
|
||||
sb.append(" </trkseg>\n");
|
||||
sb.append(" </trk>\n");
|
||||
sb.append("</gpx>\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("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
||||
sb.append("<gpx \n");
|
||||
sb.append(" xmlns=\"http://www.topografix.com/GPX/1/1\" \n");
|
||||
sb.append(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n");
|
||||
sb.append(" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\" \n");
|
||||
sb.append(" creator=\"BRouter-" + OsmTrack.version + "\" version=\"1.1\">\n");
|
||||
}
|
||||
|
||||
public void formatGpxFooter(BufferedWriter sb) throws IOException {
|
||||
sb.append("</gpx>\n");
|
||||
}
|
||||
|
||||
public void formatWaypointGpx(BufferedWriter sb, OsmNodeNamed n) throws IOException {
|
||||
sb.append(" <wpt lon=\"").append(formatILon(n.ilon)).append("\" lat=\"")
|
||||
.append(formatILat(n.ilat)).append("\">");
|
||||
if (n.getSElev() != Short.MIN_VALUE) {
|
||||
sb.append("<ele>").append("" + n.getElev()).append("</ele>");
|
||||
}
|
||||
if (n.name != null) {
|
||||
sb.append("<name>").append(StringUtils.escapeXml10(n.name)).append("</name>");
|
||||
}
|
||||
if (n.nodeDescription != null && rc != null) {
|
||||
sb.append("<desc>").append(rc.expctxWay.getKeyValueDescription(false, n.nodeDescription)).append("</desc>");
|
||||
}
|
||||
sb.append("</wpt>\n");
|
||||
}
|
||||
|
||||
public static String getWaypoint(int ilon, int ilat, String name, String desc) {
|
||||
return "<wpt lon=\"" + formatILon(ilon) + "\" lat=\"" + formatILat(ilat) + "\"><name>" + name + "</name>" + (desc != null ? "<desc>" + desc + "</desc>" : "") + "</wpt>";
|
||||
}
|
||||
|
||||
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("<trkpt ");
|
||||
if (idx0 >= 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));
|
||||
}
|
||||
}
|
||||
br.close();
|
||||
return track;
|
||||
}
|
||||
|
||||
}
|
||||
246
brouter-core/src/main/java/btools/router/FormatJson.java
Normal file
246
brouter-core/src/main/java/btools/router/FormatJson.java
Normal file
|
|
@ -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<String> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
91
brouter-core/src/main/java/btools/router/FormatKml.java
Normal file
91
brouter-core/src/main/java/btools/router/FormatKml.java
Normal file
|
|
@ -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("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
||||
|
||||
sb.append("<kml xmlns=\"http://earth.google.com/kml/2.0\">\n");
|
||||
sb.append(" <Document>\n");
|
||||
sb.append(" <name>KML Samples</name>\n");
|
||||
sb.append(" <open>1</open>\n");
|
||||
sb.append(" <distance>3.497064</distance>\n");
|
||||
sb.append(" <traveltime>872</traveltime>\n");
|
||||
sb.append(" <description>To enable simple instructions add: 'instructions=1' as parameter to the URL</description>\n");
|
||||
sb.append(" <Folder>\n");
|
||||
sb.append(" <name>Paths</name>\n");
|
||||
sb.append(" <visibility>0</visibility>\n");
|
||||
sb.append(" <description>Examples of paths.</description>\n");
|
||||
sb.append(" <Placemark>\n");
|
||||
sb.append(" <name>Tessellated</name>\n");
|
||||
sb.append(" <visibility>0</visibility>\n");
|
||||
sb.append(" <description><![CDATA[If the <tessellate> tag has a value of 1, the line will contour to the underlying terrain]]></description>\n");
|
||||
sb.append(" <LineString>\n");
|
||||
sb.append(" <tessellate>1</tessellate>\n");
|
||||
sb.append(" <coordinates>");
|
||||
|
||||
for (OsmPathElement n : t.nodes) {
|
||||
sb.append(formatILon(n.getILon())).append(",").append(formatILat(n.getILat())).append("\n");
|
||||
}
|
||||
|
||||
sb.append(" </coordinates>\n");
|
||||
sb.append(" </LineString>\n");
|
||||
sb.append(" </Placemark>\n");
|
||||
sb.append(" </Folder>\n");
|
||||
if (t.exportWaypoints || !t.pois.isEmpty()) {
|
||||
if (!t.pois.isEmpty()) {
|
||||
sb.append(" <Folder>\n");
|
||||
sb.append(" <name>poi</name>\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(" </Folder>\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(" </Document>\n");
|
||||
sb.append("</kml>\n");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void createFolder(StringBuilder sb, String type, List<MatchedWaypoint> waypoints) {
|
||||
sb.append(" <Folder>\n");
|
||||
sb.append(" <name>" + type + "</name>\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(" </Folder>\n");
|
||||
}
|
||||
|
||||
private void createPlaceMark(StringBuilder sb, String name, int ilat, int ilon) {
|
||||
sb.append(" <Placemark>\n");
|
||||
sb.append(" <name>" + StringUtils.escapeXml10(name) + "</name>\n");
|
||||
sb.append(" <Point>\n");
|
||||
sb.append(" <coordinates>" + formatILon(ilon) + "," + formatILat(ilat) + "</coordinates>\n");
|
||||
sb.append(" </Point>\n");
|
||||
sb.append(" </Placemark>\n");
|
||||
}
|
||||
|
||||
}
|
||||
110
brouter-core/src/main/java/btools/router/Formatter.java
Normal file
110
brouter-core/src/main/java/btools/router/Formatter.java
Normal file
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -168,7 +168,7 @@ public class OsmNogoPolygon extends OsmNodeNamed {
|
|||
Point p1 = points.get(0);
|
||||
for (int i = 1; i <= i_last; i++) {
|
||||
final Point p2 = points.get(i);
|
||||
if (OsmNogoPolygon.isOnLine(px, py, p1.x, p1.y, p2.x, p2.y)) {
|
||||
if (isOnLine(px, py, p1.x, p1.y, p2.x, p2.y)) {
|
||||
return true;
|
||||
}
|
||||
p1 = p2;
|
||||
|
|
@ -234,7 +234,7 @@ public class OsmNogoPolygon extends OsmNodeNamed {
|
|||
final long p1x = p1.x;
|
||||
final long p1y = p1.y;
|
||||
|
||||
if (OsmNogoPolygon.isOnLine(px, py, p0x, p0y, p1x, p1y)) {
|
||||
if (isOnLine(px, py, p0x, p0y, p1x, p1y)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@
|
|||
*/
|
||||
package btools.router;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import btools.mapaccess.OsmLink;
|
||||
import btools.mapaccess.OsmLinkHolder;
|
||||
import btools.mapaccess.OsmNode;
|
||||
|
|
@ -33,8 +31,6 @@ abstract class OsmPath implements OsmLinkHolder {
|
|||
public OsmPathElement originElement;
|
||||
public OsmPathElement myElement;
|
||||
|
||||
protected float traffic;
|
||||
|
||||
private OsmLinkHolder nextForLink = null;
|
||||
|
||||
public int treedepth = 0;
|
||||
|
|
@ -72,25 +68,6 @@ abstract class OsmPath implements OsmLinkHolder {
|
|||
|
||||
public MessageData message;
|
||||
|
||||
public void unregisterUpTree(RoutingContext rc) {
|
||||
try {
|
||||
OsmPathElement pe = originElement;
|
||||
while (pe instanceof OsmPathElementWithTraffic && ((OsmPathElementWithTraffic) pe).unregister(rc)) {
|
||||
pe = pe.origin;
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerUpTree() {
|
||||
if (originElement instanceof OsmPathElementWithTraffic) {
|
||||
OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic) originElement;
|
||||
ot.register();
|
||||
ot.addTraffic(traffic);
|
||||
}
|
||||
}
|
||||
|
||||
public void init(OsmLink link) {
|
||||
this.link = link;
|
||||
targetNode = link.getTarget(null);
|
||||
|
|
@ -102,7 +79,7 @@ abstract class OsmPath implements OsmLinkHolder {
|
|||
|
||||
public void init(OsmPath origin, OsmLink link, OsmTrack refTrack, boolean detailMode, RoutingContext rc) {
|
||||
if (origin.myElement == null) {
|
||||
origin.myElement = OsmPathElement.create(origin, rc.countTraffic);
|
||||
origin.myElement = OsmPathElement.create(origin);
|
||||
}
|
||||
this.originElement = origin.myElement;
|
||||
this.link = link;
|
||||
|
|
@ -143,7 +120,7 @@ abstract class OsmPath implements OsmLinkHolder {
|
|||
return;
|
||||
}
|
||||
|
||||
boolean recordTransferNodes = detailMode || rc.countTraffic;
|
||||
boolean recordTransferNodes = detailMode;
|
||||
|
||||
rc.nogoCost = 0.;
|
||||
|
||||
|
|
@ -272,7 +249,7 @@ abstract class OsmPath implements OsmLinkHolder {
|
|||
if (recordTransferNodes) {
|
||||
if (rc.wayfraction > 0.) {
|
||||
ele1 = interpolateEle(ele1, ele2, 1. - rc.wayfraction);
|
||||
originElement = OsmPathElement.create(rc.ilonshortest, rc.ilatshortest, ele1, null, rc.countTraffic);
|
||||
originElement = OsmPathElement.create(rc.ilonshortest, rc.ilatshortest, ele1, null);
|
||||
} else {
|
||||
originElement = null; // prevent duplicate point
|
||||
}
|
||||
|
|
@ -296,7 +273,7 @@ abstract class OsmPath implements OsmLinkHolder {
|
|||
// apply a start-direction if appropriate (by faking the origin position)
|
||||
if (isStartpoint) {
|
||||
if (rc.startDirectionValid) {
|
||||
double dir = rc.startDirection.intValue() * CheapRuler.DEG_TO_RAD;
|
||||
double dir = rc.startDirection * CheapRuler.DEG_TO_RAD;
|
||||
double[] lonlat2m = CheapRuler.getLonLatToMeterScales((lon0 + lat1) >> 1);
|
||||
lon0 = lon1 - (int) (1000. * Math.sin(dir) / lonlat2m[0]);
|
||||
lat0 = lat1 - (int) (1000. * Math.cos(dir) / lonlat2m[1]);
|
||||
|
|
@ -333,13 +310,6 @@ abstract class OsmPath implements OsmLinkHolder {
|
|||
|
||||
cost += (int) sectionCost;
|
||||
|
||||
// calculate traffic
|
||||
if (rc.countTraffic) {
|
||||
int minDist = (int) rc.trafficSourceMinDist;
|
||||
int cost2 = cost < minDist ? minDist : cost;
|
||||
traffic += dist * rc.expctxWay.getTrafficSourceDensity() * Math.pow(cost2 / 10000.f, rc.trafficSourceExponent);
|
||||
}
|
||||
|
||||
// compute kinematic
|
||||
computeKinematic(rc, dist, delta_h, detailMode);
|
||||
|
||||
|
|
@ -357,7 +327,7 @@ abstract class OsmPath implements OsmLinkHolder {
|
|||
|
||||
if (stopAtEndpoint) {
|
||||
if (recordTransferNodes) {
|
||||
originElement = OsmPathElement.create(rc.ilonshortest, rc.ilatshortest, originEle2, originElement, rc.countTraffic);
|
||||
originElement = OsmPathElement.create(rc.ilonshortest, rc.ilatshortest, originEle2, originElement);
|
||||
originElement.cost = cost;
|
||||
if (message != null) {
|
||||
originElement.message = message;
|
||||
|
|
@ -383,10 +353,8 @@ abstract class OsmPath implements OsmLinkHolder {
|
|||
transferNode = transferNode.next;
|
||||
|
||||
if (recordTransferNodes) {
|
||||
originElement = OsmPathElement.create(lon2, lat2, originEle2, originElement, rc.countTraffic);
|
||||
originElement = OsmPathElement.create(lon2, lat2, originEle2, originElement);
|
||||
originElement.cost = cost;
|
||||
originElement.addTraffic(traffic);
|
||||
traffic = 0;
|
||||
}
|
||||
lon0 = lon1;
|
||||
lat0 = lat1;
|
||||
|
|
|
|||
|
|
@ -81,16 +81,16 @@ public class OsmPathElement implements OsmPos {
|
|||
public OsmPathElement origin;
|
||||
|
||||
// construct a path element from a path
|
||||
public static final OsmPathElement create(OsmPath path, boolean countTraffic) {
|
||||
public static final OsmPathElement create(OsmPath path) {
|
||||
OsmNode n = path.getTargetNode();
|
||||
OsmPathElement pe = create(n.getILon(), n.getILat(), n.getSElev(), path.originElement, countTraffic);
|
||||
OsmPathElement pe = create(n.getILon(), n.getILat(), n.getSElev(), path.originElement);
|
||||
pe.cost = path.cost;
|
||||
pe.message = path.message;
|
||||
return pe;
|
||||
}
|
||||
|
||||
public static final OsmPathElement create(int ilon, int ilat, short selev, OsmPathElement origin, boolean countTraffic) {
|
||||
OsmPathElement pe = countTraffic ? new OsmPathElementWithTraffic() : new OsmPathElement();
|
||||
public static final OsmPathElement create(int ilon, int ilat, short selev, OsmPathElement origin) {
|
||||
OsmPathElement pe = new OsmPathElement();
|
||||
pe.ilon = ilon;
|
||||
pe.ilat = ilat;
|
||||
pe.selev = selev;
|
||||
|
|
@ -101,9 +101,6 @@ public class OsmPathElement implements OsmPos {
|
|||
protected OsmPathElement() {
|
||||
}
|
||||
|
||||
public void addTraffic(float traffic) {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return ilon + "_" + ilat;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
package btools.router;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* Extension to OsmPathElement to count traffic load
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
|
||||
public final class OsmPathElementWithTraffic extends OsmPathElement {
|
||||
private int registerCount;
|
||||
private float farTraffic;
|
||||
private float nearTraffic;
|
||||
|
||||
public void register() {
|
||||
if (registerCount++ == 0) {
|
||||
if (origin instanceof OsmPathElementWithTraffic) {
|
||||
OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic) origin;
|
||||
ot.register();
|
||||
ot.farTraffic += farTraffic;
|
||||
ot.nearTraffic += nearTraffic;
|
||||
farTraffic = 0;
|
||||
nearTraffic = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTraffic(float traffic) {
|
||||
this.farTraffic += traffic;
|
||||
this.nearTraffic += traffic;
|
||||
}
|
||||
|
||||
// unregister from origin if our registercount is 0, else do nothing
|
||||
|
||||
public static double maxtraffic = 0.;
|
||||
|
||||
public boolean unregister(RoutingContext rc) throws IOException {
|
||||
if (--registerCount == 0) {
|
||||
if (origin instanceof OsmPathElementWithTraffic) {
|
||||
OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic) origin;
|
||||
|
||||
int costdelta = cost - ot.cost;
|
||||
ot.farTraffic += farTraffic * Math.exp(-costdelta / rc.farTrafficDecayLength);
|
||||
ot.nearTraffic += nearTraffic * Math.exp(-costdelta / rc.nearTrafficDecayLength);
|
||||
|
||||
if (costdelta > 0 && farTraffic > maxtraffic) maxtraffic = farTraffic;
|
||||
|
||||
int t2 = cost == ot.cost ? -1 : (int) (rc.farTrafficWeight * farTraffic + rc.nearTrafficWeight * nearTraffic);
|
||||
|
||||
if (t2 > 4000 || t2 == -1) {
|
||||
// System.out.println( "unregistered: " + this + " origin=" + ot + " farTraffic =" + farTraffic + " nearTraffic =" + nearTraffic + " cost=" + cost );
|
||||
if (rc.trafficOutputStream != null) {
|
||||
rc.trafficOutputStream.writeLong(getIdFromPos());
|
||||
rc.trafficOutputStream.writeLong(ot.getIdFromPos());
|
||||
rc.trafficOutputStream.writeInt(t2);
|
||||
}
|
||||
}
|
||||
farTraffic = 0;
|
||||
nearTraffic = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
package btools.router;
|
||||
|
||||
import java.io.DataOutput;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -141,14 +140,6 @@ public final class RoutingContext {
|
|||
starttimeoffset = expctxGlobal.getVariableValue("starttimeoffset", 0.f);
|
||||
transitonly = expctxGlobal.getVariableValue("transitonly", 0.f) != 0.f;
|
||||
|
||||
farTrafficWeight = expctxGlobal.getVariableValue("farTrafficWeight", 2.f);
|
||||
nearTrafficWeight = expctxGlobal.getVariableValue("nearTrafficWeight", 2.f);
|
||||
farTrafficDecayLength = expctxGlobal.getVariableValue("farTrafficDecayLength", 30000.f);
|
||||
nearTrafficDecayLength = expctxGlobal.getVariableValue("nearTrafficDecayLength", 3000.f);
|
||||
trafficDirectionFactor = expctxGlobal.getVariableValue("trafficDirectionFactor", 0.9f);
|
||||
trafficSourceExponent = expctxGlobal.getVariableValue("trafficSourceExponent", -0.7f);
|
||||
trafficSourceMinDist = expctxGlobal.getVariableValue("trafficSourceMinDist", 3000.f);
|
||||
|
||||
showspeed = 0.f != expctxGlobal.getVariableValue("showspeed", 0.f);
|
||||
showSpeedProfile = 0.f != expctxGlobal.getVariableValue("showSpeedProfile", 0.f);
|
||||
inverseRouting = 0.f != expctxGlobal.getVariableValue("inverseRouting", 0.f);
|
||||
|
|
@ -199,23 +190,16 @@ public final class RoutingContext {
|
|||
public int ilatshortest;
|
||||
public int ilonshortest;
|
||||
|
||||
public boolean countTraffic;
|
||||
public boolean inverseDirection;
|
||||
public DataOutput trafficOutputStream;
|
||||
|
||||
public double farTrafficWeight;
|
||||
public double nearTrafficWeight;
|
||||
public double farTrafficDecayLength;
|
||||
public double nearTrafficDecayLength;
|
||||
public double trafficDirectionFactor;
|
||||
public double trafficSourceExponent;
|
||||
public double trafficSourceMinDist;
|
||||
|
||||
public boolean showspeed;
|
||||
public boolean showSpeedProfile;
|
||||
public boolean inverseRouting;
|
||||
public boolean showTime;
|
||||
|
||||
public String outputFormat = "gpx";
|
||||
public boolean exportWaypoints = false;
|
||||
|
||||
public OsmPrePath firstPrePath;
|
||||
|
||||
public int turnInstructionMode; // 0=none, 1=auto, 2=locus, 3=osmand, 4=comment-style, 5=gpsies-style
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import btools.mapaccess.OsmLink;
|
|||
import btools.mapaccess.OsmLinkHolder;
|
||||
import btools.mapaccess.OsmNode;
|
||||
import btools.mapaccess.OsmNodePairSet;
|
||||
import btools.mapaccess.OsmPos;
|
||||
import btools.util.CompactLongMap;
|
||||
import btools.util.SortedHeap;
|
||||
import btools.util.StackSampler;
|
||||
|
|
@ -158,16 +159,21 @@ public class RoutingEngine extends Thread {
|
|||
|
||||
switch (engineMode) {
|
||||
case BROUTER_ENGINEMODE_ROUTING:
|
||||
if (waypoints.size() < 2) {
|
||||
throw new IllegalArgumentException("we need two lat/lon points at least!");
|
||||
}
|
||||
doRouting(maxRunningTime);
|
||||
break;
|
||||
case BROUTER_ENGINEMODE_SEED: /* do nothing, handled the old way */
|
||||
break;
|
||||
throw new IllegalArgumentException("not a valid engine mode");
|
||||
case BROUTER_ENGINEMODE_GETELEV:
|
||||
if (waypoints.size() < 1) {
|
||||
throw new IllegalArgumentException("we need one lat/lon point at least!");
|
||||
}
|
||||
doGetElev();
|
||||
break;
|
||||
default:
|
||||
doRouting(maxRunningTime);
|
||||
break;
|
||||
throw new IllegalArgumentException("not a valid engine mode");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -181,37 +187,76 @@ public class RoutingEngine extends Thread {
|
|||
OsmTrack[] refTracks = new OsmTrack[nsections]; // used ways for alternatives
|
||||
OsmTrack[] lastTracks = new OsmTrack[nsections];
|
||||
OsmTrack track = null;
|
||||
ArrayList<String> messageList = new ArrayList<>();
|
||||
List<String> messageList = new ArrayList<>();
|
||||
for (int i = 0; ; i++) {
|
||||
track = findTrack(refTracks, lastTracks);
|
||||
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.writeGpx(filename);
|
||||
track.exportWaypoints = routingContext.exportWaypoints;
|
||||
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;
|
||||
|
|
@ -221,7 +266,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;
|
||||
}
|
||||
|
|
@ -300,8 +345,32 @@ public class RoutingEngine extends Thread {
|
|||
OsmNodeNamed n = new OsmNodeNamed(listOne.get(0).crosspoint);
|
||||
n.selev = startNode != null ? startNode.getSElev() : Short.MIN_VALUE;
|
||||
|
||||
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 + "." + 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");
|
||||
} catch (Exception e) {
|
||||
|
|
@ -621,9 +690,9 @@ public class RoutingEngine extends Thread {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
ArrayList<OsmPathElement> removeBackList = new ArrayList<>();
|
||||
ArrayList<OsmPathElement> removeForeList = new ArrayList<>();
|
||||
ArrayList<Integer> removeVoiceHintList = new ArrayList<>();
|
||||
List<OsmPathElement> removeBackList = new ArrayList<>();
|
||||
List<OsmPathElement> removeForeList = new ArrayList<>();
|
||||
List<Integer> removeVoiceHintList = new ArrayList<>();
|
||||
OsmPathElement last = null;
|
||||
OsmPathElement lastJunction = null;
|
||||
CompactLongMap<OsmTrack.OsmPathElementHolder> lastJunctions = new CompactLongMap<>();
|
||||
|
|
@ -839,11 +908,12 @@ public class RoutingEngine extends Thread {
|
|||
if (ele_last != Short.MIN_VALUE) {
|
||||
ehb = ehb + (ele_last - ele) * eleFactor;
|
||||
}
|
||||
double filter = elevationFilter(n);
|
||||
if (ehb > 0) {
|
||||
ascend += ehb;
|
||||
ehb = 0;
|
||||
} else if (ehb < -10) {
|
||||
ehb = -10;
|
||||
} else if (ehb < filter) {
|
||||
ehb = filter;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -880,6 +950,21 @@ public class RoutingEngine extends Thread {
|
|||
logInfo("filtered ascend = " + t.ascend);
|
||||
}
|
||||
|
||||
/**
|
||||
* find the elevation type for position
|
||||
* to determine the filter value
|
||||
*
|
||||
* @param n the point
|
||||
* @return the filter value for 1sec / 3sec elevation source
|
||||
*/
|
||||
double elevationFilter(OsmPos n) {
|
||||
if (nodesCache != null) {
|
||||
int r = nodesCache.getElevationType(n.getILon(), n.getILat());
|
||||
if (r == 1) return -5.;
|
||||
}
|
||||
return -10.;
|
||||
}
|
||||
|
||||
// geometric position matching finding the nearest routable way-section
|
||||
private void matchWaypointsToNodes(List<MatchedWaypoint> unmatchedWaypoints) {
|
||||
resetCache(false);
|
||||
|
|
@ -935,7 +1020,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.) {
|
||||
|
|
@ -1161,7 +1246,7 @@ public class RoutingEngine extends Thread {
|
|||
addToOpenset(startPath1);
|
||||
addToOpenset(startPath2);
|
||||
}
|
||||
ArrayList<OsmPath> openBorderList = new ArrayList<>(4096);
|
||||
List<OsmPath> openBorderList = new ArrayList<>(4096);
|
||||
boolean memoryPanicMode = false;
|
||||
boolean needNonPanicProcessing = false;
|
||||
|
||||
|
|
@ -1194,7 +1279,6 @@ public class RoutingEngine extends Thread {
|
|||
}
|
||||
|
||||
if (path.airdistance == -1) {
|
||||
path.unregisterUpTree(routingContext);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1262,7 +1346,6 @@ public class RoutingEngine extends Thread {
|
|||
OsmNode currentNode = path.getTargetNode();
|
||||
|
||||
if (currentLink.isLinkUnused()) {
|
||||
path.unregisterUpTree(routingContext);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1305,7 +1388,7 @@ public class RoutingEngine extends Thread {
|
|||
+ path.elevationCorrection()
|
||||
+ (costCuttingTrack.cost - pe.cost);
|
||||
if (costEstimate <= maxTotalCost) {
|
||||
matchPath = OsmPathElement.create(path, routingContext.countTraffic);
|
||||
matchPath = OsmPathElement.create(path);
|
||||
}
|
||||
if (costEstimate < maxTotalCost) {
|
||||
logInfo("maxcost " + maxTotalCost + " -> " + costEstimate);
|
||||
|
|
@ -1315,7 +1398,6 @@ public class RoutingEngine extends Thread {
|
|||
}
|
||||
}
|
||||
|
||||
int keepPathAirdistance = path.airdistance;
|
||||
OsmLinkHolder firstLinkHolder = currentLink.getFirstLinkHolder(sourceNode);
|
||||
for (OsmLinkHolder linkHolder = firstLinkHolder; linkHolder != null; linkHolder = linkHolder.getNextForLink()) {
|
||||
((OsmPath) linkHolder).airdistance = -1; // invalidate the entry in the open set;
|
||||
|
|
@ -1334,7 +1416,6 @@ public class RoutingEngine extends Thread {
|
|||
// recheck cutoff before doing expensive stuff
|
||||
int addDiff = 100;
|
||||
if (path.cost + path.airdistance > maxTotalCost + addDiff) {
|
||||
path.unregisterUpTree(routingContext);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1389,7 +1470,7 @@ public class RoutingEngine extends Thread {
|
|||
if (routingContext.turnInstructionMode > 0) {
|
||||
OsmPath detour = routingContext.createPath(path, link, refTrack, true);
|
||||
if (detour.cost >= 0. && nextId != startNodeId1 && nextId != startNodeId2) {
|
||||
guideTrack.registerDetourForId(currentNode.getIdFromPos(), OsmPathElement.create(detour, false));
|
||||
guideTrack.registerDetourForId(currentNode.getIdFromPos(), OsmPathElement.create(detour));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
|
@ -1425,16 +1506,14 @@ public class RoutingEngine extends Thread {
|
|||
}
|
||||
}
|
||||
if (bestPath != null) {
|
||||
boolean trafficSim = endPos == null;
|
||||
|
||||
bestPath.airdistance = trafficSim ? keepPathAirdistance : (isFinalLink ? 0 : nextNode.calcDistance(endPos));
|
||||
bestPath.airdistance = isFinalLink ? 0 : nextNode.calcDistance(endPos);
|
||||
|
||||
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) {
|
||||
while (dominator != null) {
|
||||
OsmPath dp = (OsmPath) dominator;
|
||||
if (dp.airdistance != -1 && bestPath.definitlyWorseThan(dp)) {
|
||||
break;
|
||||
|
|
@ -1443,9 +1522,6 @@ public class RoutingEngine extends Thread {
|
|||
}
|
||||
|
||||
if (dominator == null) {
|
||||
if (trafficSim && boundary != null && path.cost == 0 && bestPath.cost > 0) {
|
||||
bestPath.airdistance += boundary.getBoundaryDistance(nextNode);
|
||||
}
|
||||
bestPath.treedepth = path.treedepth + 1;
|
||||
link.addLinkHolder(bestPath, currentNode);
|
||||
addToOpenset(bestPath);
|
||||
|
|
@ -1453,8 +1529,6 @@ public class RoutingEngine extends Thread {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
path.unregisterUpTree(routingContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1468,12 +1542,11 @@ public class RoutingEngine extends Thread {
|
|||
private void addToOpenset(OsmPath path) {
|
||||
if (path.cost >= 0) {
|
||||
openSet.add(path.cost + (int) (path.airdistance * airDistanceCostFactor), path);
|
||||
path.registerUpTree();
|
||||
}
|
||||
}
|
||||
|
||||
private OsmTrack compileTrack(OsmPath path, boolean verbose) {
|
||||
OsmPathElement element = OsmPathElement.create(path, false);
|
||||
OsmPathElement element = OsmPathElement.create(path);
|
||||
|
||||
// for final track, cut endnode
|
||||
if (guideTrack != null && element.origin != null) {
|
||||
|
|
@ -1612,7 +1685,7 @@ public class RoutingEngine extends Thread {
|
|||
}
|
||||
|
||||
public String getTime() {
|
||||
return foundTrack.getFormattedTime2();
|
||||
return Formatter.getFormattedTime2(foundTrack.getTotalSeconds());
|
||||
}
|
||||
|
||||
public OsmTrack getFoundTrack() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,356 @@
|
|||
package btools.router;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class RoutingParamCollector {
|
||||
|
||||
final static boolean DEBUG = false;
|
||||
|
||||
/**
|
||||
* get a list of points and optional extra info for the points
|
||||
*
|
||||
* @param lonLats linked list separated by ';' or '|'
|
||||
* @return a list
|
||||
*/
|
||||
public List<OsmNodeNamed> getWayPointList(String lonLats) {
|
||||
if (lonLats == null) throw new IllegalArgumentException("lonlats parameter not set");
|
||||
|
||||
String[] coords = lonLats.split(";|\\|"); // use both variantes
|
||||
if (coords.length < 1 || !coords[0].contains(","))
|
||||
throw new IllegalArgumentException("we need one lat/lon point at least!");
|
||||
|
||||
List<OsmNodeNamed> wplist = new ArrayList<>();
|
||||
for (int i = 0; i < coords.length; i++) {
|
||||
String[] lonLat = coords[i].split(",");
|
||||
if (lonLat.length < 1)
|
||||
throw new IllegalArgumentException("we need one lat/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;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a list of points (old style, positions only)
|
||||
*
|
||||
* @param lons array with longitudes
|
||||
* @param lats array with latitudes
|
||||
* @return a list
|
||||
*/
|
||||
public List<OsmNodeNamed> readPositions(double[] lons, double[] lats) {
|
||||
List<OsmNodeNamed> wplist = new ArrayList<>();
|
||||
|
||||
if (lats == null || lats.length < 2 || lons == null || lons.length < 2) {
|
||||
return wplist;
|
||||
}
|
||||
|
||||
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 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 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* read a url like parameter list linked with '&'
|
||||
*
|
||||
* @param url parameter list
|
||||
* @return a hashmap of the parameter
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
public Map<String, String> getUrlParams(String url) throws UnsupportedEncodingException {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
String decoded = URLDecoder.decode(url, "UTF-8");
|
||||
StringTokenizer tk = new StringTokenizer(decoded, "?&");
|
||||
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();
|
||||
params.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public void setParams(RoutingContext rctx, List<OsmNodeNamed> wplist, Map<String, String> params) {
|
||||
if (params != null) {
|
||||
if (params.size() == 0) return;
|
||||
|
||||
// prepare nogos extra
|
||||
if (params.containsKey("profile")) {
|
||||
rctx.localFunction = params.get("profile");
|
||||
}
|
||||
if (params.containsKey("nogoLats") && params.get("nogoLats").length() > 0) {
|
||||
List<OsmNodeNamed> nogoList = readNogos(params.get("nogoLons"), params.get("nogoLats"), params.get("nogoRadi"));
|
||||
if (nogoList != null) {
|
||||
RoutingContext.prepareNogoPoints(nogoList);
|
||||
if (rctx.nogopoints == null) {
|
||||
rctx.nogopoints = nogoList;
|
||||
} else {
|
||||
rctx.nogopoints.addAll(nogoList);
|
||||
}
|
||||
}
|
||||
params.remove("nogoLats");
|
||||
params.remove("nogoLons");
|
||||
params.remove("nogoRadi");
|
||||
}
|
||||
if (params.containsKey("nogos")) {
|
||||
List<OsmNodeNamed> nogoList = readNogoList(params.get("nogos"));
|
||||
if (nogoList != null) {
|
||||
RoutingContext.prepareNogoPoints(nogoList);
|
||||
if (rctx.nogopoints == null) {
|
||||
rctx.nogopoints = nogoList;
|
||||
} else {
|
||||
rctx.nogopoints.addAll(nogoList);
|
||||
}
|
||||
}
|
||||
params.remove("nogos");
|
||||
}
|
||||
if (params.containsKey("polylines")) {
|
||||
List<OsmNodeNamed> result = new ArrayList<>();
|
||||
parseNogoPolygons(params.get("polylines"), result, false);
|
||||
if (rctx.nogopoints == null) {
|
||||
rctx.nogopoints = result;
|
||||
} else {
|
||||
rctx.nogopoints.addAll(result);
|
||||
}
|
||||
params.remove("polylines");
|
||||
}
|
||||
if (params.containsKey("polygons")) {
|
||||
List<OsmNodeNamed> result = new ArrayList<>();
|
||||
parseNogoPolygons(params.get("polygons"), result, true);
|
||||
if (rctx.nogopoints == null) {
|
||||
rctx.nogopoints = result;
|
||||
} else {
|
||||
rctx.nogopoints.addAll(result);
|
||||
}
|
||||
params.remove("polygons");
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> e : params.entrySet()) {
|
||||
String key = e.getKey();
|
||||
String value = e.getValue();
|
||||
if (DEBUG) System.out.println("params " + key + " " + value);
|
||||
|
||||
if (key.equals("straight")) {
|
||||
try {
|
||||
String[] sa = value.split(",");
|
||||
for (int i = 0; i < sa.length; i++) {
|
||||
int v = Integer.parseInt(sa[i]);
|
||||
if (wplist.size() > v) wplist.get(v).direct = true;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
System.err.println("error " + ex.getStackTrace()[0].getLineNumber() + " " + ex.getStackTrace()[0] + "\n" + ex);
|
||||
}
|
||||
} else if (key.equals("pois")) {
|
||||
rctx.poipoints = readPoisList(value);
|
||||
} else if (key.equals("heading")) {
|
||||
rctx.startDirection = Integer.valueOf(value);
|
||||
rctx.forceUseStartDirection = true;
|
||||
} else if (key.equals("direction")) {
|
||||
rctx.startDirection = Integer.valueOf(value);
|
||||
} else if (key.equals("alternativeidx")) {
|
||||
rctx.setAlternativeIdx(Integer.parseInt(value));
|
||||
} else if (key.equals("turnInstructionMode")) {
|
||||
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")) {
|
||||
rctx.outputFormat = ((String) value).toLowerCase();
|
||||
} else if (key.equals("trackFormat")) {
|
||||
rctx.outputFormat = ((String) value).toLowerCase();
|
||||
} else if (key.startsWith("profile:")) {
|
||||
if (rctx.keyValues == null) rctx.keyValues = new HashMap<>();
|
||||
rctx.keyValues.put(key.substring(8), value);
|
||||
}
|
||||
// ignore other params
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fill profile parameter list
|
||||
*
|
||||
* @param rctx the routing context
|
||||
* @param params the list of parameters
|
||||
*/
|
||||
public void setProfileParams(RoutingContext rctx, Map<String, String> params) {
|
||||
if (params != null) {
|
||||
if (params.size() == 0) return;
|
||||
if (rctx.keyValues == null) rctx.keyValues = new HashMap<>();
|
||||
for (Map.Entry<String, String> e : params.entrySet()) {
|
||||
String key = e.getKey();
|
||||
String value = e.getValue();
|
||||
if (DEBUG) System.out.println("params " + key + " " + value);
|
||||
rctx.keyValues.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void parseNogoPolygons(String polygons, List<OsmNodeNamed> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<OsmNodeNamed> readPoisList(String pois) {
|
||||
// lon,lat,name|...
|
||||
if (pois == null) return null;
|
||||
|
||||
String[] lonLatNameList = pois.split("\\|");
|
||||
|
||||
List<OsmNodeNamed> 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;
|
||||
}
|
||||
|
||||
public List<OsmNodeNamed> readNogoList(String nogos) {
|
||||
// lon,lat,radius[,weight]|...
|
||||
|
||||
if (nogos == null) return null;
|
||||
|
||||
String[] lonLatRadList = nogos.split("\\|");
|
||||
|
||||
List<OsmNodeNamed> 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;
|
||||
}
|
||||
|
||||
public List<OsmNodeNamed> readNogos(String nogoLons, String nogoLats, String nogoRadi) {
|
||||
if (nogoLons == null || nogoLats == null || nogoRadi == null) return null;
|
||||
List<OsmNodeNamed> nogoList = new ArrayList<>();
|
||||
|
||||
String[] lons = nogoLons.split(",");
|
||||
String[] lats = nogoLats.split(",");
|
||||
String[] radi = nogoRadi.split(",");
|
||||
String nogoWeight = "undefined";
|
||||
for (int i = 0; i < lons.length && i < lats.length && i < radi.length; i++) {
|
||||
OsmNodeNamed n = readNogo(lons[i].trim(), lats[i].trim(), radi[i].trim(), nogoWeight);
|
||||
nogoList.add(n);
|
||||
}
|
||||
return nogoList;
|
||||
}
|
||||
|
||||
|
||||
private 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), (int) Double.parseDouble(radius), weight);
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -49,6 +49,8 @@ final class StdPath extends OsmPath {
|
|||
float turncostbase = rc.expctxWay.getTurncost();
|
||||
float uphillcutoff = rc.expctxWay.getUphillcutoff() * 10000;
|
||||
float downhillcutoff = rc.expctxWay.getDownhillcutoff() * 10000;
|
||||
float uphillmaxslope = rc.expctxWay.getUphillmaxslope() * 10000;
|
||||
float downhillmaxslope = rc.expctxWay.getDownhillmaxslope() * 10000;
|
||||
float cfup = rc.expctxWay.getUphillCostfactor();
|
||||
float cfdown = rc.expctxWay.getDownhillCostfactor();
|
||||
float cf = rc.expctxWay.getCostfactor();
|
||||
|
|
@ -60,11 +62,27 @@ final class StdPath extends OsmPath {
|
|||
downhillcostdiv = 1000000 / downhillcostdiv;
|
||||
}
|
||||
|
||||
int downhillmaxslopecostdiv = (int) rc.expctxWay.getDownhillmaxslopecost();
|
||||
if (downhillmaxslopecostdiv > 0) {
|
||||
downhillmaxslopecostdiv = 1000000 / downhillmaxslopecostdiv;
|
||||
} else {
|
||||
// if not given, use legacy behavior
|
||||
downhillmaxslopecostdiv = downhillcostdiv;
|
||||
}
|
||||
|
||||
uphillcostdiv = (int) rc.expctxWay.getUphillcost();
|
||||
if (uphillcostdiv > 0) {
|
||||
uphillcostdiv = 1000000 / uphillcostdiv;
|
||||
}
|
||||
|
||||
int uphillmaxslopecostdiv = (int) rc.expctxWay.getUphillmaxslopecost();
|
||||
if (uphillmaxslopecostdiv > 0) {
|
||||
uphillmaxslopecostdiv = 1000000 / uphillmaxslopecostdiv;
|
||||
} else {
|
||||
// if not given, use legacy behavior
|
||||
uphillmaxslopecostdiv = uphillcostdiv;
|
||||
}
|
||||
|
||||
int dist = (int) distance; // legacy arithmetics needs int
|
||||
|
||||
// penalty for turning angle
|
||||
|
|
@ -99,8 +117,14 @@ final class StdPath extends OsmPath {
|
|||
reduce = excess;
|
||||
}
|
||||
ehbd -= reduce;
|
||||
float elevationCost = 0.f;
|
||||
if (downhillcostdiv > 0) {
|
||||
int elevationCost = reduce / downhillcostdiv;
|
||||
elevationCost += Math.min(reduce, dist * downhillmaxslope) / downhillcostdiv;
|
||||
}
|
||||
if (downhillmaxslopecostdiv > 0) {
|
||||
elevationCost += Math.max(0, reduce - dist * downhillmaxslope) / downhillmaxslopecostdiv;
|
||||
}
|
||||
if (elevationCost > 0) {
|
||||
sectionCost += elevationCost;
|
||||
if (message != null) {
|
||||
message.linkelevationcost += elevationCost;
|
||||
|
|
@ -125,8 +149,14 @@ final class StdPath extends OsmPath {
|
|||
reduce = excess;
|
||||
}
|
||||
ehbu -= reduce;
|
||||
float elevationCost = 0.f;
|
||||
if (uphillcostdiv > 0) {
|
||||
int elevationCost = reduce / uphillcostdiv;
|
||||
elevationCost += Math.min(reduce, dist * uphillmaxslope) / uphillcostdiv;
|
||||
}
|
||||
if (uphillmaxslopecostdiv > 0) {
|
||||
elevationCost += Math.max(0, reduce - dist * uphillmaxslope) / uphillmaxslopecostdiv;
|
||||
}
|
||||
if (elevationCost > 0) {
|
||||
sectionCost += elevationCost;
|
||||
if (message != null) {
|
||||
message.linkelevationcost += elevationCost;
|
||||
|
|
|
|||
|
|
@ -20,11 +20,11 @@ public class VoiceHint {
|
|||
static final int KL = 8; // keep left
|
||||
static final int KR = 9; // keep right
|
||||
static final int TLU = 10; // U-turn
|
||||
static final int TU = 11; // 180 degree u-turn
|
||||
static final int TRU = 12; // Right U-turn
|
||||
static final int OFFR = 13; // Off route
|
||||
static final int RNDB = 14; // Roundabout
|
||||
static final int RNLB = 15; // Roundabout left
|
||||
static final int TRU = 11; // Right U-turn
|
||||
static final int OFFR = 12; // Off route
|
||||
static final int RNDB = 13; // Roundabout
|
||||
static final int RNLB = 14; // Roundabout left
|
||||
static final int TU = 15; // 180 degree u-turn
|
||||
static final int BL = 16; // Beeline routing
|
||||
|
||||
int ilon;
|
||||
|
|
@ -44,6 +44,7 @@ public class VoiceHint {
|
|||
float angle = Float.MAX_VALUE;
|
||||
boolean turnAngleConsumed;
|
||||
boolean needsRealTurn;
|
||||
int maxBadPrio = -1;
|
||||
|
||||
int roundaboutExit;
|
||||
|
||||
|
|
@ -61,8 +62,43 @@ public class VoiceHint {
|
|||
badWays.add(badWay);
|
||||
}
|
||||
|
||||
public int getCommand() {
|
||||
return cmd;
|
||||
public int getJsonCommandIndex() {
|
||||
switch (cmd) {
|
||||
case TLU:
|
||||
return 10;
|
||||
case TU:
|
||||
return 15;
|
||||
case TSHL:
|
||||
return 4;
|
||||
case TL:
|
||||
return 2;
|
||||
case TSLL:
|
||||
return 3;
|
||||
case KL:
|
||||
return 8;
|
||||
case C:
|
||||
return 1;
|
||||
case KR:
|
||||
return 9;
|
||||
case TSLR:
|
||||
return 6;
|
||||
case TR:
|
||||
return 5;
|
||||
case TSHR:
|
||||
return 7;
|
||||
case TRU:
|
||||
return 11;
|
||||
case RNDB:
|
||||
return 13;
|
||||
case RNLB:
|
||||
return 14;
|
||||
case BL:
|
||||
return 16;
|
||||
case OFFR:
|
||||
return 12;
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown command: " + cmd);
|
||||
}
|
||||
}
|
||||
|
||||
public int getExitNumber() {
|
||||
|
|
|
|||
|
|
@ -10,23 +10,50 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
public class VoiceHintList {
|
||||
private String transportMode;
|
||||
|
||||
static final int TRANS_MODE_NONE = 0;
|
||||
static final int TRANS_MODE_FOOT = 1;
|
||||
static final int TRANS_MODE_BIKE = 2;
|
||||
static final int TRANS_MODE_CAR = 3;
|
||||
|
||||
private int transportMode = TRANS_MODE_BIKE;
|
||||
int turnInstructionMode;
|
||||
List<VoiceHint> list = new ArrayList<>();
|
||||
|
||||
public void setTransportMode(boolean isCar, boolean isBike) {
|
||||
transportMode = isCar ? "car" : (isBike ? "bike" : "foot");
|
||||
transportMode = isCar ? TRANS_MODE_CAR : (isBike ? TRANS_MODE_BIKE : TRANS_MODE_FOOT);
|
||||
}
|
||||
|
||||
public void setTransportMode(int mode) {
|
||||
transportMode = mode;
|
||||
}
|
||||
|
||||
public String getTransportMode() {
|
||||
String ret;
|
||||
switch (transportMode) {
|
||||
case TRANS_MODE_FOOT:
|
||||
ret = "foot";
|
||||
break;
|
||||
case TRANS_MODE_CAR:
|
||||
ret = "car";
|
||||
break;
|
||||
case TRANS_MODE_BIKE:
|
||||
default:
|
||||
ret = "bike";
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public int transportMode() {
|
||||
return transportMode;
|
||||
}
|
||||
|
||||
public int getLocusRouteType() {
|
||||
if ("car".equals(transportMode)) {
|
||||
if (transportMode == TRANS_MODE_CAR) {
|
||||
return 0;
|
||||
}
|
||||
if ("bike".equals(transportMode)) {
|
||||
if (transportMode == TRANS_MODE_BIKE) {
|
||||
return 5;
|
||||
}
|
||||
return 3; // foot
|
||||
|
|
|
|||
|
|
@ -15,10 +15,12 @@ public final class VoiceHintProcessor {
|
|||
|
||||
// private double catchingRange; // range to catch angles and merge turns
|
||||
private boolean explicitRoundabouts;
|
||||
private int transportMode;
|
||||
|
||||
public VoiceHintProcessor(double catchingRange, boolean explicitRoundabouts) {
|
||||
public VoiceHintProcessor(double catchingRange, boolean explicitRoundabouts, int transportMode) {
|
||||
// this.catchingRange = catchingRange;
|
||||
this.explicitRoundabouts = explicitRoundabouts;
|
||||
this.transportMode = transportMode;
|
||||
}
|
||||
|
||||
private float sumNonConsumedWithinCatchingRange(List<VoiceHint> inputs, int offset) {
|
||||
|
|
@ -81,10 +83,21 @@ public final class VoiceHintProcessor {
|
|||
if (explicitRoundabouts && input.oldWay.isRoundabout()) {
|
||||
if (roundaboudStartIdx == -1) roundaboudStartIdx = hintIdx;
|
||||
roundAboutTurnAngle += sumNonConsumedWithinCatchingRange(inputs, hintIdx);
|
||||
if (roundaboudStartIdx == hintIdx) {
|
||||
if (input.badWays != null) {
|
||||
// remove goodWay
|
||||
roundAboutTurnAngle -= input.goodWay.turnangle;
|
||||
// add a badWay
|
||||
for (MessageData badWay : input.badWays) {
|
||||
if (!badWay.isBadOneway()) roundAboutTurnAngle += badWay.turnangle;
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean isExit = roundaboutExit == 0; // exit point is always exit
|
||||
if (input.badWays != null) {
|
||||
for (MessageData badWay : input.badWays) {
|
||||
if (!badWay.isBadOneway() && badWay.isGoodForCars() && Math.abs(badWay.turnangle) < 120.) {
|
||||
if (!badWay.isBadOneway() &&
|
||||
badWay.isGoodForCars()) {
|
||||
isExit = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -95,12 +108,35 @@ public final class VoiceHintProcessor {
|
|||
continue;
|
||||
}
|
||||
if (roundaboutExit > 0) {
|
||||
roundAboutTurnAngle += sumNonConsumedWithinCatchingRange(inputs, hintIdx);
|
||||
double startTurn = (roundaboudStartIdx != -1 ? inputs.get(roundaboudStartIdx).goodWay.turnangle : turnAngle);
|
||||
//roundAboutTurnAngle += sumNonConsumedWithinCatchingRange(inputs, hintIdx);
|
||||
//double startTurn = (roundaboudStartIdx != -1 ? inputs.get(roundaboudStartIdx + 1).goodWay.turnangle : turnAngle);
|
||||
input.angle = roundAboutTurnAngle;
|
||||
input.goodWay.turnangle = roundAboutTurnAngle;
|
||||
input.distanceToNext = distance;
|
||||
input.roundaboutExit = startTurn < 0 ? -roundaboutExit : roundaboutExit;
|
||||
//input.roundaboutExit = startTurn < 0 ? roundaboutExit : -roundaboutExit;
|
||||
input.roundaboutExit = roundAboutTurnAngle < 0 ? roundaboutExit : -roundaboutExit;
|
||||
float tmpangle = 0;
|
||||
VoiceHint tmpRndAbt = new VoiceHint();
|
||||
tmpRndAbt.badWays = new ArrayList<>();
|
||||
for (int i = hintIdx-1; i > roundaboudStartIdx; i--) {
|
||||
VoiceHint vh = inputs.get(i);
|
||||
tmpangle += inputs.get(i).goodWay.turnangle;
|
||||
if (vh.badWays != null) {
|
||||
for (MessageData badWay : vh.badWays) {
|
||||
if (!badWay.isBadOneway()) {
|
||||
MessageData md = new MessageData();
|
||||
md.linkdist = vh.goodWay.linkdist;
|
||||
md.priorityclassifier = vh.goodWay.priorityclassifier;
|
||||
md.turnangle = tmpangle;
|
||||
tmpRndAbt.badWays.add(md);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
distance = 0.;
|
||||
|
||||
input.badWays = tmpRndAbt.badWays;
|
||||
|
||||
results.add(input);
|
||||
roundAboutTurnAngle = 0.f;
|
||||
roundaboutExit = 0;
|
||||
|
|
@ -127,10 +163,7 @@ public final class VoiceHintProcessor {
|
|||
|
||||
if (badPrio > maxPrioAll && !isBadHighway2Link) {
|
||||
maxPrioAll = badPrio;
|
||||
}
|
||||
|
||||
if (badWay.costfactor < 20.f && Math.abs(badTurn) < minAbsAngeRaw) {
|
||||
minAbsAngeRaw = Math.abs(badTurn);
|
||||
input.maxBadPrio = Math.max(input.maxBadPrio, badPrio);
|
||||
}
|
||||
|
||||
if (badPrio < minPrio) {
|
||||
|
|
@ -145,8 +178,13 @@ public final class VoiceHintProcessor {
|
|||
continue; // ways from the back should not trigger a slight turn
|
||||
}
|
||||
|
||||
if (badWay.costfactor < 20.f && Math.abs(badTurn) < minAbsAngeRaw) {
|
||||
minAbsAngeRaw = Math.abs(badTurn);
|
||||
}
|
||||
|
||||
if (badPrio > maxPrioCandidates) {
|
||||
maxPrioCandidates = badPrio;
|
||||
input.maxBadPrio = Math.max(input.maxBadPrio, badPrio);
|
||||
}
|
||||
if (badTurn > maxAngle) {
|
||||
maxAngle = badTurn;
|
||||
|
|
@ -157,7 +195,8 @@ public final class VoiceHintProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
boolean hasSomethingMoreStraight = (Math.abs(turnAngle) - minAbsAngeRaw) > 20.;
|
||||
// boolean hasSomethingMoreStraight = (Math.abs(turnAngle) - minAbsAngeRaw) > 20.;
|
||||
boolean hasSomethingMoreStraight = (Math.abs(turnAngle - minAbsAngeRaw)) > 20. && input.badWays != null; // && !ignoreBadway;
|
||||
|
||||
// unconditional triggers are all junctions with
|
||||
// - higher detour prios than the minimum route prio (except link->highway junctions)
|
||||
|
|
@ -244,78 +283,132 @@ public final class VoiceHintProcessor {
|
|||
List<VoiceHint> results = new ArrayList<>();
|
||||
double distance = 0;
|
||||
VoiceHint inputLast = null;
|
||||
ArrayList<VoiceHint> tmpList = new ArrayList<>();
|
||||
VoiceHint inputLastSaved = null;
|
||||
for (int hintIdx = 0; hintIdx < inputs.size(); hintIdx++) {
|
||||
VoiceHint input = inputs.get(hintIdx);
|
||||
VoiceHint nextInput = null;
|
||||
if (hintIdx + 1 < inputs.size()) {
|
||||
nextInput = inputs.get(hintIdx + 1);
|
||||
}
|
||||
|
||||
if (input.cmd == VoiceHint.C && !input.goodWay.isLinktType()) {
|
||||
int badWayPrio = 0;
|
||||
for (MessageData md : input.badWays) {
|
||||
badWayPrio = Math.max(badWayPrio, md.getPrio());
|
||||
}
|
||||
if (input.goodWay.getPrio() < badWayPrio) {
|
||||
results.add(input);
|
||||
} else {
|
||||
if (inputLast != null) { // when drop add distance to last
|
||||
inputLast.distanceToNext += input.distanceToNext;
|
||||
if (nextInput == null) {
|
||||
if (input.cmd == VoiceHint.C && !input.goodWay.isLinktType()) {
|
||||
if (input.goodWay.getPrio() < input.maxBadPrio && (inputLastSaved != null && inputLastSaved.distanceToNext > catchingRange)) {
|
||||
results.add(input);
|
||||
} else {
|
||||
if (inputLast != null) { // when drop add distance to last
|
||||
inputLast.distanceToNext += input.distanceToNext;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
results.add(input);
|
||||
}
|
||||
} else {
|
||||
if (input.distanceToNext < catchingRange) {
|
||||
if ((inputLastSaved != null && inputLastSaved.distanceToNext > catchingRange) || input.distanceToNext > catchingRange) {
|
||||
if (input.cmd == VoiceHint.C && !input.goodWay.isLinktType()) {
|
||||
if (input.goodWay.getPrio() < input.maxBadPrio
|
||||
&& (inputLastSaved != null && inputLastSaved.distanceToNext > minRange)
|
||||
&& (input.distanceToNext > minRange)) {
|
||||
// add only on prio
|
||||
results.add(input);
|
||||
inputLastSaved = input;
|
||||
} else {
|
||||
if (inputLastSaved != null) { // when drop add distance to last
|
||||
inputLastSaved.distanceToNext += input.distanceToNext;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// add all others
|
||||
// ignore motorway / primary continue
|
||||
if (((input.goodWay.getPrio() != 28) &&
|
||||
(input.goodWay.getPrio() != 30) &&
|
||||
(input.goodWay.getPrio() != 26))
|
||||
|| input.isRoundabout()
|
||||
|| Math.abs(input.angle) > 21.f) {
|
||||
results.add(input);
|
||||
inputLastSaved = input;
|
||||
} else {
|
||||
if (inputLastSaved != null) { // when drop add distance to last
|
||||
inputLastSaved.distanceToNext += input.distanceToNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (input.distanceToNext < catchingRange) {
|
||||
double dist = input.distanceToNext;
|
||||
float angles = input.angle;
|
||||
int i = 1;
|
||||
boolean save = true;
|
||||
tmpList.clear();
|
||||
while (dist < catchingRange && hintIdx + i < inputs.size()) {
|
||||
VoiceHint h2 = inputs.get(hintIdx + i);
|
||||
dist += h2.distanceToNext;
|
||||
angles += h2.angle;
|
||||
if (VoiceHint.is180DegAngle(input.angle) || VoiceHint.is180DegAngle(h2.angle)) { // u-turn, 180 degree
|
||||
save = true;
|
||||
break;
|
||||
} else if (Math.abs(angles) > 180 - SIGNIFICANT_ANGLE) { // u-turn, collects e.g. two left turns in range
|
||||
input.angle = angles;
|
||||
input.calcCommand();
|
||||
input.distanceToNext += h2.distanceToNext;
|
||||
save = true;
|
||||
hintIdx++;
|
||||
break;
|
||||
} else if (Math.abs(angles) < SIGNIFICANT_ANGLE && input.distanceToNext < minRange) {
|
||||
input.angle = angles;
|
||||
input.calcCommand();
|
||||
input.distanceToNext += h2.distanceToNext;
|
||||
save = true;
|
||||
hintIdx++;
|
||||
break;
|
||||
} else if (Math.abs(input.angle) > SIGNIFICANT_ANGLE) {
|
||||
tmpList.add(h2);
|
||||
hintIdx++;
|
||||
} else if (dist > catchingRange) { // distance reached
|
||||
break;
|
||||
} else {
|
||||
if (inputLast != null) { // when drop add distance to last
|
||||
inputLast.distanceToNext += input.distanceToNext;
|
||||
boolean save = false;
|
||||
|
||||
dist += nextInput.distanceToNext;
|
||||
angles += nextInput.angle;
|
||||
|
||||
if (input.cmd == VoiceHint.C && !input.goodWay.isLinktType()) {
|
||||
if (input.goodWay.getPrio() < input.maxBadPrio) {
|
||||
if (inputLastSaved != null && inputLastSaved.cmd != VoiceHint.C
|
||||
&& (inputLastSaved != null && inputLastSaved.distanceToNext > minRange)
|
||||
&& transportMode != VoiceHintList.TRANS_MODE_CAR) {
|
||||
// add when straight and not linktype
|
||||
// and last vh not straight
|
||||
save = true;
|
||||
// remove when next straight and not linktype
|
||||
if (nextInput != null &&
|
||||
nextInput.cmd == VoiceHint.C &&
|
||||
!nextInput.goodWay.isLinktType()) {
|
||||
input.distanceToNext += nextInput.distanceToNext;
|
||||
hintIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (inputLastSaved != null) { // when drop add distance to last
|
||||
inputLastSaved.distanceToNext += input.distanceToNext;
|
||||
}
|
||||
save = false;
|
||||
}
|
||||
i++;
|
||||
} else if (VoiceHint.is180DegAngle(input.angle)) {
|
||||
// add u-turn, 180 degree
|
||||
save = true;
|
||||
} else if (transportMode == VoiceHintList.TRANS_MODE_CAR && Math.abs(angles) > 180 - SIGNIFICANT_ANGLE) {
|
||||
// add when inc car mode and u-turn, collects e.g. two left turns in range
|
||||
input.angle = angles;
|
||||
input.calcCommand();
|
||||
input.distanceToNext += nextInput.distanceToNext;
|
||||
save = true;
|
||||
hintIdx++;
|
||||
} else if (Math.abs(angles) < SIGNIFICANT_ANGLE && input.distanceToNext < minRange) {
|
||||
input.angle = angles;
|
||||
input.calcCommand();
|
||||
input.distanceToNext += nextInput.distanceToNext;
|
||||
save = true;
|
||||
hintIdx++;
|
||||
} else if (Math.abs(input.angle) > SIGNIFICANT_ANGLE) {
|
||||
// add when angle above 22.5 deg
|
||||
save = true;
|
||||
} else if (Math.abs(input.angle) < SIGNIFICANT_ANGLE) {
|
||||
// add when angle below 22.5 deg ???
|
||||
// save = true;
|
||||
} else {
|
||||
// otherwise ignore but add distance to next
|
||||
if (nextInput != null) { // when drop add distance to last
|
||||
nextInput.distanceToNext += input.distanceToNext;
|
||||
}
|
||||
save = false;
|
||||
}
|
||||
|
||||
if (save) {
|
||||
results.add(input); // add when last
|
||||
if (tmpList.size() > 0) { // add when something in stock
|
||||
results.addAll(tmpList);
|
||||
hintIdx += tmpList.size() - 1;
|
||||
}
|
||||
inputLastSaved = input;
|
||||
}
|
||||
} else {
|
||||
results.add(input);
|
||||
inputLastSaved = input;
|
||||
}
|
||||
inputLast = input;
|
||||
}
|
||||
inputLast = input;
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
68
brouter-core/src/test/java/btools/router/RouteParamTest.java
Normal file
68
brouter-core/src/test/java/btools/router/RouteParamTest.java
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
package btools.router;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class RouteParamTest {
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void readWptsNull() {
|
||||
|
||||
RoutingParamCollector rpc = new RoutingParamCollector();
|
||||
List<OsmNodeNamed> map = rpc.getWayPointList(null);
|
||||
|
||||
Assert.assertEquals("result content null", 0, map.size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readWpts() {
|
||||
String data = "1.0,1.2;2.0,2.2";
|
||||
RoutingParamCollector rpc = new RoutingParamCollector();
|
||||
List<OsmNodeNamed> map = rpc.getWayPointList(data);
|
||||
|
||||
Assert.assertEquals("result content 1 ", 2, map.size());
|
||||
|
||||
data = "1.0,1.1|2.0,2.2|3.0,3.3";
|
||||
map = rpc.getWayPointList(data);
|
||||
|
||||
Assert.assertEquals("result content 2 ", 3, map.size());
|
||||
|
||||
data = "1.0,1.2,Name;2.0,2.2";
|
||||
map = rpc.getWayPointList(data);
|
||||
|
||||
Assert.assertEquals("result content 3 ", "Name", map.get(0).name);
|
||||
|
||||
data = "1.0,1.2,d;2.0,2.2";
|
||||
map = rpc.getWayPointList(data);
|
||||
|
||||
Assert.assertTrue("result content 4 ", map.get(0).direct);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readUrlParams() throws UnsupportedEncodingException {
|
||||
String url = "lonlats=1,1;2,2&profile=test&more=1";
|
||||
RoutingParamCollector rpc = new RoutingParamCollector();
|
||||
Map<String, String> map = rpc.getUrlParams(url);
|
||||
|
||||
Assert.assertEquals("result content ", 3, map.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readParamsFromList() throws UnsupportedEncodingException {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("timode", "3");
|
||||
RoutingContext rc = new RoutingContext();
|
||||
RoutingParamCollector rpc = new RoutingParamCollector();
|
||||
rpc.setParams(rc, null, params);
|
||||
|
||||
Assert.assertEquals("result content timode ", 3, rc.turnInstructionMode);
|
||||
}
|
||||
|
||||
}
|
||||
1
brouter-expressions/.gitignore
vendored
1
brouter-expressions/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
/build/
|
||||
|
|
@ -1,9 +1,8 @@
|
|||
plugins {
|
||||
id 'java-library'
|
||||
id 'brouter.library-conventions'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':brouter-util')
|
||||
implementation project(':brouter-codec')
|
||||
testImplementation 'junit:junit:4.13.1'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<manifest package="btools.expressions" />
|
||||
|
|
@ -9,14 +9,15 @@ final class BExpression {
|
|||
|
||||
private static final int ADD_EXP = 20;
|
||||
private static final int MULTIPLY_EXP = 21;
|
||||
private static final int MAX_EXP = 22;
|
||||
private static final int EQUAL_EXP = 23;
|
||||
private static final int GREATER_EXP = 24;
|
||||
private static final int MIN_EXP = 25;
|
||||
private static final int DIVIDE_EXP = 22;
|
||||
private static final int MAX_EXP = 23;
|
||||
private static final int EQUAL_EXP = 24;
|
||||
private static final int GREATER_EXP = 25;
|
||||
private static final int MIN_EXP = 26;
|
||||
|
||||
private static final int SUB_EXP = 26;
|
||||
private static final int LESSER_EXP = 27;
|
||||
private static final int XOR_EXP = 28;
|
||||
private static final int SUB_EXP = 27;
|
||||
private static final int LESSER_EXP = 28;
|
||||
private static final int XOR_EXP = 29;
|
||||
|
||||
private static final int SWITCH_EXP = 30;
|
||||
private static final int ASSIGN_EXP = 31;
|
||||
|
|
@ -66,11 +67,11 @@ final class BExpression {
|
|||
} else {
|
||||
BExpression eCollapsed = e.tryCollapse();
|
||||
if (e != eCollapsed) {
|
||||
e = eCollapsed; // allow breakspoint..
|
||||
e = eCollapsed; // allow breakpoint..
|
||||
}
|
||||
BExpression eEvaluated = e.tryEvaluateConstant();
|
||||
if (e != eEvaluated) {
|
||||
e = eEvaluated; // allow breakspoint..
|
||||
e = eEvaluated; // allow breakpoint..
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -144,6 +145,8 @@ final class BExpression {
|
|||
exp.typ = AND_EXP;
|
||||
} else if ("multiply".equals(operator)) {
|
||||
exp.typ = MULTIPLY_EXP;
|
||||
} else if ("divide".equals(operator)) {
|
||||
exp.typ = DIVIDE_EXP;
|
||||
} else if ("add".equals(operator)) {
|
||||
exp.typ = ADD_EXP;
|
||||
} else if ("max".equals(operator)) {
|
||||
|
|
@ -239,15 +242,15 @@ final class BExpression {
|
|||
}
|
||||
// parse operands
|
||||
if (nops > 0) {
|
||||
exp.op1 = BExpression.parse(ctx, level + 1, exp.typ == ASSIGN_EXP ? "=" : null);
|
||||
exp.op1 = parse(ctx, level + 1, exp.typ == ASSIGN_EXP ? "=" : null);
|
||||
}
|
||||
if (nops > 1) {
|
||||
if (ifThenElse) checkExpectedToken(ctx, "then");
|
||||
exp.op2 = BExpression.parse(ctx, level + 1, null);
|
||||
exp.op2 = parse(ctx, level + 1, null);
|
||||
}
|
||||
if (nops > 2) {
|
||||
if (ifThenElse) checkExpectedToken(ctx, "else");
|
||||
exp.op3 = BExpression.parse(ctx, level + 1, null);
|
||||
exp.op3 = parse(ctx, level + 1, null);
|
||||
}
|
||||
if (brackets) {
|
||||
checkExpectedToken(ctx, ")");
|
||||
|
|
@ -277,6 +280,8 @@ final class BExpression {
|
|||
return op1.evaluate(ctx) - op2.evaluate(ctx);
|
||||
case MULTIPLY_EXP:
|
||||
return op1.evaluate(ctx) * op2.evaluate(ctx);
|
||||
case DIVIDE_EXP:
|
||||
return divide(op1.evaluate(ctx), op2.evaluate(ctx));
|
||||
case MAX_EXP:
|
||||
return max(op1.evaluate(ctx), op2.evaluate(ctx));
|
||||
case MIN_EXP:
|
||||
|
|
@ -360,6 +365,11 @@ final class BExpression {
|
|||
return v1 < v2 ? v1 : v2;
|
||||
}
|
||||
|
||||
private float divide(float v1, float v2) {
|
||||
if (v2 == 0f) throw new IllegalArgumentException("div by zero");
|
||||
return v1 / v2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (typ == NUMBER_EXP) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import java.util.Arrays;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.Random;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TreeMap;
|
||||
|
|
@ -227,7 +228,7 @@ public abstract class BExpressionContext implements IByteArrayUnifier {
|
|||
}
|
||||
|
||||
public List<String> getKeyValueList(boolean inverseDirection, byte[] ab) {
|
||||
ArrayList<String> res = new ArrayList<>();
|
||||
List<String> res = new ArrayList<>();
|
||||
decode(lookupData, inverseDirection, ab);
|
||||
for (int inum = 0; inum < lookupValues.size(); inum++) { // loop over lookup names
|
||||
BExpressionLookupValue[] va = lookupValues.get(inum);
|
||||
|
|
@ -245,7 +246,7 @@ public abstract class BExpressionContext implements IByteArrayUnifier {
|
|||
public int getLookupKey(String name) {
|
||||
int res = -1;
|
||||
try {
|
||||
res = lookupNumbers.get(name).intValue();
|
||||
res = lookupNumbers.get(name);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return res;
|
||||
|
|
@ -433,11 +434,11 @@ public abstract class BExpressionContext implements IByteArrayUnifier {
|
|||
|
||||
|
||||
public void dumpStatistics() {
|
||||
TreeMap<String, String> counts = new TreeMap<>();
|
||||
NavigableMap<String, String> counts = new TreeMap<>();
|
||||
// first count
|
||||
for (String name : lookupNumbers.keySet()) {
|
||||
int cnt = 0;
|
||||
int inum = lookupNumbers.get(name).intValue();
|
||||
int inum = lookupNumbers.get(name);
|
||||
int[] histo = lookupHistograms.get(inum);
|
||||
// if ( histo.length == 500 ) continue;
|
||||
for (int i = 2; i < histo.length; i++) {
|
||||
|
|
@ -450,7 +451,7 @@ public abstract class BExpressionContext implements IByteArrayUnifier {
|
|||
String key = counts.lastEntry().getKey();
|
||||
String name = counts.get(key);
|
||||
counts.remove(key);
|
||||
int inum = lookupNumbers.get(name).intValue();
|
||||
int inum = lookupNumbers.get(name);
|
||||
BExpressionLookupValue[] values = lookupValues.get(inum);
|
||||
int[] histo = lookupHistograms.get(inum);
|
||||
if (values.length == 1000) continue;
|
||||
|
|
@ -507,7 +508,7 @@ public abstract class BExpressionContext implements IByteArrayUnifier {
|
|||
|
||||
public String variableName(int idx) {
|
||||
for (Map.Entry<String, Integer> e : variableNumbers.entrySet()) {
|
||||
if (e.getValue().intValue() == idx) {
|
||||
if (e.getValue() == idx) {
|
||||
return e.getKey();
|
||||
}
|
||||
}
|
||||
|
|
@ -544,9 +545,8 @@ public abstract class BExpressionContext implements IByteArrayUnifier {
|
|||
}
|
||||
|
||||
// look for that value
|
||||
int inum = num.intValue();
|
||||
BExpressionLookupValue[] values = lookupValues.get(inum);
|
||||
int[] histo = lookupHistograms.get(inum);
|
||||
BExpressionLookupValue[] values = lookupValues.get(num);
|
||||
int[] histo = lookupHistograms.get(num);
|
||||
int i = 0;
|
||||
boolean bFoundAsterix = false;
|
||||
for (; i < values.length; i++) {
|
||||
|
|
@ -558,102 +558,105 @@ public abstract class BExpressionContext implements IByteArrayUnifier {
|
|||
if (lookupData2 != null) {
|
||||
// do not create unknown value for external data array,
|
||||
// record as 'unknown' instead
|
||||
lookupData2[inum] = 1; // 1 == unknown
|
||||
lookupData2[num] = 1; // 1 == unknown
|
||||
if (bFoundAsterix) {
|
||||
// found value for lookup *
|
||||
//System.out.println( "add unknown " + name + " " + value );
|
||||
String org = value;
|
||||
try {
|
||||
// remove some unused characters
|
||||
value = value.replace(",", ".");
|
||||
value = value.replace(">", "");
|
||||
value = value.replace("_", "");
|
||||
value = value.replaceAll(",", ".");
|
||||
value = value.replaceAll(">", "");
|
||||
value = value.replaceAll("_", "");
|
||||
value = value.replaceAll(" ", "");
|
||||
value = value.replaceAll("~", "");
|
||||
value = value.replace((char) 8217, '\'');
|
||||
value = value.replace((char) 8221, '"');
|
||||
if (value.indexOf("-") == 0) value = value.substring(1);
|
||||
if (value.indexOf("~") == 0) value = value.substring(1);
|
||||
if (value.contains("-")) { // replace eg. 1.4-1.6 m
|
||||
if (value.contains("-")) {
|
||||
// replace eg. 1.4-1.6 m to 1.4m
|
||||
// but also 1'-6" to 1'
|
||||
// keep the unit of measure
|
||||
String tmp = value.substring(value.indexOf("-") + 1).replaceAll("[0-9.,-]", "");
|
||||
value = value.substring(0, value.indexOf("-")) + tmp;
|
||||
value = value.substring(0, value.indexOf("-"));
|
||||
if (value.matches("\\d+(\\.\\d+)?")) value += tmp;
|
||||
}
|
||||
value = value.toLowerCase(Locale.US);
|
||||
|
||||
// do some value conversion
|
||||
if (value.toLowerCase().contains("ft")) {
|
||||
float foot = 0f;
|
||||
if (value.contains("ft")) {
|
||||
float feet = 0f;
|
||||
int inch = 0;
|
||||
String[] sa = value.toLowerCase().trim().split("ft");
|
||||
if (sa.length >= 1) foot = Float.parseFloat(sa[0].trim());
|
||||
String[] sa = value.split("ft");
|
||||
if (sa.length >= 1) feet = Float.parseFloat(sa[0]);
|
||||
if (sa.length == 2) {
|
||||
value = sa[1];
|
||||
if (value.indexOf("in") > 0) value = value.substring(0, value.indexOf("in"));
|
||||
inch = Integer.parseInt(value.trim());
|
||||
foot += inch / 12f;
|
||||
inch = Integer.parseInt(value);
|
||||
feet += inch / 12f;
|
||||
}
|
||||
value = String.format(Locale.US, "%3.1f", foot * 0.3048f);
|
||||
}
|
||||
if (value.toLowerCase().contains("'")) {
|
||||
float foot = 0f;
|
||||
value = String.format(Locale.US, "%3.1f", feet * 0.3048f);
|
||||
} else if (value.contains("'")) {
|
||||
float feet = 0f;
|
||||
int inch = 0;
|
||||
String[] sa = value.toLowerCase().trim().split("'");
|
||||
if (sa.length >= 1) foot = Float.parseFloat(sa[0].trim());
|
||||
String[] sa = value.split("'");
|
||||
if (sa.length >= 1) feet = Float.parseFloat(sa[0]);
|
||||
if (sa.length == 2) {
|
||||
value = sa[1];
|
||||
if (value.indexOf("''") > 0) value = value.substring(0, value.indexOf("''"));
|
||||
if (value.indexOf("\"") > 0) value = value.substring(0, value.indexOf("\""));
|
||||
inch = Integer.parseInt(value.trim());
|
||||
foot += inch / 12f;
|
||||
inch = Integer.parseInt(value);
|
||||
feet += inch / 12f;
|
||||
}
|
||||
value = String.format(Locale.US, "%3.1f", foot * 0.3048f);
|
||||
value = String.format(Locale.US, "%3.1f", feet * 0.3048f);
|
||||
} else if (value.contains("in") || value.contains("\"")) {
|
||||
float inch = 0f;
|
||||
if (value.indexOf("in") > 0) value = value.substring(0, value.indexOf("in"));
|
||||
if (value.indexOf("\"") > 0) value = value.substring(0, value.indexOf("\""));
|
||||
inch = Float.parseFloat(value.trim());
|
||||
inch = Float.parseFloat(value);
|
||||
value = String.format(Locale.US, "%3.1f", inch * 0.0254f);
|
||||
} else if (value.toLowerCase().contains("feet") || value.toLowerCase().contains("foot")) {
|
||||
} else if (value.contains("feet") || value.contains("foot")) {
|
||||
float feet = 0f;
|
||||
String s = value.substring(0, value.toLowerCase().indexOf("f"));
|
||||
feet = Float.parseFloat(s.trim());
|
||||
String s = value.substring(0, value.indexOf("f"));
|
||||
feet = Float.parseFloat(s);
|
||||
value = String.format(Locale.US, "%3.1f", feet * 0.3048f);
|
||||
} else if (value.toLowerCase().contains("fathom") || value.toLowerCase().contains("fm")) {
|
||||
float fathom = 0f;
|
||||
String s = value.substring(0, value.toLowerCase().indexOf("f"));
|
||||
fathom = Float.parseFloat(s.trim());
|
||||
} else if (value.contains("fathom") || value.contains("fm")) {
|
||||
String s = value.substring(0, value.indexOf("f"));
|
||||
float fathom = Float.parseFloat(s);
|
||||
value = String.format(Locale.US, "%3.1f", fathom * 1.8288f);
|
||||
} else if (value.contains("cm")) {
|
||||
String[] sa = value.trim().split("cm");
|
||||
if (sa.length == 1) value = sa[0].trim();
|
||||
float cm = Float.parseFloat(value.trim());
|
||||
value = String.format(Locale.US, "%3.1f", cm * 100f);
|
||||
} else if (value.toLowerCase().contains("meter")) {
|
||||
String s = value.substring(0, value.toLowerCase().indexOf("m"));
|
||||
value = s.trim();
|
||||
} else if (value.toLowerCase().contains("mph")) {
|
||||
value = value.replace("_", "");
|
||||
String[] sa = value.trim().toLowerCase().split("mph");
|
||||
if (sa.length >= 1) value = sa[0].trim();
|
||||
float mph = Float.parseFloat(value.trim());
|
||||
String[] sa = value.split("cm");
|
||||
if (sa.length >= 1) value = sa[0];
|
||||
float cm = Float.parseFloat(value);
|
||||
value = String.format(Locale.US, "%3.1f", cm / 100f);
|
||||
} else if (value.contains("meter")) {
|
||||
value = value.substring(0, value.indexOf("m"));
|
||||
} else if (value.contains("mph")) {
|
||||
String[] sa = value.split("mph");
|
||||
if (sa.length >= 1) value = sa[0];
|
||||
float mph = Float.parseFloat(value);
|
||||
value = String.format(Locale.US, "%3.1f", mph * 1.609344f);
|
||||
} else if (value.toLowerCase().contains("knot")) {
|
||||
String[] sa = value.trim().toLowerCase().split("knot");
|
||||
if (sa.length >= 1) value = sa[0].trim();
|
||||
float nm = Float.parseFloat(value.trim());
|
||||
} else if (value.contains("knot")) {
|
||||
String[] sa = value.split("knot");
|
||||
if (sa.length >= 1) value = sa[0];
|
||||
float nm = Float.parseFloat(value);
|
||||
value = String.format(Locale.US, "%3.1f", nm * 1.852f);
|
||||
} else if (value.contains("kmh") || value.contains("km/h") || value.contains("kph")) {
|
||||
String[] sa = value.trim().split("k");
|
||||
if (sa.length == 1) value = sa[0].trim();
|
||||
String[] sa = value.split("k");
|
||||
if (sa.length > 1) value = sa[0];
|
||||
} else if (value.contains("m")) {
|
||||
String s = value.substring(0, value.toLowerCase().indexOf("m"));
|
||||
value = s.trim();
|
||||
value = value.substring(0, value.indexOf("m"));
|
||||
} else if (value.contains("(")) {
|
||||
String s = value.substring(0, value.toLowerCase().indexOf("("));
|
||||
value = s.trim();
|
||||
value = value.substring(0, value.indexOf("("));
|
||||
}
|
||||
// found negative maxdraft values
|
||||
// no negative values
|
||||
// values are float with 2 decimals
|
||||
lookupData2[inum] = 1000 + (int) (Math.abs(Float.parseFloat(value)) * 100f);
|
||||
lookupData2[num] = 1000 + (int) (Math.abs(Float.parseFloat(value)) * 100f);
|
||||
} catch (Exception e) {
|
||||
// ignore errors
|
||||
System.err.println("error for " + name + " " + org + " trans " + value + " " + e.getMessage());
|
||||
lookupData2[inum] = 0;
|
||||
lookupData2[num] = 0;
|
||||
}
|
||||
}
|
||||
return newValue;
|
||||
|
|
@ -674,15 +677,15 @@ public abstract class BExpressionContext implements IByteArrayUnifier {
|
|||
histo = nhisto;
|
||||
newValue = new BExpressionLookupValue(value);
|
||||
values[i] = newValue;
|
||||
lookupHistograms.set(inum, histo);
|
||||
lookupValues.set(inum, values);
|
||||
lookupHistograms.set(num, histo);
|
||||
lookupValues.set(num, values);
|
||||
}
|
||||
|
||||
histo[i]++;
|
||||
|
||||
// finally remember the actual data
|
||||
if (lookupData2 != null) lookupData2[inum] = i;
|
||||
else lookupData[inum] = i;
|
||||
if (lookupData2 != null) lookupData2[num] = i;
|
||||
else lookupData[num] = i;
|
||||
return newValue;
|
||||
}
|
||||
|
||||
|
|
@ -697,11 +700,10 @@ public abstract class BExpressionContext implements IByteArrayUnifier {
|
|||
}
|
||||
|
||||
// look for that value
|
||||
int inum = num.intValue();
|
||||
int nvalues = lookupValues.get(inum).length;
|
||||
int nvalues = lookupValues.get(num).length;
|
||||
if (valueIndex < 0 || valueIndex >= nvalues)
|
||||
throw new IllegalArgumentException("value index out of range for name " + name + ": " + valueIndex);
|
||||
lookupData[inum] = valueIndex;
|
||||
lookupData[num] = valueIndex;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -718,9 +720,8 @@ public abstract class BExpressionContext implements IByteArrayUnifier {
|
|||
}
|
||||
|
||||
// look for that value
|
||||
int inum = num.intValue();
|
||||
int nvalues = lookupValues.get(inum).length;
|
||||
int oldValueIndex = lookupData[inum];
|
||||
int nvalues = lookupValues.get(num).length;
|
||||
int oldValueIndex = lookupData[num];
|
||||
if (oldValueIndex > 1 && oldValueIndex < valueIndex) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -729,12 +730,12 @@ public abstract class BExpressionContext implements IByteArrayUnifier {
|
|||
}
|
||||
if (valueIndex < 0)
|
||||
throw new IllegalArgumentException("value index out of range for name " + name + ": " + valueIndex);
|
||||
lookupData[inum] = valueIndex;
|
||||
lookupData[num] = valueIndex;
|
||||
}
|
||||
|
||||
public boolean getBooleanLookupValue(String name) {
|
||||
Integer num = lookupNumbers.get(name);
|
||||
return num != null && lookupData[num.intValue()] == 2;
|
||||
return num != null && lookupData[num] == 2;
|
||||
}
|
||||
|
||||
public int getOutputVariableIndex(String name, boolean mustExist) {
|
||||
|
|
@ -846,7 +847,7 @@ public abstract class BExpressionContext implements IByteArrayUnifier {
|
|||
public void setVariableValue(String name, float value, boolean create) {
|
||||
Integer num = variableNumbers.get(name);
|
||||
if (num != null) {
|
||||
variableData[num.intValue()] = value;
|
||||
variableData[num] = value;
|
||||
} else if (create) {
|
||||
num = getVariableIdx(name, create);
|
||||
float[] readOnlyData = variableData;
|
||||
|
|
@ -855,13 +856,13 @@ public abstract class BExpressionContext implements IByteArrayUnifier {
|
|||
for (int i = 0; i < minWriteIdx; i++) {
|
||||
variableData[i] = readOnlyData[i];
|
||||
}
|
||||
variableData[num.intValue()] = value;
|
||||
variableData[num] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public float getVariableValue(String name, float defaultValue) {
|
||||
Integer num = variableNumbers.get(name);
|
||||
return num == null ? defaultValue : getVariableValue(num.intValue());
|
||||
return num == null ? defaultValue : getVariableValue(num);
|
||||
}
|
||||
|
||||
float getVariableValue(int variableIdx) {
|
||||
|
|
@ -879,7 +880,7 @@ public abstract class BExpressionContext implements IByteArrayUnifier {
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
return num.intValue();
|
||||
return num;
|
||||
}
|
||||
|
||||
int getMinWriteIdx() {
|
||||
|
|
@ -897,7 +898,7 @@ public abstract class BExpressionContext implements IByteArrayUnifier {
|
|||
|
||||
public int getLookupNameIdx(String name) {
|
||||
Integer num = lookupNumbers.get(name);
|
||||
return num == null ? -1 : num.intValue();
|
||||
return num == null ? -1 : num;
|
||||
}
|
||||
|
||||
public final void markLookupIdxUsed(int idx) {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ public final class BExpressionContextWay extends BExpressionContext implements T
|
|||
private boolean decodeForbidden = true;
|
||||
|
||||
private static String[] buildInVariables =
|
||||
{"costfactor", "turncost", "uphillcostfactor", "downhillcostfactor", "initialcost", "nodeaccessgranted", "initialclassifier", "trafficsourcedensity", "istrafficbackbone", "priorityclassifier", "classifiermask", "maxspeed", "uphillcost", "downhillcost", "uphillcutoff", "downhillcutoff"};
|
||||
{"costfactor", "turncost", "uphillcostfactor", "downhillcostfactor", "initialcost", "nodeaccessgranted", "initialclassifier", "trafficsourcedensity", "istrafficbackbone", "priorityclassifier", "classifiermask", "maxspeed", "uphillcost", "downhillcost", "uphillcutoff", "downhillcutoff", "uphillmaxslope", "downhillmaxslope", "uphillmaxslopecost", "downhillmaxslopecost"};
|
||||
|
||||
protected String[] getBuildInVariableNames() {
|
||||
return buildInVariables;
|
||||
|
|
@ -82,6 +82,22 @@ public final class BExpressionContextWay extends BExpressionContext implements T
|
|||
return getBuildInVariable(15);
|
||||
}
|
||||
|
||||
public float getUphillmaxslope() {
|
||||
return getBuildInVariable(16);
|
||||
}
|
||||
|
||||
public float getDownhillmaxslope() {
|
||||
return getBuildInVariable(17);
|
||||
}
|
||||
|
||||
public float getUphillmaxslopecost() {
|
||||
return getBuildInVariable(18);
|
||||
}
|
||||
|
||||
public float getDownhillmaxslopecost() {
|
||||
return getBuildInVariable(19);
|
||||
}
|
||||
|
||||
public BExpressionContextWay(BExpressionMetaData meta) {
|
||||
super("way", meta);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public class EncodeDecodeTest {
|
|||
"depth=1'6\"",
|
||||
// "depth=6 feet",
|
||||
"maxheight=5.1m",
|
||||
"maxdraft=~3 mt",
|
||||
"maxdraft=~3 m - 4 m",
|
||||
"reversedirection=yes"
|
||||
};
|
||||
|
||||
|
|
|
|||
1
brouter-map-creator/.gitignore
vendored
1
brouter-map-creator/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
/build/
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
plugins {
|
||||
id 'java-library'
|
||||
id 'brouter.application-conventions'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
|
@ -8,6 +8,4 @@ dependencies {
|
|||
implementation project(':brouter-expressions')
|
||||
|
||||
implementation group: 'org.openstreetmap.osmosis', name: 'osmosis-osm-binary', version: '0.48.3'
|
||||
|
||||
testImplementation('junit:junit:4.13.1')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,250 +0,0 @@
|
|||
package btools.mapcreator;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
public class ConvertLidarTile {
|
||||
private static int NROWS;
|
||||
private static int NCOLS;
|
||||
|
||||
public static final short NODATA2 = -32767; // hgt-formats nodata
|
||||
public static final short NODATA = Short.MIN_VALUE;
|
||||
|
||||
private static final String HGT_FILE_EXT = ".hgt";
|
||||
private static final int HGT_BORDER_OVERLAP = 1;
|
||||
private static final int HGT_3ASEC_ROWS = 1201; // 3 arc second resolution (90m)
|
||||
private static final int HGT_3ASEC_FILE_SIZE = HGT_3ASEC_ROWS * HGT_3ASEC_ROWS * Short.BYTES;
|
||||
private static final int HGT_1ASEC_ROWS = 3601; // 1 arc second resolution (30m)
|
||||
|
||||
static short[] imagePixels;
|
||||
|
||||
private static void readHgtZip(String filename, int rowOffset, int colOffset) throws Exception {
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(filename)));
|
||||
try {
|
||||
for (; ; ) {
|
||||
ZipEntry ze = zis.getNextEntry();
|
||||
if (ze == null) break;
|
||||
if (ze.getName().toLowerCase().endsWith(HGT_FILE_EXT)) {
|
||||
readHgtFromStream(zis, rowOffset, colOffset, HGT_3ASEC_ROWS);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
zis.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void readHgtFromStream(InputStream is, int rowOffset, int colOffset, int rowLength)
|
||||
throws Exception {
|
||||
DataInputStream dis = new DataInputStream(new BufferedInputStream(is));
|
||||
for (int ir = 0; ir < rowLength; ir++) {
|
||||
int row = rowOffset + ir;
|
||||
|
||||
for (int ic = 0; ic < rowLength; ic++) {
|
||||
int col = colOffset + ic;
|
||||
|
||||
int i1 = dis.read(); // msb first!
|
||||
int i0 = dis.read();
|
||||
|
||||
if (i0 == -1 || i1 == -1)
|
||||
throw new RuntimeException("unexpected end of file reading hgt entry!");
|
||||
|
||||
short val = (short) ((i1 << 8) | i0);
|
||||
|
||||
if (val == NODATA2) {
|
||||
val = NODATA;
|
||||
}
|
||||
|
||||
setPixel(row, col, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setPixel(int row, int col, short val) {
|
||||
if (row >= 0 && row < NROWS && col >= 0 && col < NCOLS) {
|
||||
imagePixels[row * NCOLS + col] = val;
|
||||
}
|
||||
}
|
||||
|
||||
private static short getPixel(int row, int col) {
|
||||
if (row >= 0 && row < NROWS && col >= 0 && col < NCOLS) {
|
||||
return imagePixels[row * NCOLS + col];
|
||||
}
|
||||
return NODATA;
|
||||
}
|
||||
|
||||
|
||||
public static void doConvert(String inputDir, int lonDegreeStart, int latDegreeStart, String outputFile) throws Exception {
|
||||
int extraBorder = 0;
|
||||
|
||||
NROWS = 5 * 1200 + 1 + 2 * extraBorder;
|
||||
NCOLS = 5 * 1200 + 1 + 2 * extraBorder;
|
||||
|
||||
imagePixels = new short[NROWS * NCOLS]; // 650 MB !
|
||||
|
||||
// prefill as NODATA
|
||||
for (int row = 0; row < NROWS; row++) {
|
||||
for (int col = 0; col < NCOLS; col++) {
|
||||
imagePixels[row * NCOLS + col] = NODATA;
|
||||
}
|
||||
}
|
||||
|
||||
for (int latIdx = -1; latIdx <= 5; latIdx++) {
|
||||
int latDegree = latDegreeStart + latIdx;
|
||||
int rowOffset = extraBorder + (4 - latIdx) * 1200;
|
||||
|
||||
for (int lonIdx = -1; lonIdx <= 5; lonIdx++) {
|
||||
int lonDegree = lonDegreeStart + lonIdx;
|
||||
int colOffset = extraBorder + lonIdx * 1200;
|
||||
|
||||
String filename = inputDir + "/" + formatLat(latDegree) + formatLon(lonDegree) + ".zip";
|
||||
File f = new File(filename);
|
||||
if (f.exists() && f.length() > 0) {
|
||||
System.out.println("exist: " + filename);
|
||||
readHgtZip(filename, rowOffset, colOffset);
|
||||
} else {
|
||||
System.out.println("none : " + filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean halfCol5 = false; // no halfcol tiles in lidar data (?)
|
||||
|
||||
|
||||
SrtmRaster raster = new SrtmRaster();
|
||||
raster.nrows = NROWS;
|
||||
raster.ncols = NCOLS;
|
||||
raster.halfcol = halfCol5;
|
||||
raster.noDataValue = NODATA;
|
||||
raster.cellsize = 1 / 1200.;
|
||||
raster.xllcorner = lonDegreeStart - (0.5 + extraBorder) * raster.cellsize;
|
||||
raster.yllcorner = latDegreeStart - (0.5 + extraBorder) * raster.cellsize;
|
||||
raster.eval_array = imagePixels;
|
||||
|
||||
// encode the raster
|
||||
OutputStream os = new BufferedOutputStream(new FileOutputStream(outputFile));
|
||||
new RasterCoder().encodeRaster(raster, os);
|
||||
os.close();
|
||||
|
||||
// decode the raster
|
||||
InputStream is = new BufferedInputStream(new FileInputStream(outputFile));
|
||||
SrtmRaster raster2 = new RasterCoder().decodeRaster(is);
|
||||
is.close();
|
||||
|
||||
short[] pix2 = raster2.eval_array;
|
||||
if (pix2.length != imagePixels.length)
|
||||
throw new RuntimeException("length mismatch!");
|
||||
|
||||
// compare decoding result
|
||||
for (int row = 0; row < NROWS; row++) {
|
||||
int colstep = halfCol5 ? 2 : 1;
|
||||
for (int col = 0; col < NCOLS; col += colstep) {
|
||||
int idx = row * NCOLS + col;
|
||||
short p2 = pix2[idx];
|
||||
if (p2 != imagePixels[idx]) {
|
||||
throw new RuntimeException("content mismatch: p2=" + p2 + " p1=" + imagePixels[idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatLon(int lon) {
|
||||
if (lon >= 180)
|
||||
lon -= 180; // TODO: w180 oder E180 ?
|
||||
|
||||
String s = "E";
|
||||
if (lon < 0) {
|
||||
lon = -lon;
|
||||
s = "W";
|
||||
}
|
||||
String n = "000" + lon;
|
||||
return s + n.substring(n.length() - 3);
|
||||
}
|
||||
|
||||
private static String formatLat(int lat) {
|
||||
String s = "N";
|
||||
if (lat < 0) {
|
||||
lat = -lat;
|
||||
s = "S";
|
||||
}
|
||||
String n = "00" + lat;
|
||||
return s + n.substring(n.length() - 2);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String filename90 = args[0];
|
||||
String filename30 = filename90.substring(0, filename90.length() - 3) + "bef";
|
||||
|
||||
int srtmLonIdx = Integer.parseInt(filename90.substring(5, 7).toLowerCase());
|
||||
int srtmLatIdx = Integer.parseInt(filename90.substring(8, 10).toLowerCase());
|
||||
|
||||
int ilon_base = (srtmLonIdx - 1) * 5 - 180;
|
||||
int ilat_base = 150 - srtmLatIdx * 5 - 90;
|
||||
|
||||
doConvert(args[1], ilon_base, ilat_base, filename30);
|
||||
}
|
||||
|
||||
public SrtmRaster getRaster(File f, double lon, double lat) throws Exception {
|
||||
long fileSize;
|
||||
InputStream inputStream;
|
||||
|
||||
if (f.getName().toLowerCase().endsWith(".zip")) {
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(f)));
|
||||
for (; ; ) {
|
||||
ZipEntry ze = zis.getNextEntry();
|
||||
if (ze == null) {
|
||||
throw new FileNotFoundException(f.getName() + " doesn't contain a " + HGT_FILE_EXT + " file.");
|
||||
}
|
||||
if (ze.getName().toLowerCase().endsWith(HGT_FILE_EXT)) {
|
||||
fileSize = ze.getSize();
|
||||
inputStream = zis;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fileSize = f.length();
|
||||
inputStream = new FileInputStream(f);
|
||||
}
|
||||
|
||||
int rowLength;
|
||||
if (fileSize > HGT_3ASEC_FILE_SIZE) {
|
||||
rowLength = HGT_1ASEC_ROWS;
|
||||
} else {
|
||||
rowLength = HGT_3ASEC_ROWS;
|
||||
}
|
||||
|
||||
// stay at 1 deg * 1 deg raster
|
||||
NROWS = rowLength;
|
||||
NCOLS = rowLength;
|
||||
|
||||
imagePixels = new short[NROWS * NCOLS];
|
||||
|
||||
// prefill as NODATA
|
||||
Arrays.fill(imagePixels, NODATA);
|
||||
readHgtFromStream(inputStream, 0, 0, rowLength);
|
||||
inputStream.close();
|
||||
|
||||
SrtmRaster raster = new SrtmRaster();
|
||||
raster.nrows = NROWS;
|
||||
raster.ncols = NCOLS;
|
||||
raster.halfcol = false; // assume full resolution
|
||||
raster.noDataValue = NODATA;
|
||||
raster.cellsize = 1. / (double) (rowLength - HGT_BORDER_OVERLAP);
|
||||
raster.xllcorner = (int) (lon < 0 ? lon - 1 : lon); //onDegreeStart - raster.cellsize;
|
||||
raster.yllcorner = (int) (lat < 0 ? lat - 1 : lat); //latDegreeStart - raster.cellsize;
|
||||
raster.eval_array = imagePixels;
|
||||
|
||||
return raster;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,260 +0,0 @@
|
|||
package btools.mapcreator;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class ConvertSrtmTile {
|
||||
public static int NROWS;
|
||||
public static int NCOLS;
|
||||
|
||||
public static final short SKIPDATA = -32766; // >50 degree skipped pixel
|
||||
public static final short NODATA2 = -32767; // bil-formats nodata
|
||||
public static final short NODATA = Short.MIN_VALUE;
|
||||
|
||||
static short[] imagePixels;
|
||||
|
||||
public static int[] diffs = new int[100];
|
||||
|
||||
private static void readBilZip(String filename, int rowOffset, int colOffset, boolean halfCols) throws Exception {
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(filename)));
|
||||
try {
|
||||
for (; ; ) {
|
||||
ZipEntry ze = zis.getNextEntry();
|
||||
if (ze.getName().endsWith(".bil")) {
|
||||
readBilFromStream(zis, rowOffset, colOffset, halfCols);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
zis.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void readBilFromStream(InputStream is, int rowOffset, int colOffset, boolean halfCols)
|
||||
throws Exception {
|
||||
DataInputStream dis = new DataInputStream(new BufferedInputStream(is));
|
||||
for (int ir = 0; ir < 3601; ir++) {
|
||||
int row = rowOffset + ir;
|
||||
|
||||
for (int ic = 0; ic < 3601; ic++) {
|
||||
int col = colOffset + ic;
|
||||
|
||||
if ((ic % 2) == 1 && halfCols) {
|
||||
if (getPixel(row, col) == NODATA) {
|
||||
setPixel(row, col, SKIPDATA);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
int i0 = dis.read();
|
||||
int i1 = dis.read();
|
||||
|
||||
if (i0 == -1 || i1 == -1)
|
||||
throw new RuntimeException("unexcepted end of file reading bil entry!");
|
||||
|
||||
short val = (short) ((i1 << 8) | i0);
|
||||
|
||||
if (val == NODATA2) {
|
||||
val = NODATA;
|
||||
}
|
||||
|
||||
setPixel(row, col, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void setPixel(int row, int col, short val) {
|
||||
if (row >= 0 && row < NROWS && col >= 0 && col < NCOLS) {
|
||||
imagePixels[row * NCOLS + col] = val;
|
||||
}
|
||||
}
|
||||
|
||||
private static short getPixel(int row, int col) {
|
||||
if (row >= 0 && row < NROWS && col >= 0 && col < NCOLS) {
|
||||
return imagePixels[row * NCOLS + col];
|
||||
}
|
||||
return NODATA;
|
||||
}
|
||||
|
||||
|
||||
public static void doConvert(String inputDir, String v1Dir, int lonDegreeStart, int latDegreeStart, String outputFile, SrtmRaster raster90) throws Exception {
|
||||
int extraBorder = 10;
|
||||
int datacells = 0;
|
||||
int mismatches = 0;
|
||||
|
||||
NROWS = 5 * 3600 + 1 + 2 * extraBorder;
|
||||
NCOLS = 5 * 3600 + 1 + 2 * extraBorder;
|
||||
|
||||
imagePixels = new short[NROWS * NCOLS]; // 650 MB !
|
||||
|
||||
// prefill as NODATA
|
||||
for (int row = 0; row < NROWS; row++) {
|
||||
for (int col = 0; col < NCOLS; col++) {
|
||||
imagePixels[row * NCOLS + col] = NODATA;
|
||||
}
|
||||
}
|
||||
|
||||
for (int latIdx = -1; latIdx <= 5; latIdx++) {
|
||||
int latDegree = latDegreeStart + latIdx;
|
||||
int rowOffset = extraBorder + (4 - latIdx) * 3600;
|
||||
|
||||
for (int lonIdx = -1; lonIdx <= 5; lonIdx++) {
|
||||
int lonDegree = lonDegreeStart + lonIdx;
|
||||
int colOffset = extraBorder + lonIdx * 3600;
|
||||
|
||||
String filename = inputDir + "/" + formatLat(latDegree) + "_" + formatLon(lonDegree) + "_1arc_v3_bil.zip";
|
||||
File f = new File(filename);
|
||||
if (f.exists() && f.length() > 0) {
|
||||
System.out.println("exist: " + filename);
|
||||
boolean halfCol = latDegree >= 50 || latDegree < -50;
|
||||
readBilZip(filename, rowOffset, colOffset, halfCol);
|
||||
} else {
|
||||
System.out.println("none : " + filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean halfCol5 = latDegreeStart >= 50 || latDegreeStart < -50;
|
||||
|
||||
for (int row90 = 0; row90 < 6001; row90++) {
|
||||
int crow = 3 * row90 + extraBorder; // center row of 3x3
|
||||
for (int col90 = 0; col90 < 6001; col90++) {
|
||||
int ccol = 3 * col90 + extraBorder; // center col of 3x3
|
||||
|
||||
// evaluate 3x3 area
|
||||
if (raster90 != null && (!halfCol5 || (col90 % 2) == 0)) {
|
||||
short v90 = raster90.eval_array[row90 * 6001 + col90];
|
||||
|
||||
int sum = 0;
|
||||
int nodatas = 0;
|
||||
int datas = 0;
|
||||
int colstep = halfCol5 ? 2 : 1;
|
||||
for (int row = crow - 1; row <= crow + 1; row++) {
|
||||
for (int col = ccol - colstep; col <= ccol + colstep; col += colstep) {
|
||||
short v30 = imagePixels[row * NCOLS + col];
|
||||
if (v30 == NODATA) {
|
||||
nodatas++;
|
||||
} else if (v30 != SKIPDATA) {
|
||||
sum += v30;
|
||||
datas++;
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean doReplace = nodatas > 0 || v90 == NODATA || datas < 7;
|
||||
if (!doReplace) {
|
||||
datacells++;
|
||||
int diff = sum - datas * v90;
|
||||
if (diff < -4 || diff > 4) {
|
||||
doReplace = true;
|
||||
mismatches++;
|
||||
}
|
||||
|
||||
if (diff > -50 && diff < 50 && (row90 % 1200) != 0 && (col90 % 1200) != 0) {
|
||||
diffs[diff + 50]++;
|
||||
}
|
||||
}
|
||||
if (doReplace) {
|
||||
for (int row = crow - 1; row <= crow + 1; row++) {
|
||||
for (int col = ccol - colstep; col <= ccol + colstep; col += colstep) {
|
||||
imagePixels[row * NCOLS + col] = v90;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SrtmRaster raster = new SrtmRaster();
|
||||
raster.nrows = NROWS;
|
||||
raster.ncols = NCOLS;
|
||||
raster.halfcol = halfCol5;
|
||||
raster.noDataValue = NODATA;
|
||||
raster.cellsize = 1 / 3600.;
|
||||
raster.xllcorner = lonDegreeStart - (0.5 + extraBorder) * raster.cellsize;
|
||||
raster.yllcorner = latDegreeStart - (0.5 + extraBorder) * raster.cellsize;
|
||||
raster.eval_array = imagePixels;
|
||||
|
||||
// encode the raster
|
||||
OutputStream os = new BufferedOutputStream(new FileOutputStream(outputFile));
|
||||
new RasterCoder().encodeRaster(raster, os);
|
||||
os.close();
|
||||
|
||||
// decode the raster
|
||||
InputStream is = new BufferedInputStream(new FileInputStream(outputFile));
|
||||
SrtmRaster raster2 = new RasterCoder().decodeRaster(is);
|
||||
is.close();
|
||||
|
||||
short[] pix2 = raster2.eval_array;
|
||||
if (pix2.length != imagePixels.length)
|
||||
throw new RuntimeException("length mismatch!");
|
||||
|
||||
// compare decoding result
|
||||
for (int row = 0; row < NROWS; row++) {
|
||||
int colstep = halfCol5 ? 2 : 1;
|
||||
for (int col = 0; col < NCOLS; col += colstep) {
|
||||
int idx = row * NCOLS + col;
|
||||
if (imagePixels[idx] == SKIPDATA) {
|
||||
continue;
|
||||
}
|
||||
short p2 = pix2[idx];
|
||||
if (p2 > SKIPDATA) {
|
||||
p2 /= 2;
|
||||
}
|
||||
if (p2 != imagePixels[idx]) {
|
||||
throw new RuntimeException("content mismatch!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i < 100; i++) System.out.println("diff[" + (i - 50) + "] = " + diffs[i]);
|
||||
System.out.println("datacells=" + datacells + " mismatch%=" + (100. * mismatches) / datacells);
|
||||
btools.util.MixCoderDataOutputStream.stats();
|
||||
// test( raster );
|
||||
// raster.calcWeights( 50. );
|
||||
// test( raster );
|
||||
// 39828330 &lon=3115280&layer=OpenStreetMap
|
||||
}
|
||||
|
||||
private static void test(SrtmRaster raster) {
|
||||
int lat0 = 39828330;
|
||||
int lon0 = 3115280;
|
||||
|
||||
for (int iy = -9; iy <= 9; iy++) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int ix = -9; ix <= 9; ix++) {
|
||||
int lat = lat0 + 90000000 - 100 * iy;
|
||||
int lon = lon0 + 180000000 + 100 * ix;
|
||||
int ival = (int) (raster.getElevation(lon, lat) / 4.);
|
||||
String sval = " " + ival;
|
||||
sb.append(sval.substring(sval.length() - 4));
|
||||
}
|
||||
System.out.println(sb);
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatLon(int lon) {
|
||||
if (lon >= 180)
|
||||
lon -= 180; // TODO: w180 oder E180 ?
|
||||
|
||||
String s = "e";
|
||||
if (lon < 0) {
|
||||
lon = -lon;
|
||||
s = "w";
|
||||
}
|
||||
String n = "000" + lon;
|
||||
return s + n.substring(n.length() - 3);
|
||||
}
|
||||
|
||||
private static String formatLat(int lat) {
|
||||
String s = "n";
|
||||
if (lat < 0) {
|
||||
lat = -lat;
|
||||
s = "s";
|
||||
}
|
||||
String n = "00" + lat;
|
||||
return s + n.substring(n.length() - 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
package btools.mapcreator;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
|
||||
public class ConvertUrlList {
|
||||
public static final short NODATA = -32767;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
BufferedReader br = new BufferedReader(new FileReader(args[0]));
|
||||
|
||||
for (; ; ) {
|
||||
String line = br.readLine();
|
||||
if (line == null) {
|
||||
break;
|
||||
}
|
||||
int idx1 = line.indexOf("srtm_");
|
||||
if (idx1 < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String filename90 = line.substring(idx1);
|
||||
String filename30 = filename90.substring(0, filename90.length() - 3) + "bef";
|
||||
|
||||
if (new File(filename30).exists()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// int srtmLonIdx = (ilon+5000000)/5000000; -> ilon = (srtmLonIdx-1)*5
|
||||
// int srtmLatIdx = (154999999-ilat)/5000000; -> ilat = 155 - srtmLatIdx*5
|
||||
|
||||
int srtmLonIdx = Integer.parseInt(filename90.substring(5, 7).toLowerCase());
|
||||
int srtmLatIdx = Integer.parseInt(filename90.substring(8, 10).toLowerCase());
|
||||
|
||||
int ilon_base = (srtmLonIdx - 1) * 5 - 180;
|
||||
int ilat_base = 150 - srtmLatIdx * 5 - 90;
|
||||
|
||||
SrtmRaster raster90 = null;
|
||||
|
||||
File file90 = new File(new File(args[1]), filename90);
|
||||
if (file90.exists()) {
|
||||
System.out.println("reading " + file90);
|
||||
raster90 = new SrtmData(file90).getRaster();
|
||||
}
|
||||
|
||||
ConvertSrtmTile.doConvert(args[2], args[3], ilon_base, ilat_base, filename30, raster90);
|
||||
}
|
||||
br.close();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,335 @@
|
|||
package btools.mapcreator;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
|
||||
public class CreateElevationRasterImage {
|
||||
|
||||
final static boolean DEBUG = false;
|
||||
|
||||
int[] data;
|
||||
ElevationRaster lastSrtmRaster;
|
||||
Map<String, ElevationRaster> srtmmap;
|
||||
int lastSrtmLonIdx;
|
||||
int lastSrtmLatIdx;
|
||||
short maxElev = Short.MIN_VALUE;
|
||||
short minElev = Short.MAX_VALUE;
|
||||
String srtmdir;
|
||||
boolean missingData;
|
||||
Map<Short, Color> colorMap;
|
||||
|
||||
|
||||
private void createImage(double lon, double lat, String dir, String imageName, int maxX, int maxY, int downscale, String format, String colors) throws Exception {
|
||||
srtmdir = dir;
|
||||
if (colors != null) {
|
||||
loadColors(colors);
|
||||
}
|
||||
if (format.equals("hgt")) {
|
||||
createImageFromHgt(lon, lat, dir, imageName, maxX, maxY);
|
||||
return;
|
||||
}
|
||||
if (!format.equals("bef")) {
|
||||
System.out.println("wrong format (bef|hgt)");
|
||||
return;
|
||||
}
|
||||
srtmmap = new HashMap<>();
|
||||
lastSrtmLonIdx = -1;
|
||||
lastSrtmLatIdx = -1;
|
||||
lastSrtmRaster = null;
|
||||
NodeData n = new NodeData(1, lon, lat);
|
||||
ElevationRaster srtm = srtmForNode(n.ilon, n.ilat);
|
||||
if (srtm == null) {
|
||||
System.out.println("no data");
|
||||
return;
|
||||
}
|
||||
System.out.println("srtm " + srtm.toString());
|
||||
//System.out.println("srtm elev " + srtm.getElevation(n.ilon, n.ilat));
|
||||
double[] pos = getElevationPos(srtm, n.ilon, n.ilat);
|
||||
//System.out.println("srtm pos " + Math.round(pos[0]) + " " + Math.round(pos[1]));
|
||||
short[] raster = srtm.eval_array;
|
||||
int rasterX = srtm.ncols;
|
||||
int rasterY = srtm.nrows;
|
||||
|
||||
int tileSize = 1000 / downscale;
|
||||
int sizeX = (maxX);
|
||||
int sizeY = (maxY);
|
||||
int[] imgraster = new int[sizeX * sizeY];
|
||||
for (int y = 0; y < sizeY; y++) {
|
||||
for (int x = 0; x < sizeX; x++) {
|
||||
//short e = getElevationXY(srtm, pos[0] + (sizeY - y) * downscale, pos[1] + (x * downscale));
|
||||
short e = get(srtm, (int) Math.round(pos[0]) + (sizeY - y), x + (int) Math.round(pos[1]));
|
||||
if (e != Short.MIN_VALUE && e < minElev) minElev = e;
|
||||
if (e != Short.MIN_VALUE && e > maxElev) maxElev = e;
|
||||
|
||||
if (e == Short.MIN_VALUE) {
|
||||
imgraster[sizeY * y + x] = 0xffff;
|
||||
} else {
|
||||
//imgraster[sizeY * y + x] = getColorForHeight((short)(e/4)); //(int)(e/4.);
|
||||
imgraster[sizeY * y + x] = getColorForHeight(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("srtm target " + sizeX + " " + sizeY + " (" + rasterX + " " + rasterY + ")" + " min " + minElev + " max " + maxElev);
|
||||
|
||||
if (DEBUG) {
|
||||
String out = "short ";
|
||||
for (int i = 0; i < 100; i++) {
|
||||
out += " " + get(srtm, sizeY - 0, i);
|
||||
}
|
||||
System.out.println(out);
|
||||
}
|
||||
|
||||
BufferedImage argbImage = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_INT_ARGB);
|
||||
data = ((DataBufferInt) argbImage.getRaster().getDataBuffer()).getData();
|
||||
|
||||
for (int y = 0; y < sizeY; y++) {
|
||||
for (int x = 0; x < sizeX; x++) {
|
||||
int v0 = imgraster[sizeX * y + x];
|
||||
|
||||
int rgb;
|
||||
if (v0 != 0xffff)
|
||||
rgb = 0xff000000 | v0; //(v0 << 8);
|
||||
else
|
||||
rgb = 0xff000000;
|
||||
data[y * sizeX + x] = rgb;
|
||||
}
|
||||
}
|
||||
|
||||
ImageIO.write(argbImage, "png", new FileOutputStream(imageName));
|
||||
}
|
||||
|
||||
private void createImageFromHgt(double lon, double lat, String dir, String imageName, int maxX, int maxY) throws Exception {
|
||||
HgtReader rdr = new HgtReader(dir);
|
||||
short[] data = rdr.getElevationDataFromHgt(lat, lon);
|
||||
if (data == null) {
|
||||
System.out.println("no data");
|
||||
return;
|
||||
}
|
||||
|
||||
int size = (data != null ? data.length : 0);
|
||||
int rowlen = (int) Math.sqrt(size);
|
||||
int sizeX = (maxX);
|
||||
int sizeY = (maxY);
|
||||
int[] imgraster = new int[sizeX * sizeY];
|
||||
|
||||
for (int y = 0; y < sizeY; y++) {
|
||||
for (int x = 0; x < sizeX; x++) {
|
||||
short e = data[(rowlen * y) + x];
|
||||
if (e != HgtReader.HGT_VOID && e < minElev) minElev = e;
|
||||
if (e != HgtReader.HGT_VOID && e > maxElev) maxElev = e;
|
||||
|
||||
if (e == HgtReader.HGT_VOID) {
|
||||
imgraster[sizeY * y + x] = 0xffff;
|
||||
} else if (e == 0) {
|
||||
imgraster[sizeY * y + x] = 0xffff;
|
||||
} else {
|
||||
imgraster[sizeY * y + x] = getColorForHeight((short) (e));
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("hgt size " + rowlen + " x " + rowlen + " min " + minElev + " max " + maxElev);
|
||||
if (DEBUG) {
|
||||
String out = "short ";
|
||||
for (int i = 0; i < 100; i++) {
|
||||
out += " " + data[i];
|
||||
}
|
||||
System.out.println(out);
|
||||
}
|
||||
BufferedImage argbImage = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_INT_ARGB);
|
||||
int[] idata = ((DataBufferInt) argbImage.getRaster().getDataBuffer()).getData();
|
||||
|
||||
for (int y = 0; y < sizeY; y++) {
|
||||
for (int x = 0; x < sizeX; x++) {
|
||||
int v0 = imgraster[sizeX * y + x];
|
||||
|
||||
int rgb;
|
||||
if (v0 != 0xffff)
|
||||
rgb = 0xff000000 | v0; //(v0 << 8);
|
||||
else
|
||||
rgb = 0xff000000;
|
||||
idata[y * sizeX + x] = rgb;
|
||||
}
|
||||
}
|
||||
|
||||
ImageIO.write(argbImage, "png", new FileOutputStream(imageName));
|
||||
|
||||
}
|
||||
|
||||
private void loadColors(String colors) {
|
||||
if (DEBUG) System.out.println("colors=" + colors);
|
||||
File colFile = new File(colors);
|
||||
if (colFile.exists()) {
|
||||
BufferedReader reader = null;
|
||||
colorMap = new TreeMap<>();
|
||||
try {
|
||||
reader = new BufferedReader(new FileReader(colors));
|
||||
String line = reader.readLine();
|
||||
|
||||
while (line != null) {
|
||||
if (DEBUG) System.out.println(line);
|
||||
String[] sa = line.split(",");
|
||||
if (!line.startsWith("#") && sa.length == 4) {
|
||||
short e = Short.parseShort(sa[0].trim());
|
||||
short r = Short.parseShort(sa[1].trim());
|
||||
short g = Short.parseShort(sa[2].trim());
|
||||
short b = Short.parseShort(sa[3].trim());
|
||||
colorMap.put(e, new Color(r, g, b));
|
||||
}
|
||||
// read next line
|
||||
line = reader.readLine();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
colorMap = null;
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
System.out.println("color file " + colors + " not found");
|
||||
}
|
||||
}
|
||||
|
||||
public double[] getElevationPos(ElevationRaster srtm, int ilon, int ilat) {
|
||||
double lon = ilon / 1000000. - 180.;
|
||||
double lat = ilat / 1000000. - 90.;
|
||||
|
||||
double dcol = (lon - srtm.xllcorner) / srtm.cellsize - 0.5;
|
||||
double drow = (lat - srtm.yllcorner) / srtm.cellsize - 0.5;
|
||||
int row = (int) drow;
|
||||
int col = (int) dcol;
|
||||
if (col < 0) col = 0;
|
||||
if (row < 0) row = 0;
|
||||
|
||||
return new double[]{drow, dcol};
|
||||
}
|
||||
|
||||
private short get(ElevationRaster srtm, int r, int c) {
|
||||
short e = srtm.eval_array[(srtm.nrows - 1 - r) * srtm.ncols + c];
|
||||
if (e == Short.MIN_VALUE) missingData = true;
|
||||
return e;
|
||||
}
|
||||
|
||||
public short getElevationXY(ElevationRaster srtm, double drow, double dcol) {
|
||||
int row = (int) drow;
|
||||
int col = (int) dcol;
|
||||
if (col < 0) col = 0;
|
||||
if (col >= srtm.ncols - 1) col = srtm.ncols - 2;
|
||||
if (row < 0) row = 0;
|
||||
if (row >= srtm.nrows - 1) row = srtm.nrows - 2;
|
||||
double wrow = drow - row;
|
||||
double wcol = dcol - col;
|
||||
missingData = false;
|
||||
|
||||
double eval = (1. - wrow) * (1. - wcol) * get(srtm, row, col)
|
||||
+ (wrow) * (1. - wcol) * get(srtm, row + 1, col)
|
||||
+ (1. - wrow) * (wcol) * get(srtm, row, col + 1)
|
||||
+ (wrow) * (wcol) * get(srtm, row + 1, col + 1);
|
||||
|
||||
return missingData ? Short.MIN_VALUE : (short) (eval * 4);
|
||||
}
|
||||
|
||||
|
||||
int getColorForHeight(short h) {
|
||||
if (colorMap == null) {
|
||||
colorMap = new TreeMap<>();
|
||||
colorMap.put((short) 0, new Color(102, 153, 153));
|
||||
colorMap.put((short) 1, new Color(0, 102, 0));
|
||||
colorMap.put((short) 500, new Color(251, 255, 128));
|
||||
colorMap.put((short) 1200, new Color(224, 108, 31));
|
||||
colorMap.put((short) 2500, new Color(200, 55, 55));
|
||||
colorMap.put((short) 4000, new Color(215, 244, 244));
|
||||
colorMap.put((short) 8000, new Color(255, 244, 244));
|
||||
}
|
||||
Color lastColor = null;
|
||||
short lastKey = 0;
|
||||
for (Entry<Short, Color> entry : colorMap.entrySet()) {
|
||||
short key = entry.getKey();
|
||||
Color value = entry.getValue();
|
||||
if (key == h) return value.getRGB();
|
||||
if (lastColor != null && lastKey < h && key > h) {
|
||||
double between = (double) (h - lastKey) / (key - lastKey);
|
||||
return mixColors(value, lastColor, between);
|
||||
}
|
||||
lastColor = value;
|
||||
lastKey = key;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int mixColors(Color color1, Color color2, double percent) {
|
||||
double inverse_percent = 1.0 - percent;
|
||||
int redPart = (int) (color1.getRed() * percent + color2.getRed() * inverse_percent);
|
||||
int greenPart = (int) (color1.getGreen() * percent + color2.getGreen() * inverse_percent);
|
||||
int bluePart = (int) (color1.getBlue() * percent + color2.getBlue() * inverse_percent);
|
||||
return new Color(redPart, greenPart, bluePart).getRGB();
|
||||
}
|
||||
|
||||
private ElevationRaster srtmForNode(int ilon, int ilat) throws Exception {
|
||||
int srtmLonIdx = (ilon + 5000000) / 5000000;
|
||||
int srtmLatIdx = (654999999 - ilat) / 5000000 - 100; // ugly negative rounding...
|
||||
|
||||
if (srtmLonIdx == lastSrtmLonIdx && srtmLatIdx == lastSrtmLatIdx) {
|
||||
return lastSrtmRaster;
|
||||
}
|
||||
lastSrtmLonIdx = srtmLonIdx;
|
||||
lastSrtmLatIdx = srtmLatIdx;
|
||||
|
||||
String slonidx = "0" + srtmLonIdx;
|
||||
String slatidx = "0" + srtmLatIdx;
|
||||
String filename = "srtm_" + slonidx.substring(slonidx.length() - 2) + "_" + slatidx.substring(slatidx.length() - 2);
|
||||
|
||||
lastSrtmRaster = srtmmap.get(filename);
|
||||
if (lastSrtmRaster == null && !srtmmap.containsKey(filename)) {
|
||||
File f = new File(new File(srtmdir), filename + ".bef");
|
||||
if (f.exists()) {
|
||||
System.out.println("*** reading: " + f);
|
||||
try {
|
||||
InputStream isc = new BufferedInputStream(new FileInputStream(f));
|
||||
lastSrtmRaster = new ElevationRasterCoder().decodeRaster(isc);
|
||||
isc.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println("**** ERROR reading " + f + " ****");
|
||||
}
|
||||
srtmmap.put(filename, lastSrtmRaster);
|
||||
return lastSrtmRaster;
|
||||
}
|
||||
|
||||
srtmmap.put(filename, lastSrtmRaster);
|
||||
}
|
||||
return lastSrtmRaster;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length < 6) {
|
||||
System.out.println("usage: java CreateLidarImage <lon> <lat> <srtm-folder> <imageFileName> <maxX> <maxY> <downscale> [type] [color_file]");
|
||||
System.out.println("\nwhere: type = [bef|hgt] downscale = [1|2|4|..]");
|
||||
return;
|
||||
}
|
||||
String format = args.length >= 8 ? args[7] : "bef";
|
||||
String colors = args.length == 9 ? args[8] : null;
|
||||
new CreateElevationRasterImage().createImage(Double.parseDouble(args[0]), Double.parseDouble(args[1]), args[2], args[3],
|
||||
Integer.parseInt(args[4]), Integer.parseInt(args[5]), Integer.parseInt(args[6]), format, colors);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,11 +3,11 @@ package btools.mapcreator;
|
|||
import btools.util.ReducedMedianFilter;
|
||||
|
||||
/**
|
||||
* Container for a srtm-raster + it's meta-data
|
||||
* Container for a elevation raster + it's meta-data
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
public class SrtmRaster {
|
||||
public class ElevationRaster {
|
||||
public int ncols;
|
||||
public int nrows;
|
||||
public boolean halfcol;
|
||||
|
|
@ -1,15 +1,20 @@
|
|||
package btools.mapcreator;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import btools.util.*;
|
||||
import btools.util.MixCoderDataInputStream;
|
||||
import btools.util.MixCoderDataOutputStream;
|
||||
|
||||
//
|
||||
// Encode/decode a raster
|
||||
//
|
||||
|
||||
public class RasterCoder {
|
||||
public void encodeRaster(SrtmRaster raster, OutputStream os) throws IOException {
|
||||
public class ElevationRasterCoder {
|
||||
public void encodeRaster(ElevationRaster raster, OutputStream os) throws IOException {
|
||||
DataOutputStream dos = new DataOutputStream(os);
|
||||
|
||||
long t0 = System.currentTimeMillis();
|
||||
|
|
@ -28,12 +33,12 @@ public class RasterCoder {
|
|||
System.out.println("finished encoding in " + (t1 - t0) + " ms");
|
||||
}
|
||||
|
||||
public SrtmRaster decodeRaster(InputStream is) throws IOException {
|
||||
public ElevationRaster decodeRaster(InputStream is) throws IOException {
|
||||
DataInputStream dis = new DataInputStream(is);
|
||||
|
||||
long t0 = System.currentTimeMillis();
|
||||
|
||||
SrtmRaster raster = new SrtmRaster();
|
||||
ElevationRaster raster = new ElevationRaster();
|
||||
raster.ncols = dis.readInt();
|
||||
raster.nrows = dis.readInt();
|
||||
raster.halfcol = dis.readBoolean();
|
||||
|
|
@ -45,7 +50,7 @@ public class RasterCoder {
|
|||
|
||||
_decodeRaster(raster, is);
|
||||
|
||||
raster.usingWeights = raster.ncols > 6001;
|
||||
raster.usingWeights = false; // raster.ncols > 6001;
|
||||
|
||||
long t1 = System.currentTimeMillis();
|
||||
System.out.println("finished decoding in " + (t1 - t0) + " ms ncols=" + raster.ncols + " nrows=" + raster.nrows);
|
||||
|
|
@ -53,7 +58,7 @@ public class RasterCoder {
|
|||
}
|
||||
|
||||
|
||||
private void _encodeRaster(SrtmRaster raster, OutputStream os) throws IOException {
|
||||
private void _encodeRaster(ElevationRaster raster, OutputStream os) throws IOException {
|
||||
MixCoderDataOutputStream mco = new MixCoderDataOutputStream(os);
|
||||
int nrows = raster.nrows;
|
||||
int ncols = raster.ncols;
|
||||
|
|
@ -78,7 +83,7 @@ public class RasterCoder {
|
|||
mco.flush();
|
||||
}
|
||||
|
||||
private void _decodeRaster(SrtmRaster raster, InputStream is) throws IOException {
|
||||
private void _decodeRaster(ElevationRaster raster, InputStream is) throws IOException {
|
||||
MixCoderDataInputStream mci = new MixCoderDataInputStream(is);
|
||||
int nrows = raster.nrows;
|
||||
int ncols = raster.ncols;
|
||||
|
|
@ -0,0 +1,545 @@
|
|||
package btools.mapcreator;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
public class ElevationRasterTileConverter {
|
||||
|
||||
public static final boolean DEBUG = false;
|
||||
|
||||
public static final short NODATA2 = -32767; // hgt-formats nodata
|
||||
public static final short NODATA = Short.MIN_VALUE;
|
||||
|
||||
private static final String HGT_FILE_EXT = ".hgt";
|
||||
private static final int HGT_BORDER_OVERLAP = 1;
|
||||
private static final int HGT_3ASEC_ROWS = 1201; // 3 arc second resolution (90m)
|
||||
private static final int HGT_3ASEC_FILE_SIZE = HGT_3ASEC_ROWS * HGT_3ASEC_ROWS * Short.BYTES;
|
||||
private static final int HGT_1ASEC_ROWS = 3601; // 1 arc second resolution (30m)
|
||||
private static final int SRTM3_ROW_LENGTH = 1200; // number of elevation values per line
|
||||
private static final int SRTM1_ROW_LENGTH = 3600;
|
||||
private static final boolean SRTM_NO_ZERO = true;
|
||||
|
||||
private int NROWS;
|
||||
private int NCOLS;
|
||||
private int ROW_LENGTH;
|
||||
private short[] imagePixels;
|
||||
|
||||
/**
|
||||
* This generates elevation raster files with a 5x5 degree scope
|
||||
* The output can be for 1sec (18000x18000 points)
|
||||
* or for 3sec (6000x6000 points)
|
||||
* When using 1sec input files a not found area can be called from 3sec pool
|
||||
* The input can be 1x1 degree 1sec/3sec hgt files (also packed as zip)
|
||||
* or 5x5 degree 3sec asc files (delivered as zip)
|
||||
* Arguments for single file generation:
|
||||
* ElevationRasterTileConverter <srtm-filename | all> <hgt-data-dir> <srtm-output-dir> [arc seconds (1 or 3,default=3)] [hgt-fallback-data-dir]
|
||||
* Samples
|
||||
* $ ... ElevationRasterTileConverter srtm_34_-1 ./srtm/hgt3sec ./srtm/srtm3_bef
|
||||
* $ ... ElevationRasterTileConverter srtm_34_-1 ./srtm/hgt1sec ./srtm/srtm1_bef 1
|
||||
* $ ... ElevationRasterTileConverter srtm_34_-1 ./srtm/hgt1sec ./srtm/srtm1_bef 1 ./srtm/hgt3sec
|
||||
* <p>
|
||||
* Arguments for multi file generation (world wide):
|
||||
* $ ... ElevationRasterTileConverter all ./srtm/hgt3sec ./srtm/srtm3_bef
|
||||
* $ ... ElevationRasterTileConverter all ./srtm/hgt1sec ./srtm/srtm1_bef 1
|
||||
* $ ... ElevationRasterTileConverter all ./srtm/hgt1sec ./srtm/srtm1_bef 1 ./srtm/hgt3sec
|
||||
*
|
||||
* @param args
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length == 3 || args.length == 4 || args.length == 5) {
|
||||
String filename90 = args[0];
|
||||
if ("all".equals(filename90)) {
|
||||
//if (DEBUG)
|
||||
System.out.println("raster convert all ");
|
||||
new ElevationRasterTileConverter().doConvertAll(args[1], args[2], (args.length > 3 ? args[3] : null), (args.length == 5 ? args[4] : null));
|
||||
return;
|
||||
}
|
||||
// old filenames only
|
||||
String filename30 = filename90 + ".bef"; //filename90.substring(0, filename90.length() - 3) + "bef";
|
||||
|
||||
int srtmLonIdx = Integer.parseInt(filename90.substring(5, 7).toLowerCase());
|
||||
int srtmLatIdx = Integer.parseInt(filename90.substring(8, 10).toLowerCase());
|
||||
|
||||
int ilon_base = (srtmLonIdx - 1) * 5 - 180;
|
||||
int ilat_base = 150 - srtmLatIdx * 5 - 90;
|
||||
int row_length = SRTM3_ROW_LENGTH;
|
||||
String fallbackdir = null;
|
||||
if (args.length > 3) {
|
||||
row_length = (Integer.parseInt(args[3]) == 1 ? SRTM1_ROW_LENGTH : SRTM3_ROW_LENGTH);
|
||||
fallbackdir = (args.length == 5 ? args[4] : null);
|
||||
}
|
||||
//if (DEBUG)
|
||||
System.out.println("raster convert " + ilon_base + " " + ilat_base + " from " + srtmLonIdx + " " + srtmLatIdx + " f: " + filename90 + " rowl " + row_length);
|
||||
|
||||
new ElevationRasterTileConverter().doConvert(args[1], ilon_base, ilat_base, args[2] + "/" + filename30, row_length, fallbackdir);
|
||||
} else {
|
||||
System.out.println("usage: java <srtm-filename> <hgt-data-dir> <srtm-output-dir> [arc seconds (1 or 3,default=3)] [hgt-fallback-data-dir]");
|
||||
System.out.println("or java all <hgt-data-dir> <srtm-output-dir> [arc seconds (1 or 3, default=3)] [hgt-fallback-data-dir]");
|
||||
}
|
||||
}
|
||||
|
||||
private void doConvertAll(String hgtdata, String outdir, String rlen, String hgtfallbackdata) throws Exception {
|
||||
int row_length = SRTM3_ROW_LENGTH;
|
||||
if (rlen != null) {
|
||||
row_length = (Integer.parseInt(rlen) == 1 ? SRTM1_ROW_LENGTH : SRTM3_ROW_LENGTH);
|
||||
}
|
||||
String filename30;
|
||||
for (int ilon_base = -180; ilon_base < 180; ilon_base += 5) {
|
||||
for (int ilat_base = 85; ilat_base > -90; ilat_base -= 5) {
|
||||
if (PosUnifier.UseRasterRd5FileName) {
|
||||
filename30 = genFilenameRd5(ilon_base, ilat_base);
|
||||
} else {
|
||||
filename30 = genFilenameOld(ilon_base, ilat_base);
|
||||
}
|
||||
if (DEBUG)
|
||||
System.out.println("lidar convert all: " + filename30);
|
||||
doConvert(hgtdata, ilon_base, ilat_base, outdir + "/" + filename30, row_length, hgtfallbackdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static String genFilenameOld(int ilon_base, int ilat_base) {
|
||||
int srtmLonIdx = ((ilon_base + 180) / 5) + 1;
|
||||
int srtmLatIdx = (60 - ilat_base) / 5;
|
||||
return String.format(Locale.US, "srtm_%02d_%02d.bef", srtmLonIdx, srtmLatIdx);
|
||||
}
|
||||
|
||||
static String genFilenameRd5(int ilon_base, int ilat_base) {
|
||||
return String.format("srtm_%s_%s.bef", ilon_base < 0 ? "W" + (-ilon_base) : "E" + ilon_base,
|
||||
ilat_base < 0 ? "S" + (-ilat_base) : "N" + ilat_base);
|
||||
}
|
||||
|
||||
private void readHgtZip(String filename, int rowOffset, int colOffset, int row_length, int scale) throws Exception {
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(filename)));
|
||||
try {
|
||||
for (; ; ) {
|
||||
ZipEntry ze = zis.getNextEntry();
|
||||
if (ze == null) break;
|
||||
if (ze.getName().toLowerCase().endsWith(HGT_FILE_EXT)) {
|
||||
readHgtFromStream(zis, rowOffset, colOffset, row_length, scale);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
zis.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void readHgtFromStream(InputStream is, int rowOffset, int colOffset, int rowLength, int scale)
|
||||
throws Exception {
|
||||
DataInputStream dis = new DataInputStream(new BufferedInputStream(is));
|
||||
for (int ir = 0; ir < rowLength; ir++) {
|
||||
int row = rowOffset + ir * scale;
|
||||
|
||||
for (int ic = 0; ic < rowLength; ic++) {
|
||||
int col = colOffset + ic * scale;
|
||||
|
||||
int i1 = dis.read(); // msb first!
|
||||
int i0 = dis.read();
|
||||
|
||||
if (i0 == -1 || i1 == -1)
|
||||
throw new RuntimeException("unexpected end of file reading hgt entry!");
|
||||
|
||||
short val = (short) ((i1 << 8) | i0);
|
||||
|
||||
if (val == NODATA2) {
|
||||
val = NODATA;
|
||||
}
|
||||
if (scale == 3) {
|
||||
setPixel(row, col, val);
|
||||
setPixel(row + 1, col, val);
|
||||
setPixel(row + 2, col, val);
|
||||
setPixel(row, col + 1, val);
|
||||
setPixel(row + 1, col + 1, val);
|
||||
setPixel(row + 2, col + 1, val);
|
||||
setPixel(row, col + 2, val);
|
||||
setPixel(row + 1, col + 2, val);
|
||||
setPixel(row + 2, col + 2, val);
|
||||
} else {
|
||||
setPixel(row, col, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readHgtFile(File file, int rowOffset, int colOffset, int row_length, int scale)
|
||||
throws Exception {
|
||||
|
||||
if (DEBUG)
|
||||
System.out.println("read: " + file + " " + row_length);
|
||||
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
try {
|
||||
readHgtFromStream(fis, rowOffset, colOffset, row_length, scale);
|
||||
} finally {
|
||||
fis.close();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
private void readFallbackFile(File file, int rowOffset, int colOffset, int row_length)
|
||||
throws Exception {
|
||||
int rowLength;
|
||||
int scale;
|
||||
if (file.length() > HGT_3ASEC_FILE_SIZE) {
|
||||
rowLength = HGT_1ASEC_ROWS;
|
||||
scale = 1;
|
||||
} else {
|
||||
rowLength = HGT_3ASEC_ROWS;
|
||||
scale = 3;
|
||||
}
|
||||
if (DEBUG)
|
||||
System.out.println("read fallback: " + file + " " + rowLength);
|
||||
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
try {
|
||||
readHgtFromStream(fis, rowOffset, colOffset, rowLength, scale);
|
||||
} finally {
|
||||
fis.close();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
private void readAscZip(File file, ElevationRaster raster) throws Exception {
|
||||
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(file)));
|
||||
try {
|
||||
for (; ; ) {
|
||||
ZipEntry ze = zis.getNextEntry();
|
||||
if (ze.getName().endsWith(".asc")) {
|
||||
readAscFromStream(zis, raster);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
zis.close();
|
||||
}
|
||||
}
|
||||
|
||||
private String secondToken(String s) {
|
||||
StringTokenizer tk = new StringTokenizer(s, " ");
|
||||
tk.nextToken();
|
||||
return tk.nextToken();
|
||||
}
|
||||
|
||||
private void readAscFromStream(InputStream is, ElevationRaster raster) throws Exception {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(is));
|
||||
int linenr = 0;
|
||||
for (; ; ) {
|
||||
linenr++;
|
||||
if (linenr <= 6) {
|
||||
String line = br.readLine();
|
||||
if (linenr == 1)
|
||||
raster.ncols = Integer.parseInt(secondToken(line));
|
||||
else if (linenr == 2)
|
||||
raster.nrows = Integer.parseInt(secondToken(line));
|
||||
else if (linenr == 3)
|
||||
raster.xllcorner = Double.parseDouble(secondToken(line));
|
||||
else if (linenr == 4)
|
||||
raster.yllcorner = Double.parseDouble(secondToken(line));
|
||||
else if (linenr == 5)
|
||||
raster.cellsize = Double.parseDouble(secondToken(line));
|
||||
else if (linenr == 6) {
|
||||
// nodata ignored here ( < -250 assumed nodata... )
|
||||
// raster.noDataValue = Short.parseShort( secondToken( line ) );
|
||||
raster.eval_array = new short[raster.ncols * raster.nrows];
|
||||
}
|
||||
} else {
|
||||
int row = 0;
|
||||
int col = 0;
|
||||
int n = 0;
|
||||
boolean negative = false;
|
||||
for (; ; ) {
|
||||
int c = br.read();
|
||||
if (c < 0)
|
||||
break;
|
||||
if (c == ' ') {
|
||||
if (negative)
|
||||
n = -n;
|
||||
short val = n < -250 ? Short.MIN_VALUE : (short) (n);
|
||||
|
||||
raster.eval_array[row * raster.ncols + col] = val;
|
||||
if (++col == raster.ncols) {
|
||||
col = 0;
|
||||
++row;
|
||||
}
|
||||
n = 0;
|
||||
negative = false;
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
n = 10 * n + (c - '0');
|
||||
} else if (c == '-') {
|
||||
negative = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
br.close();
|
||||
}
|
||||
|
||||
|
||||
private void setPixel(int row, int col, short val) {
|
||||
if (row >= 0 && row < NROWS && col >= 0 && col < NCOLS) {
|
||||
imagePixels[row * NCOLS + col] = val;
|
||||
}
|
||||
}
|
||||
|
||||
private short getPixel(int row, int col) {
|
||||
if (row >= 0 && row < NROWS && col >= 0 && col < NCOLS) {
|
||||
return imagePixels[row * NCOLS + col];
|
||||
}
|
||||
return NODATA;
|
||||
}
|
||||
|
||||
|
||||
public void doConvert(String inputDir, int lonDegreeStart, int latDegreeStart, String outputFile, int row_length, String hgtfallbackdata) throws Exception {
|
||||
int extraBorder = 0;
|
||||
|
||||
//List<String> foundList = new ArrayList<>();
|
||||
//List<String> notfoundList = new ArrayList<>();
|
||||
|
||||
boolean hgtfound = false;
|
||||
boolean ascfound = false;
|
||||
String filename = null;
|
||||
//if (row_length == SRTM1_ROW_LENGTH)
|
||||
{
|
||||
// check for sources w/o border
|
||||
for (int latIdx = 0; latIdx < 5; latIdx++) {
|
||||
int latDegree = latDegreeStart + latIdx;
|
||||
|
||||
for (int lonIdx = 0; lonIdx < 5; lonIdx++) {
|
||||
int lonDegree = lonDegreeStart + lonIdx;
|
||||
|
||||
filename = inputDir + "/" + formatLat(latDegree) + formatLon(lonDegree) + ".zip";
|
||||
File f = new File(filename);
|
||||
if (f.exists() && f.length() > 0) {
|
||||
hgtfound = true;
|
||||
break;
|
||||
}
|
||||
filename = filename.substring(0, filename.length() - 4) + ".hgt";
|
||||
f = new File(filename);
|
||||
if (f.exists() && f.length() > 0) {
|
||||
hgtfound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hgtfound) {
|
||||
filename = inputDir + "/" + genFilenameOld(lonDegreeStart, latDegreeStart).substring(0, 10) + ".zip";
|
||||
File f = new File(filename);
|
||||
if (f.exists() && f.length() > 0) {
|
||||
ascfound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hgtfound) { // init when found
|
||||
NROWS = 5 * row_length + 1 + 2 * extraBorder;
|
||||
NCOLS = 5 * row_length + 1 + 2 * extraBorder;
|
||||
imagePixels = new short[NROWS * NCOLS]; // 650 MB !
|
||||
|
||||
// prefill as NODATA
|
||||
Arrays.fill(imagePixels, NODATA);
|
||||
} else if (!ascfound) {
|
||||
if (DEBUG)
|
||||
System.out.println("none data: " + lonDegreeStart + " " + latDegreeStart);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hgtfound) {
|
||||
for (int latIdx = -1; latIdx <= 5; latIdx++) {
|
||||
int latDegree = latDegreeStart + latIdx;
|
||||
int rowOffset = extraBorder + (4 - latIdx) * row_length;
|
||||
|
||||
for (int lonIdx = -1; lonIdx <= 5; lonIdx++) {
|
||||
int lonDegree = lonDegreeStart + lonIdx;
|
||||
int colOffset = extraBorder + lonIdx * row_length;
|
||||
|
||||
filename = inputDir + "/" + formatLat(latDegree) + formatLon(lonDegree) + ".zip";
|
||||
File f = new File(filename);
|
||||
if (f.exists() && f.length() > 0) {
|
||||
if (DEBUG)
|
||||
System.out.println("exist: " + filename);
|
||||
readHgtZip(filename, rowOffset, colOffset, row_length + 1, 1);
|
||||
continue;
|
||||
}
|
||||
filename = filename.substring(0, filename.length() - 4) + ".hgt";
|
||||
f = new File(filename);
|
||||
if (f.exists() && f.length() > 0) {
|
||||
if (DEBUG)
|
||||
System.out.println("exist: " + filename);
|
||||
readHgtFile(f, rowOffset, colOffset, row_length + 1, 1);
|
||||
continue;
|
||||
} else {
|
||||
if (hgtfallbackdata != null) {
|
||||
filename = hgtfallbackdata + "/" + formatLat(latDegree) + formatLon(lonDegree) + ".hgt";
|
||||
f = new File(filename);
|
||||
if (f.exists() && f.length() > 0) {
|
||||
readHgtFile(f, rowOffset, colOffset, SRTM3_ROW_LENGTH + 1, 3);
|
||||
continue;
|
||||
}
|
||||
filename = filename.substring(0, filename.length() - 4) + ".zip";
|
||||
f = new File(filename);
|
||||
if (f.exists() && f.length() > 0) {
|
||||
readHgtZip(filename, rowOffset, colOffset, SRTM3_ROW_LENGTH + 1, 3);
|
||||
} else {
|
||||
if (DEBUG)
|
||||
System.out.println("none : " + filename);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// post fill zero
|
||||
if (SRTM_NO_ZERO) {
|
||||
for (int row = 0; row < NROWS; row++) {
|
||||
for (int col = 0; col < NCOLS; col++) {
|
||||
if (imagePixels[row * NCOLS + col] == 0) imagePixels[row * NCOLS + col] = NODATA;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean halfCol5 = false; // no halfcol tiles in lidar data (?)
|
||||
|
||||
|
||||
ElevationRaster raster = new ElevationRaster();
|
||||
if (hgtfound) {
|
||||
raster.nrows = NROWS;
|
||||
raster.ncols = NCOLS;
|
||||
raster.halfcol = halfCol5;
|
||||
raster.noDataValue = NODATA;
|
||||
raster.cellsize = 1. / row_length;
|
||||
raster.xllcorner = lonDegreeStart - (0.5 + extraBorder) * raster.cellsize;
|
||||
raster.yllcorner = latDegreeStart - (0.5 + extraBorder) * raster.cellsize;
|
||||
raster.eval_array = imagePixels;
|
||||
}
|
||||
|
||||
if (ascfound) {
|
||||
File f = new File(filename);
|
||||
readAscZip(f, raster);
|
||||
}
|
||||
|
||||
// encode the raster
|
||||
OutputStream os = new BufferedOutputStream(new FileOutputStream(outputFile));
|
||||
new ElevationRasterCoder().encodeRaster(raster, os);
|
||||
os.close();
|
||||
|
||||
// decode the raster
|
||||
InputStream is = new BufferedInputStream(new FileInputStream(outputFile));
|
||||
ElevationRaster raster2 = new ElevationRasterCoder().decodeRaster(is);
|
||||
is.close();
|
||||
|
||||
short[] pix2 = raster2.eval_array;
|
||||
if (pix2.length != raster.eval_array.length)
|
||||
throw new RuntimeException("length mismatch!");
|
||||
|
||||
// compare decoding result
|
||||
for (int row = 0; row < raster.nrows; row++) {
|
||||
int colstep = halfCol5 ? 2 : 1;
|
||||
for (int col = 0; col < raster.ncols; col += colstep) {
|
||||
int idx = row * raster.ncols + col;
|
||||
short p2 = pix2[idx];
|
||||
if (p2 != raster.eval_array[idx]) {
|
||||
throw new RuntimeException("content mismatch: p2=" + p2 + " p1=" + raster.eval_array[idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
imagePixels = null;
|
||||
}
|
||||
|
||||
private static String formatLon(int lon) {
|
||||
if (lon >= 180)
|
||||
lon -= 180; // TODO: w180 oder E180 ?
|
||||
|
||||
String s = "E";
|
||||
if (lon < 0) {
|
||||
lon = -lon;
|
||||
s = "W";
|
||||
}
|
||||
String n = "000" + lon;
|
||||
return s + n.substring(n.length() - 3);
|
||||
}
|
||||
|
||||
private static String formatLat(int lat) {
|
||||
String s = "N";
|
||||
if (lat < 0) {
|
||||
lat = -lat;
|
||||
s = "S";
|
||||
}
|
||||
String n = "00" + lat;
|
||||
return s + n.substring(n.length() - 2);
|
||||
}
|
||||
|
||||
|
||||
public ElevationRaster getRaster(File f, double lon, double lat) throws Exception {
|
||||
long fileSize;
|
||||
InputStream inputStream;
|
||||
|
||||
if (f.getName().toLowerCase().endsWith(".zip")) {
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(f)));
|
||||
for (; ; ) {
|
||||
ZipEntry ze = zis.getNextEntry();
|
||||
if (ze == null) {
|
||||
throw new FileNotFoundException(f.getName() + " doesn't contain a " + HGT_FILE_EXT + " file.");
|
||||
}
|
||||
if (ze.getName().toLowerCase().endsWith(HGT_FILE_EXT)) {
|
||||
fileSize = ze.getSize();
|
||||
inputStream = zis;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fileSize = f.length();
|
||||
inputStream = new FileInputStream(f);
|
||||
}
|
||||
|
||||
int rowLength;
|
||||
if (fileSize > HGT_3ASEC_FILE_SIZE) {
|
||||
rowLength = HGT_1ASEC_ROWS;
|
||||
} else {
|
||||
rowLength = HGT_3ASEC_ROWS;
|
||||
}
|
||||
|
||||
// stay at 1 deg * 1 deg raster
|
||||
NROWS = rowLength;
|
||||
NCOLS = rowLength;
|
||||
|
||||
imagePixels = new short[NROWS * NCOLS];
|
||||
|
||||
// prefill as NODATA
|
||||
Arrays.fill(imagePixels, NODATA);
|
||||
readHgtFromStream(inputStream, 0, 0, rowLength, 1);
|
||||
inputStream.close();
|
||||
|
||||
ElevationRaster raster = new ElevationRaster();
|
||||
raster.nrows = NROWS;
|
||||
raster.ncols = NCOLS;
|
||||
raster.halfcol = false; // assume full resolution
|
||||
raster.noDataValue = NODATA;
|
||||
raster.cellsize = 1. / (double) (rowLength - HGT_BORDER_OVERLAP);
|
||||
raster.xllcorner = (int) (lon < 0 ? lon - 1 : lon); //onDegreeStart - raster.cellsize;
|
||||
raster.yllcorner = (int) (lat < 0 ? lat - 1 : lat); //latDegreeStart - raster.cellsize;
|
||||
raster.eval_array = imagePixels;
|
||||
|
||||
return raster;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,342 @@
|
|||
// License: GPL. For details, see LICENSE file.
|
||||
package btools.mapcreator;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
/**
|
||||
* adapted from https://github.com/JOSM/josm-plugins/blob/master/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/HgtReader.java
|
||||
* <p>
|
||||
* Class HgtReader reads data from SRTM HGT files. Currently this class is restricted to a resolution of 3 arc seconds.
|
||||
* <p>
|
||||
* SRTM data files are available at the <a href="http://dds.cr.usgs.gov/srtm/version2_1/SRTM3">NASA SRTM site</a>
|
||||
*
|
||||
* @author Oliver Wieland <oliver.wieland@online.de>
|
||||
*/
|
||||
public class HgtReader {
|
||||
final static boolean DEBUG = false;
|
||||
|
||||
private static final int SECONDS_PER_MINUTE = 60;
|
||||
|
||||
public static final String HGT_EXT = ".hgt";
|
||||
public static final String ZIP_EXT = ".zip";
|
||||
|
||||
// alter these values for different SRTM resolutions
|
||||
public static final int HGT3_RES = 3; // resolution in arc seconds
|
||||
public static final int HGT3_ROW_LENGTH = 1201; // number of elevation values per line
|
||||
public static final int HGT_VOID = -32768; // magic number which indicates 'void data' in HGT file
|
||||
public static final int HGT1_RES = 1; // <<- The new SRTM is 1-ARCSEC
|
||||
public static final int HGT1_ROW_LENGTH = 3601; //-- New file resolution is 3601x3601
|
||||
/**
|
||||
* The 'no elevation' data magic.
|
||||
*/
|
||||
public static double NO_ELEVATION = Double.NaN;
|
||||
|
||||
private static String srtmFolder = "";
|
||||
|
||||
private static final Map<String, ShortBuffer> cache = new HashMap<>();
|
||||
|
||||
public HgtReader(String folder) {
|
||||
srtmFolder = folder;
|
||||
}
|
||||
|
||||
public static double getElevationFromHgt(double lat, double lon) {
|
||||
try {
|
||||
String file = getHgtFileName(lat, lon);
|
||||
if (DEBUG) System.out.println("HGT buffer " + file + " for " + lat + " " + lon);
|
||||
|
||||
// given area in cache?
|
||||
if (!cache.containsKey(file)) {
|
||||
|
||||
// fill initial cache value. If no file is found, then
|
||||
// we use it as a marker to indicate 'file has been searched
|
||||
// but is not there'
|
||||
cache.put(file, null);
|
||||
// Try all resource directories
|
||||
//for (String location : Main.pref.getAllPossiblePreferenceDirs())
|
||||
{
|
||||
String fullPath = new File(srtmFolder, file + HGT_EXT).getPath();
|
||||
File f = new File(fullPath);
|
||||
if (f.exists()) {
|
||||
// found something: read HGT file...
|
||||
ShortBuffer data = readHgtFile(fullPath);
|
||||
// ... and store result in cache
|
||||
cache.put(file, data);
|
||||
//break;
|
||||
} else {
|
||||
fullPath = new File(srtmFolder, file + ZIP_EXT).getPath();
|
||||
f = new File(fullPath);
|
||||
if (f.exists()) {
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(f)));
|
||||
try {
|
||||
for (; ; ) {
|
||||
ZipEntry ze = zis.getNextEntry();
|
||||
if (ze == null) break;
|
||||
if (ze.getName().toLowerCase().endsWith(HGT_EXT)) {
|
||||
// System.out.println("read zip " + ze.getName());
|
||||
ShortBuffer data = readHgtStream(zis);
|
||||
// ... and store result in cache
|
||||
cache.put(file, data);
|
||||
break;
|
||||
}
|
||||
zis.closeEntry();
|
||||
}
|
||||
} finally {
|
||||
zis.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("*** reading: " + f.getName() + " " + cache.get(file));
|
||||
}
|
||||
}
|
||||
|
||||
// read elevation value
|
||||
return readElevation(lat, lon);
|
||||
} catch (FileNotFoundException e) {
|
||||
System.err.println("HGT Get elevation " + lat + ", " + lon + " failed: => " + e.getMessage());
|
||||
// no problem... file not there
|
||||
return NO_ELEVATION;
|
||||
} catch (Exception ioe) {
|
||||
// oops...
|
||||
ioe.printStackTrace(System.err);
|
||||
// fallback
|
||||
return NO_ELEVATION;
|
||||
}
|
||||
}
|
||||
|
||||
public static short[] getElevationDataFromHgt(double lat, double lon) {
|
||||
try {
|
||||
if (lon < 0) lon += 1;
|
||||
if (lat < 0) lat += 1;
|
||||
String file = getHgtFileName(lat, lon);
|
||||
if (DEBUG) System.out.println("HGT buffer " + file + " for " + lat + " " + lon);
|
||||
|
||||
ShortBuffer data = null;
|
||||
|
||||
// Try all resource directories
|
||||
//for (String location : Main.pref.getAllPossiblePreferenceDirs())
|
||||
|
||||
String fullPath = new File(srtmFolder, file + HGT_EXT).getPath();
|
||||
File f = new File(fullPath);
|
||||
if (f.exists()) {
|
||||
// found something: read HGT file...
|
||||
data = readHgtFile(fullPath);
|
||||
} else {
|
||||
fullPath = new File(srtmFolder, file + ZIP_EXT).getPath();
|
||||
f = new File(fullPath);
|
||||
if (f.exists()) {
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(f)));
|
||||
try {
|
||||
for (; ; ) {
|
||||
ZipEntry ze = zis.getNextEntry();
|
||||
if (ze == null) break;
|
||||
if (ze.getName().toLowerCase().endsWith(HGT_EXT)) {
|
||||
// System.out.println("read zip " + ze.getName());
|
||||
data = readHgtStream(zis);
|
||||
break;
|
||||
}
|
||||
zis.closeEntry();
|
||||
}
|
||||
} finally {
|
||||
zis.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
System.out.println("*** reading: " + f.getName() + " " + (data != null ? data.limit() : -1));
|
||||
if (data != null) {
|
||||
short[] array = new short[data.limit()];
|
||||
data.get(array);
|
||||
return array;
|
||||
}
|
||||
return null;
|
||||
} catch (FileNotFoundException e) {
|
||||
System.err.println("HGT Get elevation " + lat + ", " + lon + " failed: => " + e.getMessage());
|
||||
// no problem... file not there
|
||||
return null;
|
||||
} catch (Exception ioe) {
|
||||
// oops...
|
||||
ioe.printStackTrace(System.err);
|
||||
// fallback
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
private static ShortBuffer readHgtFile(String file) throws Exception {
|
||||
if (file == null) throw new Exception("no hgt file " + file);
|
||||
|
||||
FileChannel fc = null;
|
||||
ShortBuffer sb = null;
|
||||
try {
|
||||
// Eclipse complains here about resource leak on 'fc' - even with 'finally' clause???
|
||||
fc = new FileInputStream(file).getChannel();
|
||||
// choose the right endianness
|
||||
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect((int) fc.size());
|
||||
while (bb.remaining() > 0) fc.read(bb);
|
||||
|
||||
bb.flip();
|
||||
//sb = bb.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
|
||||
sb = bb.order(ByteOrder.BIG_ENDIAN).asShortBuffer();
|
||||
} finally {
|
||||
if (fc != null) fc.close();
|
||||
}
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
// @SuppressWarnings("resource")
|
||||
private static ShortBuffer readHgtStream(InputStream zis) throws Exception {
|
||||
if (zis == null) throw new Exception("no hgt stream ");
|
||||
|
||||
ShortBuffer sb = null;
|
||||
try {
|
||||
// choose the right endianness
|
||||
|
||||
byte[] bytes = zis.readAllBytes();
|
||||
ByteBuffer bb = ByteBuffer.allocate(bytes.length);
|
||||
bb.put(bytes, 0, bytes.length);
|
||||
//while (bb.remaining() > 0) zis.read(bb, 0, size);
|
||||
|
||||
//ByteBuffer bb = ByteBuffer.allocate(zis.available());
|
||||
//Channels.newChannel(zis).read(bb);
|
||||
bb.flip();
|
||||
//sb = bb.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
|
||||
sb = bb.order(ByteOrder.BIG_ENDIAN).asShortBuffer();
|
||||
} finally {
|
||||
|
||||
}
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the elevation value for the given coordinate.
|
||||
* <p>
|
||||
* See also <a href="http://gis.stackexchange.com/questions/43743/how-to-extract-elevation-from-hgt-file">stackexchange.com</a>
|
||||
*
|
||||
* @param lat, lon the coordinate to get the elevation data for
|
||||
* @return the elevation value or <code>Double.NaN</code>, if no value is present
|
||||
*/
|
||||
public static double readElevation(double lat, double lon) {
|
||||
String tag = getHgtFileName(lat, lon);
|
||||
|
||||
ShortBuffer sb = cache.get(tag);
|
||||
|
||||
if (sb == null) {
|
||||
return NO_ELEVATION;
|
||||
}
|
||||
|
||||
if (DEBUG) System.out.println("HGT buffer size " + sb.capacity() + " limit " + sb.limit());
|
||||
try {
|
||||
int rowLength = HGT3_ROW_LENGTH;
|
||||
int resolution = HGT3_RES;
|
||||
if (sb.capacity() > (HGT3_ROW_LENGTH * HGT3_ROW_LENGTH)) {
|
||||
rowLength = HGT1_ROW_LENGTH;
|
||||
resolution = HGT1_RES;
|
||||
}
|
||||
// see http://gis.stackexchange.com/questions/43743/how-to-extract-elevation-from-hgt-file
|
||||
double fLat = frac(lat) * SECONDS_PER_MINUTE;
|
||||
double fLon = frac(lon) * SECONDS_PER_MINUTE;
|
||||
|
||||
// compute offset within HGT file
|
||||
int row = (int) Math.round((fLat) * SECONDS_PER_MINUTE / resolution);
|
||||
int col = (int) Math.round((fLon) * SECONDS_PER_MINUTE / resolution);
|
||||
if (lon < 0) col = rowLength - col - 1;
|
||||
if (lat > 0) row = rowLength - row - 1;
|
||||
|
||||
|
||||
//row = rowLength - row;
|
||||
int cell = (rowLength * (row)) + col;
|
||||
//int cell = ((rowLength * (latitude)) + longitude);
|
||||
|
||||
if (DEBUG)
|
||||
System.out.println("Read HGT elevation data from row/col/cell " + row + "," + col + ", " + cell + ", " + sb.limit());
|
||||
|
||||
// valid position in buffer?
|
||||
if (cell < sb.limit()) {
|
||||
short ele = sb.get(cell);
|
||||
// check for data voids
|
||||
if (ele == HGT_VOID) {
|
||||
return NO_ELEVATION;
|
||||
} else {
|
||||
return ele;
|
||||
}
|
||||
} else {
|
||||
return NO_ELEVATION;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("error at " + lon + " " + lat + " ");
|
||||
e.printStackTrace();
|
||||
}
|
||||
return NO_ELEVATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the associated HGT file name for the given way point. Usually the
|
||||
* format is <tt>[N|S]nn[W|E]mmm.hgt</tt> where <i>nn</i> is the integral latitude
|
||||
* without decimals and <i>mmm</i> is the longitude.
|
||||
*
|
||||
* @param llat,llon the coordinate to get the filename for
|
||||
* @return the file name of the HGT file
|
||||
*/
|
||||
public static String getHgtFileName(double llat, double llon) {
|
||||
int lat = (int) llat;
|
||||
int lon = (int) llon;
|
||||
|
||||
String latPref = "N";
|
||||
if (lat < 0) {
|
||||
latPref = "S";
|
||||
lat = -lat + 1;
|
||||
}
|
||||
String lonPref = "E";
|
||||
if (lon < 0) {
|
||||
lonPref = "W";
|
||||
lon = -lon + 1;
|
||||
}
|
||||
|
||||
return String.format("%s%02d%s%03d", latPref, lat, lonPref, lon);
|
||||
}
|
||||
|
||||
public static double frac(double d) {
|
||||
long iPart;
|
||||
double fPart;
|
||||
|
||||
// Get user input
|
||||
iPart = (long) d;
|
||||
fPart = d - iPart;
|
||||
return Math.abs(fPart);
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
if (cache != null) {
|
||||
cache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("*** HGT position values and enhance elevation");
|
||||
if (args.length == 3) {
|
||||
HgtReader elevReader = new HgtReader(args[0]);
|
||||
double lon = Double.parseDouble(args[1]);
|
||||
double lat = Double.parseDouble(args[2]);
|
||||
// check hgt direct
|
||||
double elev = elevReader.getElevationFromHgt(lat, lon);
|
||||
System.out.println("-----> elv for hgt " + lat + ", " + lon + " = " + elev);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,8 @@ package btools.mapcreator;
|
|||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import btools.codec.MicroCache;
|
||||
import btools.codec.MicroCache2;
|
||||
|
|
@ -91,10 +93,10 @@ public class OsmNodeP extends OsmLinkP {
|
|||
return null;
|
||||
}
|
||||
|
||||
public void writeNodeData(MicroCache mc, OsmTrafficMap trafficMap) throws IOException {
|
||||
public void writeNodeData(MicroCache mc) throws IOException {
|
||||
boolean valid = true;
|
||||
if (mc instanceof MicroCache2) {
|
||||
valid = writeNodeData2((MicroCache2) mc, trafficMap);
|
||||
valid = writeNodeData2((MicroCache2) mc);
|
||||
} else
|
||||
throw new IllegalArgumentException("unknown cache version: " + mc.getClass());
|
||||
if (valid) {
|
||||
|
|
@ -105,7 +107,7 @@ public class OsmNodeP extends OsmLinkP {
|
|||
}
|
||||
|
||||
public void checkDuplicateTargets() {
|
||||
HashMap<OsmNodeP, OsmLinkP> targets = new HashMap<>();
|
||||
Map<OsmNodeP, OsmLinkP> targets = new HashMap<>();
|
||||
|
||||
for (OsmLinkP link0 = getFirstLink(); link0 != null; link0 = link0.getNext(this)) {
|
||||
OsmLinkP link = link0;
|
||||
|
|
@ -142,7 +144,7 @@ public class OsmNodeP extends OsmLinkP {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean writeNodeData2(MicroCache2 mc, OsmTrafficMap trafficMap) throws IOException {
|
||||
public boolean writeNodeData2(MicroCache2 mc) throws IOException {
|
||||
boolean hasLinks = false;
|
||||
|
||||
// write turn restrictions
|
||||
|
|
@ -165,14 +167,14 @@ public class OsmNodeP extends OsmLinkP {
|
|||
mc.writeVarBytes(getNodeDecsription());
|
||||
|
||||
// buffer internal reverse links
|
||||
ArrayList<OsmNodeP> internalReverse = new ArrayList<>();
|
||||
List<OsmNodeP> internalReverse = new ArrayList<>();
|
||||
|
||||
for (OsmLinkP link0 = getFirstLink(); link0 != null; link0 = link0.getNext(this)) {
|
||||
OsmLinkP link = link0;
|
||||
OsmNodeP origin = this;
|
||||
OsmNodeP target = null;
|
||||
|
||||
ArrayList<OsmNodeP> linkNodes = new ArrayList<>();
|
||||
List<OsmNodeP> linkNodes = new ArrayList<>();
|
||||
linkNodes.add(this);
|
||||
|
||||
// first pass just to see if that link is consistent
|
||||
|
|
@ -210,11 +212,7 @@ public class OsmNodeP extends OsmLinkP {
|
|||
}
|
||||
}
|
||||
|
||||
// add traffic simulation, if present
|
||||
byte[] description = link0.descriptionBitmap;
|
||||
if (trafficMap != null) {
|
||||
description = trafficMap.addTrafficClass(linkNodes, description);
|
||||
}
|
||||
|
||||
// write link data
|
||||
int sizeoffset = mc.writeSizePlaceHolder();
|
||||
|
|
@ -226,7 +224,7 @@ public class OsmNodeP extends OsmLinkP {
|
|||
origin = this;
|
||||
for (int i = 1; i < linkNodes.size() - 1; i++) {
|
||||
OsmNodeP tranferNode = linkNodes.get(i);
|
||||
if ((tranferNode.bits & OsmNodeP.DP_SURVIVOR_BIT) != 0) {
|
||||
if ((tranferNode.bits & DP_SURVIVOR_BIT) != 0) {
|
||||
mc.writeVarLengthSigned(tranferNode.ilon - origin.ilon);
|
||||
mc.writeVarLengthSigned(tranferNode.ilat - origin.ilat);
|
||||
mc.writeVarLengthSigned(tranferNode.getSElev() - origin.getSElev());
|
||||
|
|
|
|||
|
|
@ -1,245 +0,0 @@
|
|||
/**
|
||||
* Container for link between two Osm nodes (pre-pocessor version)
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
package btools.mapcreator;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
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.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import btools.expressions.BExpressionContextWay;
|
||||
import btools.util.CheapRuler;
|
||||
import btools.util.CompactLongMap;
|
||||
import btools.util.FrozenLongMap;
|
||||
|
||||
|
||||
public class OsmTrafficMap {
|
||||
int minLon;
|
||||
int minLat;
|
||||
int maxLon;
|
||||
int maxLat;
|
||||
|
||||
private BExpressionContextWay expctxWay;
|
||||
|
||||
private OsmTrafficMap oldTrafficClasses;
|
||||
private DataOutputStream newTrafficDos;
|
||||
private File oldTrafficFile;
|
||||
private File newTrafficFile;
|
||||
|
||||
private int totalChanges = 0;
|
||||
private int supressedChanges = 0;
|
||||
|
||||
private boolean doNotAdd = false;
|
||||
private boolean debug = false;
|
||||
|
||||
public OsmTrafficMap(BExpressionContextWay expctxWay) {
|
||||
this.expctxWay = expctxWay;
|
||||
debug = Boolean.getBoolean("debugTrafficMap");
|
||||
}
|
||||
|
||||
public static class OsmTrafficElement {
|
||||
public long node2;
|
||||
public int traffic;
|
||||
public OsmTrafficElement next;
|
||||
}
|
||||
|
||||
private CompactLongMap<OsmTrafficElement> map = new CompactLongMap<>();
|
||||
|
||||
public void loadAll(File file, int minLon, int minLat, int maxLon, int maxLat, boolean includeMotorways) throws Exception {
|
||||
load(file, minLon, minLat, maxLon, maxLat, includeMotorways);
|
||||
|
||||
// check for old traffic data
|
||||
oldTrafficFile = new File(file.getParentFile(), file.getName() + "_old");
|
||||
if (oldTrafficFile.exists()) {
|
||||
oldTrafficClasses = new OsmTrafficMap(null);
|
||||
oldTrafficClasses.doNotAdd = true;
|
||||
oldTrafficClasses.load(oldTrafficFile, minLon, minLat, maxLon, maxLat, false);
|
||||
}
|
||||
|
||||
// check for old traffic data
|
||||
newTrafficFile = new File(file.getParentFile(), file.getName() + "_new");
|
||||
newTrafficDos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(newTrafficFile)));
|
||||
}
|
||||
|
||||
public void finish() throws Exception {
|
||||
if (newTrafficDos != null) {
|
||||
newTrafficDos.close();
|
||||
newTrafficDos = null;
|
||||
oldTrafficFile.delete();
|
||||
newTrafficFile.renameTo(oldTrafficFile);
|
||||
System.out.println("TrafficMap: changes total=" + totalChanges + " supressed=" + supressedChanges);
|
||||
}
|
||||
}
|
||||
|
||||
public void load(File file, int minLon, int minLat, int maxLon, int maxLat, boolean includeMotorways) throws Exception {
|
||||
this.minLon = minLon;
|
||||
this.minLat = minLat;
|
||||
this.maxLon = maxLon;
|
||||
this.maxLat = maxLat;
|
||||
|
||||
int trafficElements = 0;
|
||||
DataInputStream is = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
|
||||
try {
|
||||
for (; ; ) {
|
||||
long n1 = is.readLong();
|
||||
long n2 = is.readLong();
|
||||
int traffic = is.readInt();
|
||||
if (traffic == -1 && !includeMotorways) {
|
||||
continue;
|
||||
}
|
||||
if (isInsideBounds(n1) || isInsideBounds(n2)) {
|
||||
if (addElement(n1, n2, traffic)) {
|
||||
trafficElements++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (EOFException eof) {
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
|
||||
map = new FrozenLongMap<>(map);
|
||||
System.out.println("read traffic-elements: " + trafficElements);
|
||||
}
|
||||
|
||||
|
||||
public boolean addElement(long n1, long n2, int traffic) {
|
||||
OsmTrafficElement e = getElement(n1, n2);
|
||||
if (e == null) {
|
||||
e = new OsmTrafficElement();
|
||||
e.node2 = n2;
|
||||
e.traffic = traffic;
|
||||
|
||||
OsmTrafficElement e0 = map.get(n1);
|
||||
if (e0 != null) {
|
||||
while (e0.next != null) {
|
||||
e0 = e0.next;
|
||||
}
|
||||
e0.next = e;
|
||||
} else {
|
||||
map.fastPut(n1, e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (doNotAdd) {
|
||||
e.traffic = Math.max(e.traffic, traffic);
|
||||
} else {
|
||||
e.traffic = e.traffic == -1 || traffic == -1 ? -1 : e.traffic + traffic;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isInsideBounds(long id) {
|
||||
int ilon = (int) (id >> 32);
|
||||
int ilat = (int) (id & 0xffffffff);
|
||||
|
||||
return ilon >= minLon && ilon < maxLon && ilat >= minLat && ilat < maxLat;
|
||||
}
|
||||
|
||||
public int getTrafficClass(long n1, long n2) {
|
||||
// used for the old data, where we stpre traffic-classes, not volumes
|
||||
OsmTrafficElement e = getElement(n1, n2);
|
||||
return e == null ? 0 : e.traffic;
|
||||
}
|
||||
|
||||
public int getTrafficClassForTraffic(int traffic) {
|
||||
if (traffic < 0) return -1;
|
||||
if (traffic < 40000) return 0;
|
||||
if (traffic < 80000) return 2;
|
||||
if (traffic < 160000) return 3;
|
||||
if (traffic < 320000) return 4;
|
||||
if (traffic < 640000) return 5;
|
||||
if (traffic < 1280000) return 6;
|
||||
return 7;
|
||||
}
|
||||
|
||||
private int getTraffic(long n1, long n2) {
|
||||
OsmTrafficElement e1 = getElement(n1, n2);
|
||||
int traffic1 = e1 == null ? 0 : e1.traffic;
|
||||
OsmTrafficElement e2 = getElement(n2, n1);
|
||||
int traffic2 = e2 == null ? 0 : e2.traffic;
|
||||
return traffic1 == -1 || traffic2 == -1 ? -1 : traffic1 > traffic2 ? traffic1 : traffic2;
|
||||
}
|
||||
|
||||
public void freeze() {
|
||||
}
|
||||
|
||||
private OsmTrafficElement getElement(long n1, long n2) {
|
||||
OsmTrafficElement e = map.get(n1);
|
||||
while (e != null) {
|
||||
if (e.node2 == n2) {
|
||||
return e;
|
||||
}
|
||||
e = e.next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public OsmTrafficElement getElement(long n) {
|
||||
return map.get(n);
|
||||
}
|
||||
|
||||
public byte[] addTrafficClass(List<OsmNodeP> linkNodes, byte[] description) throws IOException {
|
||||
double distance = 0.;
|
||||
double sum = 0.;
|
||||
|
||||
for (int i = 0; i < linkNodes.size() - 1; i++) {
|
||||
OsmNodeP n1 = linkNodes.get(i);
|
||||
OsmNodeP n2 = linkNodes.get(i + 1);
|
||||
int traffic = getTraffic(n1.getIdFromPos(), n2.getIdFromPos());
|
||||
double dist = CheapRuler.distance(n1.ilon, n1.ilat, n2.ilon, n2.ilat);
|
||||
distance += dist;
|
||||
sum += dist * traffic;
|
||||
}
|
||||
|
||||
if (distance == 0.) {
|
||||
return description;
|
||||
}
|
||||
int traffic = (int) (sum / distance + 0.5);
|
||||
|
||||
long id0 = linkNodes.get(0).getIdFromPos();
|
||||
long id1 = linkNodes.get(linkNodes.size() - 1).getIdFromPos();
|
||||
|
||||
int trafficClass = getTrafficClassForTraffic(traffic);
|
||||
|
||||
// delta suppression: keep old traffic classes within some buffer range
|
||||
if (oldTrafficClasses != null) {
|
||||
int oldTrafficClass = oldTrafficClasses.getTrafficClass(id0, id1);
|
||||
if (oldTrafficClass != trafficClass) {
|
||||
totalChanges++;
|
||||
boolean supressChange =
|
||||
oldTrafficClass == getTrafficClassForTraffic((int) (traffic * 1.3))
|
||||
|| oldTrafficClass == getTrafficClassForTraffic((int) (traffic * 0.77));
|
||||
|
||||
if (debug) {
|
||||
System.out.println("traffic class change " + oldTrafficClass + "->" + trafficClass + " supress=" + supressChange);
|
||||
}
|
||||
if (supressChange) {
|
||||
trafficClass = oldTrafficClass;
|
||||
supressedChanges++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trafficClass > 0) {
|
||||
newTrafficDos.writeLong(id0);
|
||||
newTrafficDos.writeLong(id1);
|
||||
newTrafficDos.writeInt(trafficClass);
|
||||
|
||||
expctxWay.decode(description);
|
||||
expctxWay.addLookupValue("estimated_traffic_class", trafficClass + 1);
|
||||
return expctxWay.encode();
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -7,7 +7,6 @@ import java.io.File;
|
|||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import btools.util.CompactLongSet;
|
||||
|
|
@ -23,16 +22,21 @@ import btools.util.FrozenLongSet;
|
|||
* @author ab
|
||||
*/
|
||||
public class PosUnifier extends MapCreatorBase {
|
||||
|
||||
public static final boolean UseRasterRd5FileName = false;
|
||||
|
||||
private DiffCoderDataOutputStream nodesOutStream;
|
||||
private DiffCoderDataOutputStream borderNodesOut;
|
||||
private File nodeTilesOut;
|
||||
private File outNodeFile;
|
||||
private CompactLongSet[] positionSets;
|
||||
|
||||
private Map<String, SrtmRaster> srtmmap;
|
||||
private Map<String, ElevationRaster> srtmmap;
|
||||
private int lastSrtmLonIdx;
|
||||
private int lastSrtmLatIdx;
|
||||
private SrtmRaster lastSrtmRaster;
|
||||
private ElevationRaster lastSrtmRaster;
|
||||
private String srtmdir;
|
||||
private String srtmfallbackdir;
|
||||
|
||||
private CompactLongSet borderNids;
|
||||
|
||||
|
|
@ -46,25 +50,40 @@ public class PosUnifier extends MapCreatorBase {
|
|||
double lat = Double.parseDouble(args[2]);
|
||||
|
||||
NodeData n = new NodeData(1, lon, lat);
|
||||
SrtmRaster srtm = posu.hgtForNode(n.ilon, n.ilat);
|
||||
short selev = Short.MIN_VALUE;
|
||||
ElevationRaster srtm = null;
|
||||
/*
|
||||
// check hgt direct
|
||||
srtm = posu.hgtForNode(n.ilon, n.ilat);
|
||||
if (srtm != null) {
|
||||
selev = srtm.getElevation(n.ilon, n.ilat);
|
||||
} else {
|
||||
System.out.println("hgtForNode no data");
|
||||
}
|
||||
posu.resetElevationRaster();
|
||||
System.out.println("-----> selv for hgt " + lat + ", " + lon + " = " + selev + " = " + (selev / 4.));
|
||||
srtm = null;
|
||||
selev = Short.MIN_VALUE;
|
||||
*/
|
||||
if (srtm == null) {
|
||||
srtm = posu.srtmForNode(n.ilon, n.ilat);
|
||||
}
|
||||
if (srtm != null) selev = srtm.getElevation(n.ilon, n.ilat);
|
||||
posu.resetSrtm();
|
||||
System.out.println("-----> selv for " + lat + ", " + lon + " = " + selev + " = " + (selev / 4.));
|
||||
posu.resetElevationRaster();
|
||||
System.out.println("-----> selv for bef " + lat + ", " + lon + " = " + selev + " = " + (selev / 4.));
|
||||
return;
|
||||
} else if (args.length != 5) {
|
||||
System.out.println("usage: java PosUnifier <node-tiles-in> <node-tiles-out> <bordernids-in> <bordernodes-out> <srtm-data-dir>");
|
||||
} else if (args.length != 5 && args.length != 6) {
|
||||
System.out.println("usage: java PosUnifier <node-tiles-in> <node-tiles-out> <bordernids-in> <bordernodes-out> <srtm-data-dir> [srtm-fallback-data-dir]");
|
||||
System.out.println("or java PosUnifier <srtm-data-dir> <lon> <lat>");
|
||||
return;
|
||||
}
|
||||
new PosUnifier().process(new File(args[0]), new File(args[1]), new File(args[2]), new File(args[3]), args[4]);
|
||||
new PosUnifier().process(new File(args[0]), new File(args[1]), new File(args[2]), new File(args[3]), args[4], (args.length == 6 ? args[5] : null));
|
||||
}
|
||||
|
||||
public void process(File nodeTilesIn, File nodeTilesOut, File bordernidsinfile, File bordernodesoutfile, String srtmdir) throws Exception {
|
||||
public void process(File nodeTilesIn, File nodeTilesOut, File bordernidsinfile, File bordernodesoutfile, String srtmdir, String srtmfallbackdir) throws Exception {
|
||||
this.nodeTilesOut = nodeTilesOut;
|
||||
this.srtmdir = srtmdir;
|
||||
this.srtmfallbackdir = srtmfallbackdir;
|
||||
|
||||
// read border nids set
|
||||
DataInputStream dis = createInStream(bordernidsinfile);
|
||||
|
|
@ -88,9 +107,9 @@ public class PosUnifier extends MapCreatorBase {
|
|||
|
||||
@Override
|
||||
public void nodeFileStart(File nodefile) throws Exception {
|
||||
resetSrtm();
|
||||
|
||||
nodesOutStream = createOutStream(fileFromTemplate(nodefile, nodeTilesOut, "u5d"));
|
||||
resetElevationRaster();
|
||||
outNodeFile = fileFromTemplate(nodefile, nodeTilesOut, "u5d");
|
||||
nodesOutStream = createOutStream(outNodeFile);
|
||||
|
||||
positionSets = new CompactLongSet[2500];
|
||||
}
|
||||
|
|
@ -106,7 +125,7 @@ public class PosUnifier extends MapCreatorBase {
|
|||
srtm = srtmForNode(n.ilon, n.ilat);
|
||||
} */
|
||||
|
||||
SrtmRaster srtm = srtmForNode(n.ilon, n.ilat);
|
||||
ElevationRaster srtm = srtmForNode(n.ilon, n.ilat);
|
||||
|
||||
if (srtm != null) n.selev = srtm.getElevation(n.ilon, n.ilat);
|
||||
findUniquePos(n);
|
||||
|
|
@ -120,7 +139,13 @@ public class PosUnifier extends MapCreatorBase {
|
|||
@Override
|
||||
public void nodeFileEnd(File nodeFile) throws Exception {
|
||||
nodesOutStream.close();
|
||||
resetSrtm();
|
||||
if (outNodeFile != null) {
|
||||
if (lastSrtmRaster != null) {
|
||||
String newName = outNodeFile.getAbsolutePath() + (lastSrtmRaster.nrows > 6001 ? "_1": "_3");
|
||||
outNodeFile.renameTo(new File(newName));
|
||||
}
|
||||
}
|
||||
resetElevationRaster();
|
||||
}
|
||||
|
||||
private boolean checkAdd(int lon, int lat) {
|
||||
|
|
@ -168,7 +193,7 @@ public class PosUnifier extends MapCreatorBase {
|
|||
* get the srtm data set for a position srtm coords are
|
||||
* srtm_<srtmLon>_<srtmLat> where srtmLon = 180 + lon, srtmLat = 60 - lat
|
||||
*/
|
||||
private SrtmRaster srtmForNode(int ilon, int ilat) throws Exception {
|
||||
private ElevationRaster srtmForNode(int ilon, int ilat) throws Exception {
|
||||
int srtmLonIdx = (ilon + 5000000) / 5000000;
|
||||
int srtmLatIdx = (654999999 - ilat) / 5000000 - 100; // ugly negative rounding...
|
||||
|
||||
|
|
@ -178,35 +203,42 @@ public class PosUnifier extends MapCreatorBase {
|
|||
lastSrtmLonIdx = srtmLonIdx;
|
||||
lastSrtmLatIdx = srtmLatIdx;
|
||||
|
||||
String slonidx = "0" + srtmLonIdx;
|
||||
String slatidx = "0" + srtmLatIdx;
|
||||
String filename = "srtm_" + slonidx.substring(slonidx.length() - 2) + "_" + slatidx.substring(slatidx.length() - 2);
|
||||
String filename;
|
||||
if (UseRasterRd5FileName) {
|
||||
filename = genFilenameRd5(ilon, ilat);
|
||||
} else {
|
||||
filename = genFilenameXY(srtmLonIdx, srtmLatIdx);
|
||||
}
|
||||
|
||||
lastSrtmRaster = srtmmap.get(filename);
|
||||
if (lastSrtmRaster == null && !srtmmap.containsKey(filename)) {
|
||||
File f = new File(new File(srtmdir), filename + ".bef");
|
||||
if (f.exists()) {
|
||||
System.out.println("*** reading: " + f);
|
||||
try {
|
||||
InputStream isc = new BufferedInputStream(new FileInputStream(f));
|
||||
lastSrtmRaster = new RasterCoder().decodeRaster(isc);
|
||||
lastSrtmRaster = new ElevationRasterCoder().decodeRaster(isc);
|
||||
isc.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println("**** ERROR reading " + f + " ****");
|
||||
}
|
||||
System.out.println("*** reading: " + f + " " + lastSrtmRaster.ncols);
|
||||
srtmmap.put(filename, lastSrtmRaster);
|
||||
return lastSrtmRaster;
|
||||
}
|
||||
|
||||
f = new File(new File(srtmdir), filename + ".zip");
|
||||
// System.out.println("reading: " + f + " ilon=" + ilon + " ilat=" + ilat);
|
||||
if (f.exists()) {
|
||||
try {
|
||||
lastSrtmRaster = new SrtmData(f).getRaster();
|
||||
if (srtmfallbackdir != null) {
|
||||
f = new File(new File(srtmfallbackdir), filename + ".bef");
|
||||
if (f.exists()) {
|
||||
try {
|
||||
InputStream isc = new BufferedInputStream(new FileInputStream(f));
|
||||
//lastSrtmRaster = new StatRasterCoder().decodeRaster(isc);
|
||||
lastSrtmRaster = new ElevationRasterCoder().decodeRaster(isc);
|
||||
isc.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println("**** ERROR reading " + f + " ****");
|
||||
}
|
||||
System.out.println("*** reading: " + f + " " + lastSrtmRaster.cellsize);
|
||||
srtmmap.put(filename, lastSrtmRaster);
|
||||
return lastSrtmRaster;
|
||||
} catch (Exception e) {
|
||||
System.out.println("**** ERROR reading " + f + " ****");
|
||||
}
|
||||
}
|
||||
srtmmap.put(filename, lastSrtmRaster);
|
||||
|
|
@ -214,23 +246,41 @@ public class PosUnifier extends MapCreatorBase {
|
|||
return lastSrtmRaster;
|
||||
}
|
||||
|
||||
private SrtmRaster hgtForNode(int ilon, int ilat) throws Exception {
|
||||
static String genFilenameXY(int srtmLonIdx, int srtmLatIdx) {
|
||||
String slonidx = "0" + srtmLonIdx;
|
||||
String slatidx = "0" + srtmLatIdx;
|
||||
return "srtm_" + slonidx.substring(slonidx.length() - 2) + "_" + slatidx.substring(slatidx.length() - 2);
|
||||
}
|
||||
|
||||
static String genFilenameRd5(int ilon, int ilat) {
|
||||
int lonDegree = ilon / 1000000;
|
||||
int latDegree = ilat / 1000000;
|
||||
int lonMod5 = lonDegree % 5;
|
||||
int latMod5 = latDegree % 5;
|
||||
lonDegree = lonDegree - 180 - lonMod5;
|
||||
latDegree = latDegree - 90 - latMod5;
|
||||
return String.format("srtm_%s_%s", lonDegree < 0 ? "W" + (-lonDegree) : "E" + lonDegree,
|
||||
latDegree < 0 ? "S" + (-latDegree) : "N" + latDegree);
|
||||
}
|
||||
|
||||
|
||||
private ElevationRaster hgtForNode(int ilon, int ilat) throws Exception {
|
||||
double lon = (ilon - 180000000) / 1000000.;
|
||||
double lat = (ilat - 90000000) / 1000000.;
|
||||
|
||||
String filename = buildHgtFilename(lat, lon);
|
||||
// don't block lastSrtmRaster
|
||||
SrtmRaster srtm = srtmmap.get(filename);
|
||||
ElevationRaster srtm = srtmmap.get(filename);
|
||||
if (srtm == null) {
|
||||
File f = new File(new File(srtmdir), filename + ".hgt");
|
||||
File f = new File(new File(srtmdir), filename + ".zip");
|
||||
if (f.exists()) {
|
||||
srtm = new ConvertLidarTile().getRaster(f, lon, lat);
|
||||
srtm = new ElevationRasterTileConverter().getRaster(f, lon, lat);
|
||||
srtmmap.put(filename, srtm);
|
||||
return srtm;
|
||||
}
|
||||
f = new File(new File(srtmdir), filename + ".zip");
|
||||
f = new File(new File(srtmdir), filename + ".hgt");
|
||||
if (f.exists()) {
|
||||
srtm = new ConvertLidarTile().getRaster(f, lon, lat);
|
||||
srtm = new ElevationRasterTileConverter().getRaster(f, lon, lat);
|
||||
srtmmap.put(filename, srtm);
|
||||
return srtm;
|
||||
}
|
||||
|
|
@ -238,6 +288,7 @@ public class PosUnifier extends MapCreatorBase {
|
|||
return srtm;
|
||||
}
|
||||
|
||||
|
||||
private String buildHgtFilename(double llat, double llon) {
|
||||
int lat = (int) llat;
|
||||
int lon = (int) llon;
|
||||
|
|
@ -253,10 +304,10 @@ public class PosUnifier extends MapCreatorBase {
|
|||
lon = -lon + 1;
|
||||
}
|
||||
|
||||
return String.format(Locale.US, "%s%02d%s%03d", latPref, lat, lonPref, lon);
|
||||
return String.format("%s%02d%s%03d", latPref, lat, lonPref, lon);
|
||||
}
|
||||
|
||||
private void resetSrtm() {
|
||||
private void resetElevationRaster() {
|
||||
srtmmap = new HashMap<>();
|
||||
lastSrtmLonIdx = -1;
|
||||
lastSrtmLatIdx = -1;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import java.io.DataInputStream;
|
|||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* WayCutter does 2 step in map-processing:
|
||||
|
|
@ -25,7 +26,7 @@ public class RelationStatistics extends MapCreatorBase {
|
|||
}
|
||||
|
||||
public void process(File relationFileIn) throws Exception {
|
||||
HashMap<String, long[]> relstats = new HashMap<>();
|
||||
Map<String, long[]> relstats = new HashMap<>();
|
||||
|
||||
DataInputStream dis = createInStream(relationFileIn);
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -1,166 +0,0 @@
|
|||
package btools.mapcreator;
|
||||
|
||||
/**
|
||||
* This is a wrapper for a 5*5 degree srtm file in ascii/zip-format
|
||||
* <p>
|
||||
* - filter out unused nodes according to the way file
|
||||
* - enhance with SRTM elevation data
|
||||
* - split further in smaller (5*5 degree) tiles
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
public class SrtmData {
|
||||
private SrtmRaster raster;
|
||||
|
||||
public SrtmData(File file) throws Exception {
|
||||
raster = new SrtmRaster();
|
||||
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(file)));
|
||||
try {
|
||||
for (; ; ) {
|
||||
ZipEntry ze = zis.getNextEntry();
|
||||
if (ze.getName().endsWith(".asc")) {
|
||||
readFromStream(zis);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
zis.close();
|
||||
}
|
||||
}
|
||||
|
||||
public SrtmRaster getRaster() {
|
||||
return raster;
|
||||
}
|
||||
|
||||
private String secondToken(String s) {
|
||||
StringTokenizer tk = new StringTokenizer(s, " ");
|
||||
tk.nextToken();
|
||||
return tk.nextToken();
|
||||
}
|
||||
|
||||
public void readFromStream(InputStream is) throws Exception {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(is));
|
||||
int linenr = 0;
|
||||
for (; ; ) {
|
||||
linenr++;
|
||||
if (linenr <= 6) {
|
||||
String line = br.readLine();
|
||||
if (linenr == 1)
|
||||
raster.ncols = Integer.parseInt(secondToken(line));
|
||||
else if (linenr == 2)
|
||||
raster.nrows = Integer.parseInt(secondToken(line));
|
||||
else if (linenr == 3)
|
||||
raster.xllcorner = Double.parseDouble(secondToken(line));
|
||||
else if (linenr == 4)
|
||||
raster.yllcorner = Double.parseDouble(secondToken(line));
|
||||
else if (linenr == 5)
|
||||
raster.cellsize = Double.parseDouble(secondToken(line));
|
||||
else if (linenr == 6) {
|
||||
// nodata ignored here ( < -250 assumed nodata... )
|
||||
// raster.noDataValue = Short.parseShort( secondToken( line ) );
|
||||
raster.eval_array = new short[raster.ncols * raster.nrows];
|
||||
}
|
||||
} else {
|
||||
int row = 0;
|
||||
int col = 0;
|
||||
int n = 0;
|
||||
boolean negative = false;
|
||||
for (; ; ) {
|
||||
int c = br.read();
|
||||
if (c < 0)
|
||||
break;
|
||||
if (c == ' ') {
|
||||
if (negative)
|
||||
n = -n;
|
||||
short val = n < -250 ? Short.MIN_VALUE : (short) (n);
|
||||
|
||||
raster.eval_array[row * raster.ncols + col] = val;
|
||||
if (++col == raster.ncols) {
|
||||
col = 0;
|
||||
++row;
|
||||
}
|
||||
n = 0;
|
||||
negative = false;
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
n = 10 * n + (c - '0');
|
||||
} else if (c == '-') {
|
||||
negative = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
br.close();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String fromDir = args[0];
|
||||
String toDir = args[1];
|
||||
|
||||
File[] files = new File(fromDir).listFiles();
|
||||
for (File f : files) {
|
||||
if (!f.getName().endsWith(".zip")) {
|
||||
continue;
|
||||
}
|
||||
System.out.println("*** reading: " + f);
|
||||
long t0 = System.currentTimeMillis();
|
||||
SrtmRaster raster = new SrtmData(f).getRaster();
|
||||
long t1 = System.currentTimeMillis();
|
||||
String name = f.getName();
|
||||
|
||||
long zipTime = t1 - t0;
|
||||
|
||||
File fbef = new File(new File(toDir), name.substring(0, name.length() - 3) + "bef");
|
||||
System.out.println("recoding: " + f + " to " + fbef);
|
||||
OutputStream osbef = new BufferedOutputStream(new FileOutputStream(fbef));
|
||||
new RasterCoder().encodeRaster(raster, osbef);
|
||||
osbef.close();
|
||||
|
||||
System.out.println("*** re-reading: " + fbef);
|
||||
|
||||
long t2 = System.currentTimeMillis();
|
||||
InputStream isc = new BufferedInputStream(new FileInputStream(fbef));
|
||||
SrtmRaster raster2 = new RasterCoder().decodeRaster(isc);
|
||||
isc.close();
|
||||
long t3 = System.currentTimeMillis();
|
||||
|
||||
long befTime = t3 - t2;
|
||||
|
||||
System.out.println("*** zip-time: " + zipTime + "*** bef-time: " + befTime);
|
||||
|
||||
String s1 = raster.toString();
|
||||
String s2 = raster2.toString();
|
||||
|
||||
if (!s1.equals(s2)) {
|
||||
throw new IllegalArgumentException("missmatch: " + s1 + "<--->" + s2);
|
||||
}
|
||||
|
||||
int cols = raster.ncols;
|
||||
int rows = raster.nrows;
|
||||
for (int c = 0; c < cols; c++) {
|
||||
for (int r = 0; r < rows; r++) {
|
||||
int idx = r * cols + c;
|
||||
|
||||
if (raster.eval_array[idx] != raster2.eval_array[idx]) {
|
||||
throw new IllegalArgumentException("missmatch: at " + c + "," + r + ": " + raster.eval_array[idx] + "<--->" + raster2.eval_array[idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import java.io.File;
|
|||
import java.io.FileInputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import btools.codec.DataBuffers;
|
||||
|
|
@ -35,7 +36,6 @@ import btools.util.LazyArrayOfLists;
|
|||
public class WayLinker extends MapCreatorBase implements Runnable {
|
||||
private File nodeTilesIn;
|
||||
private File wayTilesIn;
|
||||
private File trafficTilesIn;
|
||||
private File dataTilesOut;
|
||||
private File borderFileIn;
|
||||
|
||||
|
|
@ -44,13 +44,13 @@ public class WayLinker extends MapCreatorBase implements Runnable {
|
|||
private boolean readingBorder;
|
||||
|
||||
private CompactLongMap<OsmNodeP> nodesMap;
|
||||
private OsmTrafficMap trafficMap;
|
||||
private List<OsmNodeP> nodesList;
|
||||
private CompactLongSet borderSet;
|
||||
private short lookupVersion;
|
||||
private short lookupMinorVersion;
|
||||
|
||||
private long creationTimeStamp;
|
||||
private byte elevationType;
|
||||
|
||||
private BExpressionContextWay expctxWay;
|
||||
|
||||
|
|
@ -153,7 +153,6 @@ public class WayLinker extends MapCreatorBase implements Runnable {
|
|||
String dataTilesSuffix) throws Exception {
|
||||
this.nodeTilesIn = nodeTilesIn;
|
||||
this.wayTilesIn = wayTilesIn;
|
||||
this.trafficTilesIn = new File("../traffic");
|
||||
this.dataTilesOut = dataTilesOut;
|
||||
this.borderFileIn = borderFileIn;
|
||||
this.dataTilesSuffix = dataTilesSuffix;
|
||||
|
|
@ -214,10 +213,15 @@ public class WayLinker extends MapCreatorBase implements Runnable {
|
|||
}
|
||||
|
||||
|
||||
File trafficFile = fileFromTemplate(wayfile, trafficTilesIn, "trf");
|
||||
|
||||
// process corresponding node-file, if any
|
||||
File nodeFile = fileFromTemplate(wayfile, nodeTilesIn, "u5d");
|
||||
elevationType = 3;
|
||||
File nodeFile = fileFromTemplate(wayfile, nodeTilesIn, "u5d_1");
|
||||
if (nodeFile.exists()) {
|
||||
elevationType = 1;
|
||||
} else {
|
||||
nodeFile = fileFromTemplate(wayfile, nodeTilesIn, "u5d_3");
|
||||
if (!nodeFile.exists()) nodeFile = fileFromTemplate(wayfile, nodeTilesIn, "u5d");
|
||||
}
|
||||
if (nodeFile.exists()) {
|
||||
reset();
|
||||
|
||||
|
|
@ -265,11 +269,6 @@ public class WayLinker extends MapCreatorBase implements Runnable {
|
|||
nodesList = nodesMapFrozen.getValueList();
|
||||
}
|
||||
|
||||
// read a traffic-file, if any
|
||||
if (trafficFile.exists()) {
|
||||
trafficMap = new OsmTrafficMap(expctxWay);
|
||||
trafficMap.loadAll(trafficFile, minLon, minLat, minLon + 5000000, minLat + 5000000, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -473,7 +472,7 @@ public class WayLinker extends MapCreatorBase implements Runnable {
|
|||
MicroCache mc = new MicroCache2(size, abBuf2, lonIdxDiv, latIdxDiv, divisor);
|
||||
|
||||
// sort via treemap
|
||||
TreeMap<Integer, OsmNodeP> sortedList = new TreeMap<>();
|
||||
Map<Integer, OsmNodeP> sortedList = new TreeMap<>();
|
||||
for (OsmNodeP n : subList) {
|
||||
long longId = n.getIdFromPos();
|
||||
int shrinkid = mc.shrinkId(longId);
|
||||
|
|
@ -484,7 +483,7 @@ public class WayLinker extends MapCreatorBase implements Runnable {
|
|||
}
|
||||
|
||||
for (OsmNodeP n : sortedList.values()) {
|
||||
n.writeNodeData(mc, trafficMap);
|
||||
n.writeNodeData(mc);
|
||||
}
|
||||
if (mc.getSize() > 0) {
|
||||
byte[] subBytes;
|
||||
|
|
@ -539,6 +538,7 @@ public class WayLinker extends MapCreatorBase implements Runnable {
|
|||
for (int i55 = 0; i55 < 25; i55++) {
|
||||
os.writeInt(fileHeaderCrcs[i55]);
|
||||
}
|
||||
os.writeByte(elevationType);
|
||||
|
||||
os.close();
|
||||
|
||||
|
|
@ -547,10 +547,6 @@ public class WayLinker extends MapCreatorBase implements Runnable {
|
|||
ra.write(abFileIndex, 0, abFileIndex.length);
|
||||
ra.close();
|
||||
}
|
||||
if (trafficMap != null) {
|
||||
trafficMap.finish();
|
||||
trafficMap = null;
|
||||
}
|
||||
System.out.println("**** codec stats: *******\n" + StatCoderContext.getBitReport());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ public class MapcreatorTest {
|
|||
File unodes55 = new File(tmpdir, "unodes55");
|
||||
File bordernodes = new File(tmpdir, "bordernodes.dat");
|
||||
unodes55.mkdir();
|
||||
new PosUnifier().process(nodes55, unodes55, borderFile, bordernodes, workingDir.getAbsolutePath());
|
||||
new PosUnifier().process(nodes55, unodes55, borderFile, bordernodes, workingDir.getAbsolutePath(), null);
|
||||
|
||||
// run WayLinker
|
||||
File segments = new File(tmpdir, "segments");
|
||||
|
|
|
|||
1
brouter-mapaccess/.gitignore
vendored
1
brouter-mapaccess/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
/build/
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
plugins {
|
||||
id 'java-library'
|
||||
id 'brouter.library-conventions'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':brouter-util')
|
||||
implementation project(':brouter-codec')
|
||||
implementation project(':brouter-expressions')
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
}
|
||||
|
||||
// MapcreatorTest generates segments which are used in tests
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<manifest package="btools.mapaccess" />
|
||||
|
|
@ -385,4 +385,20 @@ public final class NodesCache {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getElevationType(int ilon, int ilat) {
|
||||
int lonDegree = ilon / 1000000;
|
||||
int latDegree = ilat / 1000000;
|
||||
OsmFile[] fileRow = fileRows[latDegree];
|
||||
int ndegrees = fileRow == null ? 0 : fileRow.length;
|
||||
for (int i = 0; i < ndegrees; i++) {
|
||||
if (fileRow[i].lonDegree == lonDegree) {
|
||||
OsmFile osmf = fileRow[i];
|
||||
if (osmf != null) return osmf.elevationType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ final class OsmFile {
|
|||
|
||||
private int divisor;
|
||||
private int cellsize;
|
||||
private int ncaches;
|
||||
private int indexsize;
|
||||
protected byte elevationType = 3;
|
||||
|
||||
public OsmFile(PhysicalFile rafile, int lonDegree, int latDegree, DataBuffers dataBuffers) throws IOException {
|
||||
this.lonDegree = lonDegree;
|
||||
|
|
@ -43,9 +43,10 @@ final class OsmFile {
|
|||
|
||||
if (rafile != null) {
|
||||
divisor = rafile.divisor;
|
||||
elevationType = rafile.elevationType;
|
||||
|
||||
cellsize = 1000000 / divisor;
|
||||
ncaches = divisor * divisor;
|
||||
int ncaches = divisor * divisor;
|
||||
indexsize = ncaches * 4;
|
||||
|
||||
byte[] iobuffer = dataBuffers.iobuffer;
|
||||
|
|
@ -141,7 +142,7 @@ final class OsmFile {
|
|||
new DirectWeaver(bc, dataBuffers, lonIdx, latIdx, divisor, wayValidator, waypointMatcher, hollowNodes);
|
||||
return MicroCache.emptyNonVirgin;
|
||||
} finally {
|
||||
// crc check only if the buffer has not been fully read
|
||||
// crc check only if the buffer has not been fully read
|
||||
int readBytes = (bc.getReadingBitPosition() + 7) >> 3;
|
||||
if (readBytes != asize - 4) {
|
||||
int crcData = Crc32.crc(ab, 0, asize - 4);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public class OsmNodePairSet {
|
|||
n2a = new long[maxTempNodes];
|
||||
}
|
||||
|
||||
private static class OsmNodePair {
|
||||
private static final class OsmNodePair {
|
||||
public long node2;
|
||||
public OsmNodePair next;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ final public class PhysicalFile {
|
|||
String fileName;
|
||||
|
||||
public int divisor = 80;
|
||||
public byte elevationType = 3;
|
||||
|
||||
public static void main(String[] args) {
|
||||
MicroCache.debug = true;
|
||||
|
|
@ -69,7 +70,7 @@ final public class PhysicalFile {
|
|||
DataBuffers dataBuffers = new DataBuffers();
|
||||
pf = new PhysicalFile(f, dataBuffers, -1, -1);
|
||||
int div = pf.divisor;
|
||||
for (int lonDegree = 0; lonDegree < 5; lonDegree++) { // does'nt really matter..
|
||||
for (int lonDegree = 0; lonDegree < 5; lonDegree++) { // doesn't really matter..
|
||||
for (int latDegree = 0; latDegree < 5; latDegree++) { // ..where on earth we are
|
||||
OsmFile osmf = new OsmFile(pf, lonDegree, latDegree, dataBuffers);
|
||||
if (osmf.hasData())
|
||||
|
|
@ -113,6 +114,10 @@ final public class PhysicalFile {
|
|||
|
||||
if (len == pos) return; // old format o.k.
|
||||
|
||||
if ((len-pos) > extraLen) {
|
||||
extraLen++;
|
||||
}
|
||||
|
||||
if (len < pos + extraLen) { // > is o.k. for future extensions!
|
||||
throw new IOException("file of size " + len + " too short, should be " + (pos + extraLen));
|
||||
}
|
||||
|
|
@ -134,5 +139,8 @@ final public class PhysicalFile {
|
|||
for (int i = 0; i < 25; i++) {
|
||||
fileHeaderCrcs[i] = dis.readInt();
|
||||
}
|
||||
try {
|
||||
elevationType = dis.readByte();
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1
brouter-routing-app/.gitignore
vendored
1
brouter-routing-app/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
/build/
|
||||
|
|
@ -1,26 +1,30 @@
|
|||
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
|
||||
|
||||
plugins {
|
||||
id 'base'
|
||||
id 'com.android.application'
|
||||
id 'checkstyle'
|
||||
id 'brouter.version-conventions'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 33
|
||||
compileSdk 34
|
||||
|
||||
base {
|
||||
archivesName = "BRouterApp." + project.version
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
namespace 'btools.routingapp'
|
||||
applicationId "btools.routingapp"
|
||||
|
||||
versionCode 48
|
||||
versionCode 54
|
||||
versionName project.version
|
||||
|
||||
resValue('string', 'app_version', defaultConfig.versionName)
|
||||
setProperty("archivesBaseName", "BRouterApp." + defaultConfig.versionName)
|
||||
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 33
|
||||
|
||||
resConfigs "en"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 34
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
|
@ -53,7 +57,7 @@ android {
|
|||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
minifyEnabled true
|
||||
debuggable false
|
||||
if (project.hasProperty("RELEASE_STORE_FILE") && RELEASE_STORE_FILE.length() > 0) {
|
||||
signingConfig signingConfigs.release
|
||||
|
|
@ -76,6 +80,10 @@ android {
|
|||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
buildFeatures {
|
||||
aidl true
|
||||
buildConfig true
|
||||
}
|
||||
|
||||
applicationVariants.all {
|
||||
variant ->
|
||||
|
|
@ -86,23 +94,28 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
|
||||
implementation 'androidx.work:work-runtime:2.8.1'
|
||||
implementation 'com.google.android.material:material:1.8.0'
|
||||
implementation 'androidx.work:work-runtime:2.9.0'
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
|
||||
implementation project(':brouter-mapaccess')
|
||||
implementation project(':brouter-core')
|
||||
implementation project(':brouter-expressions')
|
||||
implementation project(':brouter-util')
|
||||
implementation 'androidx.preference:preference:1.2.0'
|
||||
implementation 'androidx.preference:preference:1.2.1'
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
||||
androidTestImplementation 'androidx.work:work-testing:2.8.1'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.2.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
|
||||
androidTestImplementation 'androidx.work:work-testing:2.9.0'
|
||||
}
|
||||
|
||||
gradle.projectsEvaluated {
|
||||
|
|
@ -150,3 +163,8 @@ task generateReadmesZip(type: Zip) {
|
|||
}
|
||||
destinationDirectory = layout.buildDirectory.dir("assets")
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.compilerArgs += ['-Xlint:unchecked']
|
||||
options.compilerArgs += ['-Xlint:deprecation']
|
||||
}
|
||||
|
|
|
|||
8
brouter-routing-app/proguard-rules.pro
vendored
8
brouter-routing-app/proguard-rules.pro
vendored
|
|
@ -19,3 +19,11 @@
|
|||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
-keep class btools.codec.** { *; }
|
||||
-keep class btools.router.** { *; }
|
||||
-keep class btools.expressions.** { *; }
|
||||
-keep class btools.mapaccess.** { *; }
|
||||
-keep class btools.server.** { *; }
|
||||
-keep class btools.util.** { *; }
|
||||
-keep class btools.routingapp.** { *; }
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
package btools.routingapp;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package btools.routingapp;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
|
||||
<application
|
||||
|
|
@ -92,6 +93,7 @@
|
|||
android:name=".RoutingParameterDialog"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden"
|
||||
/>
|
||||
|
||||
<service
|
||||
|
|
@ -99,6 +101,10 @@
|
|||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:process=":brouter_service" />
|
||||
<service
|
||||
android:name="androidx.work.impl.foreground.SystemForegroundService"
|
||||
android:foregroundServiceType="dataSync"
|
||||
tools:node="merge" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ interface IBRouterService {
|
|||
// "maxRunningTime"-->String with a number of seconds for the routing timeout, default = 60
|
||||
// "turnInstructionFormat"-->String selecting the format for turn-instructions values: osmand, locus
|
||||
// "trackFormat"-->[kml|gpx|json] default = gpx
|
||||
// "acceptCompressedResult"-->[true] sends a compressed result when output format is gpx
|
||||
// "lats"-->double[] array of latitudes; 2 values at least.
|
||||
// "lons"-->double[] array of longitudes; 2 values at least.
|
||||
// "nogoLats"-->double[] array of nogo latitudes; may be null.
|
||||
|
|
|
|||
|
|
@ -73,13 +73,19 @@ public class BImportActivity extends AppCompatActivity {
|
|||
// URI example ==> dat=content://me.bluemail.mail.attachmentprovider/a2939069-76b5-44e4-8cbd-94485d0fd4ff/cc32b61d-97a6-4871-b67f-945d1d1d43c8/VIEW
|
||||
String filename = null;
|
||||
long filesize = 0L;
|
||||
|
||||
try (Cursor cursor = this.getContentResolver().query(intent.getData(), new String[]{
|
||||
OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE}, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
filename = cursor.getString(cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME));
|
||||
filesize = cursor.getLong(cursor.getColumnIndexOrThrow(OpenableColumns.SIZE));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
resultMessage.append("ERROR: File not accessible\n");
|
||||
displayMessage(resultMessage.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
// is the file extention ".brf" in the file name
|
||||
if (filename == null || isInvalidProfileFilename(filename)) {
|
||||
resultMessage.append("ERROR: File extention must be \".brf\"\n");
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import android.annotation.SuppressLint;
|
|||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
|
|
@ -47,6 +46,8 @@ import btools.router.RoutingHelper;
|
|||
|
||||
public class BInstallerActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = "BInstallerActivity";
|
||||
|
||||
private static final int DIALOG_CONFIRM_DELETE_ID = 1;
|
||||
private static final int DIALOG_CONFIRM_NEXTSTEPS_ID = 2;
|
||||
private static final int DIALOG_CONFIRM_GETDIFFS_ID = 3;
|
||||
|
|
@ -171,7 +172,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);
|
||||
|
|
@ -214,9 +215,10 @@ public class BInstallerActivity extends AppCompatActivity {
|
|||
.build();
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
Toast.makeText(this, "Too much data for download. Please reduce.", Toast.LENGTH_LONG).show();
|
||||
Object data;
|
||||
Toast.makeText(this, R.string.msg_too_much_data, Toast.LENGTH_LONG).show();
|
||||
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -242,10 +244,9 @@ public class BInstallerActivity extends AppCompatActivity {
|
|||
//WorkManager.getInstance(getApplicationContext()).cancelWorkById(downloadWorkRequest.getId());
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
} catch (InterruptedException e) {
|
||||
Log.d("worker", "canceled " + e.getMessage());
|
||||
//e.printStackTrace();
|
||||
Log.d(TAG, "canceled " + e.getMessage());
|
||||
}
|
||||
|
||||
workManager
|
||||
|
|
@ -264,7 +265,7 @@ public class BInstallerActivity extends AppCompatActivity {
|
|||
}
|
||||
|
||||
if (workInfo.getState() == WorkInfo.State.ENQUEUED) {
|
||||
Toast.makeText(this, "Download scheduled. Check internet connection if it doesn't start.", Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, R.string.msg_download_start, Toast.LENGTH_LONG).show();
|
||||
mProgressIndicator.hide();
|
||||
mProgressIndicator.setIndeterminate(true);
|
||||
mProgressIndicator.show();
|
||||
|
|
@ -279,7 +280,7 @@ public class BInstallerActivity extends AppCompatActivity {
|
|||
String segmentName = progress.getString(DownloadWorker.PROGRESS_SEGMENT_NAME);
|
||||
int percent = progress.getInt(DownloadWorker.PROGRESS_SEGMENT_PERCENT, 0);
|
||||
if (percent > 0) {
|
||||
mDownloadSummaryInfo.setText("Downloading .. " + segmentName);
|
||||
mDownloadSummaryInfo.setText(getString(R.string.msg_download_started) + segmentName);
|
||||
}
|
||||
if (percent > 0) {
|
||||
mProgressIndicator.setIndeterminate(false);
|
||||
|
|
@ -295,13 +296,13 @@ public class BInstallerActivity extends AppCompatActivity {
|
|||
String result;
|
||||
switch (workInfo.getState()) {
|
||||
case FAILED:
|
||||
result = "Download failed";
|
||||
result = getString(R.string.msg_download_failed);
|
||||
break;
|
||||
case CANCELLED:
|
||||
result = "Download cancelled";
|
||||
result = getString(R.string.msg_download_cancel);
|
||||
break;
|
||||
case SUCCEEDED:
|
||||
result = "Download succeeded";
|
||||
result = getString(R.string.msg_download_succeed);
|
||||
break;
|
||||
default:
|
||||
result = "";
|
||||
|
|
@ -349,12 +350,12 @@ public class BInstallerActivity extends AppCompatActivity {
|
|||
switch (id) {
|
||||
case DIALOG_CONFIRM_DELETE_ID:
|
||||
builder
|
||||
.setTitle("Confirm Delete")
|
||||
.setMessage("Really delete?").setPositiveButton("Yes", new DialogInterface.OnClickListener() {
|
||||
.setTitle(R.string.title_delete)
|
||||
.setMessage(R.string.summary_delete).setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
deleteSelectedTiles();
|
||||
}
|
||||
}).setNegativeButton("No", new DialogInterface.OnClickListener() {
|
||||
}).setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
}
|
||||
});
|
||||
|
|
@ -362,9 +363,9 @@ public class BInstallerActivity extends AppCompatActivity {
|
|||
|
||||
case DIALOG_CONFIRM_NEXTSTEPS_ID:
|
||||
builder
|
||||
.setTitle("Version Problem")
|
||||
.setMessage("The base version for tiles has changed. What to do?")
|
||||
.setPositiveButton("Continue with current download, delete other old data", new DialogInterface.OnClickListener() {
|
||||
.setTitle(R.string.title_version)
|
||||
.setMessage(R.string.summary_version)
|
||||
.setPositiveButton(R.string.action_version1, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
|
||||
ArrayList<Integer> allTiles = mBInstallerView.getSelectedTiles(MASK_INSTALLED_RD5);
|
||||
|
|
@ -376,11 +377,11 @@ public class BInstallerActivity extends AppCompatActivity {
|
|||
}
|
||||
downloadSelectedTiles();
|
||||
}
|
||||
}).setNegativeButton("Select all for download and start", new DialogInterface.OnClickListener() {
|
||||
}).setNegativeButton(R.string.action_version2, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
downloadInstalledTiles();
|
||||
}
|
||||
}).setNeutralButton("Cancel now, complete on an other day", new DialogInterface.OnClickListener() {
|
||||
}).setNeutralButton(R.string.action_version3, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
File tmplookupFile = new File(mBaseDir, "brouter/profiles2/lookups.dat.tmp");
|
||||
tmplookupFile.delete();
|
||||
|
|
@ -391,17 +392,17 @@ public class BInstallerActivity extends AppCompatActivity {
|
|||
|
||||
case DIALOG_CONFIRM_GETDIFFS_ID:
|
||||
builder
|
||||
.setTitle("Version Differences")
|
||||
.setMessage("The base version for some tiles is different. What to do?")
|
||||
.setPositiveButton("Download all different tiles", new DialogInterface.OnClickListener() {
|
||||
.setTitle(R.string.title_version_diff)
|
||||
.setMessage(R.string.summary_version_diff)
|
||||
.setPositiveButton(R.string.action_version_diff1, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
downloadDiffVersionTiles();
|
||||
}
|
||||
}).setNegativeButton("Drop all different tiles", new DialogInterface.OnClickListener() {
|
||||
}).setNegativeButton(R.string.action_version_diff2, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dropDiffVersionTiles();
|
||||
}
|
||||
}).setNeutralButton("Cancel now, complete on an other day", new DialogInterface.OnClickListener() {
|
||||
}).setNeutralButton(R.string.action_version_diff3, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
finish();
|
||||
}
|
||||
|
|
@ -409,9 +410,9 @@ public class BInstallerActivity extends AppCompatActivity {
|
|||
return builder.create();
|
||||
case DIALOG_NEW_APP_NEEDED_ID:
|
||||
builder
|
||||
.setTitle("App Version")
|
||||
.setMessage("The new data version needs a new app. Please update BRouter first")
|
||||
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
|
||||
.setTitle(R.string.title_version)
|
||||
.setMessage(R.string.summary_new_version)
|
||||
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
finish();
|
||||
}
|
||||
|
|
@ -516,10 +517,10 @@ public class BInstallerActivity extends AppCompatActivity {
|
|||
}
|
||||
return running;
|
||||
} catch (ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
return false;
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ public class BInstallerView extends View {
|
|||
int tidx = gridPos2Tileindex(ix, iy);
|
||||
int tilesize = BInstallerSizes.getRd5Size(tidx);
|
||||
if (tilesize > 0) {
|
||||
canvas.drawRect(fw * ix, fh * (iy + 1), fw * (ix + 1), fh * iy, paintGrid);
|
||||
canvas.drawRect(fw * ix, fh * iy, fw * (ix + 1), fh * (iy + 1), paintGrid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -214,7 +214,7 @@ public class BInstallerView extends View {
|
|||
canvas.drawLine(fw * ix, fh * (iy + 1), fw * (ix + 1), fh * iy, pnt);
|
||||
|
||||
// draw frame
|
||||
canvas.drawRect(fw * ix, fh * (iy + 1), fw * (ix + 1), fh * iy, pnt);
|
||||
canvas.drawRect(fw * ix, fh * iy, fw * (ix + 1), fh * (iy + 1), pnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
private static final int DIALOG_PICKWAYPOINT_ID = 10;
|
||||
private static final int DIALOG_SELECTBASEDIR_ID = 11;
|
||||
private static final int DIALOG_MAINACTION_ID = 12;
|
||||
private static final int DIALOG_OLDDATAHINT_ID = 13;
|
||||
//private static final int DIALOG_OLDDATAHINT_ID = 13;
|
||||
private static final int DIALOG_SHOW_REPEAT_TIMEOUT_HELP_ID = 16;
|
||||
private final Set<Integer> dialogIds = new HashSet<>();
|
||||
private BRouterView mBRouterView;
|
||||
|
|
@ -133,7 +133,7 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
|
||||
switch (id) {
|
||||
case DIALOG_SELECTPROFILE_ID:
|
||||
builder.setTitle("Select a routing profile");
|
||||
builder.setTitle(R.string.action_select_profile);
|
||||
builder.setItems(availableProfiles, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int item) {
|
||||
selectedProfile = availableProfiles[item];
|
||||
|
|
@ -142,9 +142,9 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
});
|
||||
return builder.create();
|
||||
case DIALOG_MAINACTION_ID:
|
||||
builder.setTitle("Select Main Action");
|
||||
builder.setTitle(R.string.main_action);
|
||||
builder.setItems(
|
||||
new String[]{"Download Manager", "BRouter App"},
|
||||
new String[]{getString(R.string.main_action_1), getString(R.string.main_action_2)},
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int item) {
|
||||
if (item == 0)
|
||||
|
|
@ -153,7 +153,7 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
showADialog(DIALOG_SELECTPROFILE_ID);
|
||||
}
|
||||
})
|
||||
.setNegativeButton("Close", new DialogInterface.OnClickListener() {
|
||||
.setNegativeButton(getString(R.string.close), new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
finish();
|
||||
}
|
||||
|
|
@ -161,19 +161,15 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
return builder.create();
|
||||
case DIALOG_SHOW_DM_INFO_ID:
|
||||
builder
|
||||
.setTitle("BRouter Download Manager")
|
||||
.setMessage(
|
||||
"*** Attention: ***\n\n" + "The Download Manager is used to download routing-data "
|
||||
+ "files which can be up to 170MB each. Do not start the Download Manager "
|
||||
+ "on a cellular data connection without a data plan! "
|
||||
+ "Download speed is restricted to 16 MBit/s.")
|
||||
.setPositiveButton("I know", new DialogInterface.OnClickListener() {
|
||||
.setTitle(R.string.title_download)
|
||||
.setMessage(R.string.summary_download)
|
||||
.setPositiveButton(R.string.i_know, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
Intent intent = new Intent(BRouterActivity.this, BInstallerActivity.class);
|
||||
startActivity(intent);
|
||||
showNewDialog(DIALOG_MAINACTION_ID);
|
||||
}
|
||||
}).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
||||
}).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
finish();
|
||||
}
|
||||
|
|
@ -181,18 +177,15 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
return builder.create();
|
||||
case DIALOG_SHOW_REPEAT_TIMEOUT_HELP_ID:
|
||||
builder
|
||||
.setTitle("Successfully prepared a timeout-free calculation")
|
||||
.setMessage(
|
||||
"You successfully repeated a calculation that previously run into a timeout "
|
||||
+ "when started from your map-tool. If you repeat the same request from your "
|
||||
+ "maptool, with the exact same destination point and a close-by starting point, "
|
||||
+ "this request is guaranteed not to time out.")
|
||||
.setNegativeButton("Exit", new DialogInterface.OnClickListener() {
|
||||
.setTitle(R.string.title_timeoutfree)
|
||||
.setMessage(R.string.summary_timeoutfree)
|
||||
.setNegativeButton(R.string.exit, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
return builder.create();
|
||||
/*
|
||||
case DIALOG_OLDDATAHINT_ID:
|
||||
builder
|
||||
.setTitle("Local setup needs reset")
|
||||
|
|
@ -202,12 +195,13 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
+ "Before downloading new datafiles made for the new table, "
|
||||
+ "you have to reset your local setup by 'moving away' (or deleting) "
|
||||
+ "your <basedir>/brouter directory and start a new setup by calling the " + "BRouter App again.")
|
||||
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
|
||||
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
return builder.create();
|
||||
*/
|
||||
case DIALOG_ROUTINGMODES_ID:
|
||||
builder.setTitle(message);
|
||||
builder.setMultiChoiceItems(routingModes, routingModesChecked,
|
||||
|
|
@ -217,7 +211,7 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
routingModesChecked[which] = isChecked;
|
||||
}
|
||||
});
|
||||
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
|
||||
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
mBRouterView.configureService(routingModes, routingModesChecked);
|
||||
}
|
||||
|
|
@ -225,9 +219,9 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
return builder.create();
|
||||
case DIALOG_EXCEPTION_ID:
|
||||
builder
|
||||
.setTitle("An Error occured")
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(errorMessage)
|
||||
.setPositiveButton("OK",
|
||||
.setPositiveButton(R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
mBRouterView.continueProcessing();
|
||||
|
|
@ -235,12 +229,12 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
});
|
||||
return builder.create();
|
||||
case DIALOG_TEXTENTRY_ID:
|
||||
builder.setTitle("Enter SDCARD base dir:");
|
||||
builder.setTitle(R.string.title_sdcard);
|
||||
builder.setMessage(message);
|
||||
final EditText input = new EditText(this);
|
||||
// input.setText(defaultbasedir);
|
||||
builder.setView(input);
|
||||
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
|
||||
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
String basedir = input.getText().toString();
|
||||
mBRouterView.startSetup(new File(basedir), true, false);
|
||||
|
|
@ -248,7 +242,7 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
});
|
||||
return builder.create();
|
||||
case DIALOG_SELECTBASEDIR_ID:
|
||||
builder.setTitle("Choose brouter data base dir:");
|
||||
builder.setTitle(getString(R.string.action_choose_folder));
|
||||
// builder.setMessage( message );
|
||||
builder.setSingleChoiceItems(basedirOptions, 0, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
|
|
@ -256,7 +250,7 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
selectedBasedir = item;
|
||||
}
|
||||
});
|
||||
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
|
||||
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
if (selectedBasedir < availableBasedirs.size()) {
|
||||
mBRouterView.startSetup(availableBasedirs.get(selectedBasedir), true, false);
|
||||
|
|
@ -267,7 +261,7 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
});
|
||||
return builder.create();
|
||||
case DIALOG_VIASELECT_ID:
|
||||
builder.setTitle("Check VIA Selection:");
|
||||
builder.setTitle(R.string.action_via_select);
|
||||
builder.setMultiChoiceItems(availableVias, getCheckedBooleanArray(availableVias.length),
|
||||
new DialogInterface.OnMultiChoiceClickListener() {
|
||||
@Override
|
||||
|
|
@ -279,7 +273,7 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
}
|
||||
}
|
||||
});
|
||||
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
|
||||
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
mBRouterView.updateViaList(selectedVias);
|
||||
mBRouterView.startProcessing(selectedProfile);
|
||||
|
|
@ -287,7 +281,7 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
});
|
||||
return builder.create();
|
||||
case DIALOG_NOGOSELECT_ID:
|
||||
builder.setTitle("Check NoGo Selection:");
|
||||
builder.setTitle(R.string.action_nogo_select);
|
||||
String[] nogoNames = new String[nogoList.size()];
|
||||
for (int i = 0; i < nogoList.size(); i++)
|
||||
nogoNames[i] = nogoList.get(i).name;
|
||||
|
|
@ -299,7 +293,7 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
nogoEnabled[which] = isChecked;
|
||||
}
|
||||
});
|
||||
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
|
||||
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
mBRouterView.updateNogoList(nogoEnabled);
|
||||
mBRouterView.startProcessing(selectedProfile);
|
||||
|
|
@ -325,21 +319,21 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
List<String> slist = new ArrayList<>();
|
||||
// Neutral button
|
||||
if (wpCount == 0) {
|
||||
slist.add("Server-Mode");
|
||||
slist.add(getString(R.string.action_servermode));
|
||||
} else if (wpCount == -3) {
|
||||
slist.add("Info");
|
||||
slist.add(getString(R.string.action_info));
|
||||
} else if (wpCount >= 2) {
|
||||
slist.add("Calc Route");
|
||||
slist.add(getString(R.string.action_calc_route));
|
||||
}
|
||||
|
||||
if (wpCount == 0) {
|
||||
slist.add("Profile Settings");
|
||||
slist.add(getString(R.string.action_profile_settings));
|
||||
}
|
||||
// Positive button
|
||||
if (wpCount == -3 || wpCount == -1) {
|
||||
slist.add("Share GPX");
|
||||
slist.add(getString(R.string.action_share));
|
||||
} else if (wpCount >= 0) {
|
||||
String selectLabel = wpCount == 0 ? "Select from" : "Select to/via";
|
||||
String selectLabel = wpCount == 0 ? getString(R.string.action_select_from) : getString(R.string.action_select_to);
|
||||
slist.add(selectLabel);
|
||||
}
|
||||
|
||||
|
|
@ -407,16 +401,16 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
*/
|
||||
|
||||
// Negative button
|
||||
builder.setNegativeButton("Exit", (dialog, which) -> {
|
||||
builder.setNegativeButton(R.string.exit, (dialog, which) -> {
|
||||
finish();
|
||||
});
|
||||
|
||||
return builder.create();
|
||||
case DIALOG_MODECONFIGOVERVIEW_ID:
|
||||
builder
|
||||
.setTitle("Success")
|
||||
.setTitle(R.string.success)
|
||||
.setMessage(message)
|
||||
.setPositiveButton("Exit",
|
||||
.setPositiveButton(R.string.exit,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
finish();
|
||||
|
|
@ -424,7 +418,7 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
});
|
||||
return builder.create();
|
||||
case DIALOG_PICKWAYPOINT_ID:
|
||||
builder.setTitle(wpCount > 0 ? "Select to/via" : "Select from");
|
||||
builder.setTitle(wpCount == 0 ? getString(R.string.action_select_from) : getString(R.string.action_select_to));
|
||||
builder.setItems(availableWaypoints, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int item) {
|
||||
mBRouterView.updateWaypointList(availableWaypoints[item]);
|
||||
|
|
@ -472,11 +466,11 @@ public class BRouterActivity extends AppCompatActivity implements ActivityCompat
|
|||
//startActivityForResult(i, 100);
|
||||
someActivityResultLauncher.launch(i);
|
||||
} else {
|
||||
Toast.makeText(this, "no profile data", Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, R.string.msg_no_profile, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(this, selectedProfile + ", no used profile", Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, selectedProfile + getString(R.string.msg_no_used_profile), Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -99,11 +96,13 @@ public class BRouterService extends Service {
|
|||
if (errMsg != null) {
|
||||
return errMsg;
|
||||
}
|
||||
// profile is already done
|
||||
params.remove("profile");
|
||||
|
||||
boolean canCompress = "true".equals(params.getString("acceptCompressedResult"));
|
||||
try {
|
||||
String gpxMessage = worker.getTrackFromParams(params);
|
||||
if (canCompress && gpxMessage.startsWith("<")) {
|
||||
if (canCompress && (gpxMessage.startsWith("<") || gpxMessage.startsWith("{"))) {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
baos.write("z64".getBytes(Charset.forName("UTF-8"))); // marker prefix
|
||||
|
|
@ -274,11 +273,17 @@ public class BRouterService extends Service {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ import btools.util.CheapRuler;
|
|||
|
||||
public class BRouterView extends View {
|
||||
|
||||
private static final String TAG = "BRouterView";
|
||||
|
||||
private final int memoryClass;
|
||||
RoutingEngine cr;
|
||||
private int imgw;
|
||||
|
|
@ -148,8 +150,8 @@ public class BRouterView extends View {
|
|||
try {
|
||||
td.mkdirs();
|
||||
} catch (Exception e) {
|
||||
Log.d("BRouterView", "Error creating base directory: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
Log.d(TAG, "Error creating base directory: " + e.getMessage());
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
}
|
||||
|
||||
if (!td.isDirectory()) {
|
||||
|
|
@ -173,7 +175,7 @@ public class BRouterView extends View {
|
|||
|
||||
// new init is done move old files
|
||||
if (waitingForMigration) {
|
||||
Log.d("BR", "path " + oldMigrationPath + " " + basedir);
|
||||
Log.d(TAG, "path " + oldMigrationPath + " " + basedir);
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
|
@ -184,7 +186,7 @@ public class BRouterView extends View {
|
|||
try {
|
||||
t.join(500);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
}
|
||||
waitingForMigration = false;
|
||||
}
|
||||
|
|
@ -224,7 +226,9 @@ public class BRouterView extends View {
|
|||
// add a "last timeout" dummy profile
|
||||
File lastTimeoutFile = new File(modesDir + "/timeoutdata.txt");
|
||||
long lastTimeoutTime = lastTimeoutFile.lastModified();
|
||||
if (lastTimeoutTime > 0 && System.currentTimeMillis() - lastTimeoutTime < 1800000) {
|
||||
if (lastTimeoutTime > 0 &&
|
||||
lastTimeoutFile.length() > 0 &&
|
||||
System.currentTimeMillis() - lastTimeoutTime < 1800000) {
|
||||
BufferedReader br = new BufferedReader(new FileReader(lastTimeoutFile));
|
||||
String repeatProfile = br.readLine();
|
||||
br.close();
|
||||
|
|
@ -331,9 +335,9 @@ public class BRouterView extends View {
|
|||
out.close();
|
||||
|
||||
} catch (FileNotFoundException fileNotFoundException) {
|
||||
Log.e("tag", fileNotFoundException.getMessage());
|
||||
Log.e(TAG, fileNotFoundException.getMessage());
|
||||
} catch (Exception e) {
|
||||
Log.e("tag", e.getMessage());
|
||||
Log.e(TAG, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -380,14 +384,14 @@ public class BRouterView extends View {
|
|||
try {
|
||||
cor.readAllPoints();
|
||||
} catch (Exception e) {
|
||||
msg = "Error reading waypoints: " + e;
|
||||
msg = getContext().getString(R.string.msg_read_wpt_error)+ ": " + e;
|
||||
}
|
||||
|
||||
int size = cor.allpoints.size();
|
||||
if (size < 1)
|
||||
msg = "coordinate source does not contain any waypoints!";
|
||||
msg = getContext().getString(R.string.msg_no_wpt);
|
||||
if (size > 1000)
|
||||
msg = "coordinate source contains too much waypoints: " + size + "(please use from/to/via names)";
|
||||
msg = String.format(getContext().getString(R.string.msg_too_much_wpts), size);
|
||||
}
|
||||
|
||||
if (msg != null) {
|
||||
|
|
@ -471,13 +475,13 @@ public class BRouterView extends View {
|
|||
if (needsWaypointSelection) {
|
||||
StringBuilder msg;
|
||||
if (wpList.size() == 0) {
|
||||
msg = new StringBuilder("Expecting waypoint selection\n" + "(coordinate-source: " + cor.basedir + cor.rootdir + ")");
|
||||
msg = new StringBuilder(getContext().getString(R.string.msg_no_wpt_selection) + "(coordinate-source: " + cor.basedir + cor.rootdir + ")");
|
||||
} else {
|
||||
msg = new StringBuilder("current waypoint selection:\n");
|
||||
msg = new StringBuilder(getContext().getString(R.string.msg_wpt_selection));
|
||||
for (int i = 0; i < wpList.size(); i++)
|
||||
msg.append(i > 0 ? "->" : "").append(wpList.get(i).name);
|
||||
}
|
||||
((BRouterActivity) getContext()).showResultMessage("Select Action", msg.toString(), wpList.size());
|
||||
((BRouterActivity) getContext()).showResultMessage(getContext().getString(R.string.title_action), msg.toString(), wpList.size());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -718,8 +722,13 @@ public class BRouterView extends View {
|
|||
((BRouterActivity) getContext()).showErrorMessage(cr.getErrorMessage());
|
||||
} else {
|
||||
String memstat = memoryClass + "mb pathPeak " + ((cr.getPathPeak() + 500) / 1000) + "k";
|
||||
String result = "version = BRouter-" + getContext().getString(R.string.app_version) + "\n" + "mem = " + memstat + "\ndistance = " + cr.getDistance() / 1000. + " km\n" + "filtered ascend = " + cr.getAscend()
|
||||
+ " m\n" + "plain ascend = " + cr.getPlainAscend() + " m\n" + "estimated time = " + cr.getTime();
|
||||
String result = String.format(getContext().getString(R.string.msg_status_result),
|
||||
getContext().getString(R.string.app_version),
|
||||
memstat,
|
||||
Double.toString(cr.getDistance() / 1000.),
|
||||
Integer.toString(cr.getAscend()),
|
||||
Integer.toString(cr.getPlainAscend()),
|
||||
cr.getTime());
|
||||
|
||||
rawTrack = cr.getFoundRawTrack();
|
||||
|
||||
|
|
@ -728,9 +737,9 @@ public class BRouterView extends View {
|
|||
writeRawTrackToPath(rawTrackPath);
|
||||
}
|
||||
|
||||
String title = "Success";
|
||||
String title = getContext().getString(R.string.success);
|
||||
if (cr.getAlternativeIndex() > 0)
|
||||
title += " / " + cr.getAlternativeIndex() + ". Alternative";
|
||||
title += " / " + cr.getAlternativeIndex() + ". " + getContext().getString(R.string.msg_alternative);
|
||||
|
||||
((BRouterActivity) getContext()).showResultMessage(title, result, rawTrackPath == null ? -1 : -3);
|
||||
trackOutfile = cr.getOutfile();
|
||||
|
|
@ -845,8 +854,13 @@ public class BRouterView extends View {
|
|||
for (int i = 0; i < 6; i++) {
|
||||
if (checkedModes[i]) {
|
||||
writeRawTrackToMode(routingModes[i]);
|
||||
String s = map.get(routingModes[i]).params;
|
||||
String p = map.get(routingModes[i]).profile;
|
||||
ServiceModeConfig sm = map.get(routingModes[i]);
|
||||
String s = null;
|
||||
String p = null;
|
||||
if (sm != null) {
|
||||
s = sm.params;
|
||||
p = sm.profile;
|
||||
}
|
||||
if (s == null || !p.equals(profileName)) s = "noparams";
|
||||
ServiceModeConfig smc = new ServiceModeConfig(routingModes[i], profileName, s);
|
||||
for (OsmNodeNamed nogo : nogoVetoList) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -32,6 +36,7 @@ public class BRouterWorker {
|
|||
public List<OsmNodeNamed> nogoPolygonsList;
|
||||
public String profileParams;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public String getTrackFromParams(Bundle params) {
|
||||
|
||||
int engineMode = 0;
|
||||
|
|
@ -39,6 +44,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<String, String> 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<String, String> 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 +123,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 = 7;
|
||||
}
|
||||
}
|
||||
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<OsmNodeNamed> 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 +150,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 +199,6 @@ public class BRouterWorker {
|
|||
return null;
|
||||
}
|
||||
|
||||
private List<OsmNodeNamed> readPositions(Bundle params) {
|
||||
List<OsmNodeNamed> 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<OsmNodeNamed> readLonlats(Bundle params, int mode) {
|
||||
List<OsmNodeNamed> 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<OsmNodeNamed> readNogoList(Bundle params) {
|
||||
// lon,lat,radius|...
|
||||
String nogos = params.getString("nogos");
|
||||
if (nogos == null) return null;
|
||||
|
||||
String[] lonLatRadList = nogos.split("\\|");
|
||||
|
||||
List<OsmNodeNamed> 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<OsmNodeNamed> readNogoPolygons(Bundle params) {
|
||||
List<OsmNodeNamed> 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<OsmNodeNamed> 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<OsmNodeNamed> readPoisList(Bundle params) {
|
||||
// lon,lat,name|...
|
||||
String pois = params.getString("pois");
|
||||
if (pois == null) return null;
|
||||
|
||||
String[] lonLatNameList = pois.split("\\|");
|
||||
|
||||
List<OsmNodeNamed> 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,15 +209,19 @@ public class BRouterWorker {
|
|||
bw.write(rc.rawTrackPath);
|
||||
bw.write("\n");
|
||||
writeWPList(bw, waypoints);
|
||||
writeWPList(bw, nogoList);
|
||||
writeWPList(bw, rc.nogopoints);
|
||||
bw.close();
|
||||
}
|
||||
|
||||
private void writeWPList(BufferedWriter bw, List<OsmNodeNamed> wps) throws Exception {
|
||||
bw.write(wps.size() + "\n");
|
||||
for (OsmNodeNamed wp : wps) {
|
||||
bw.write(wp.toString());
|
||||
bw.write("\n");
|
||||
if (wps == null) {
|
||||
bw.write("0\n");
|
||||
} else {
|
||||
bw.write(wps.size() + "\n");
|
||||
for (OsmNodeNamed wp : wps) {
|
||||
bw.write(wp.toString());
|
||||
bw.write("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.app.NotificationChannel;
|
|||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
|
|
@ -72,6 +73,7 @@ public class DownloadWorker extends Worker {
|
|||
int version = -1;
|
||||
int appversion = -1;
|
||||
String errorCode = null;
|
||||
private boolean bHttpDownloadProblem;
|
||||
|
||||
public DownloadWorker(
|
||||
@NonNull Context context,
|
||||
|
|
@ -169,7 +171,10 @@ public class DownloadWorker extends Worker {
|
|||
}
|
||||
notificationBuilder.setContentText("Starting Download");
|
||||
// Mark the Worker as important
|
||||
setForegroundAsync(new ForegroundInfo(NOTIFICATION_ID, notificationBuilder.build()));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
||||
setForegroundAsync(new ForegroundInfo(NOTIFICATION_ID, notificationBuilder.build(), ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC));
|
||||
else
|
||||
setForegroundAsync(new ForegroundInfo(NOTIFICATION_ID, notificationBuilder.build()));
|
||||
try {
|
||||
if (DEBUG) Log.d(LOG_TAG, "Download lookup & profiles");
|
||||
if (!downloadLookup()) {
|
||||
|
|
@ -251,6 +256,7 @@ public class DownloadWorker extends Worker {
|
|||
newappversion = meta.minAppVersion;
|
||||
} else {
|
||||
String lookupLocation = mServerConfig.getLookupUrl() + fileName;
|
||||
if (bHttpDownloadProblem) lookupLocation = lookupLocation.replace("https://", "http://");
|
||||
URL lookupUrl = new URL(lookupLocation);
|
||||
downloadProgressListener.onDownloadStart(fileName, DownloadType.LOOKUP);
|
||||
changed = downloadFile(lookupUrl, tmplookupFile, size, false, DownloadType.LOOKUP);
|
||||
|
|
@ -301,6 +307,7 @@ public class DownloadWorker extends Worker {
|
|||
//if (profileFile.exists())
|
||||
{
|
||||
String profileLocation = mServerConfig.getProfilesUrl() + fileName;
|
||||
if (bHttpDownloadProblem) profileLocation = profileLocation.replace("https://", "http://");
|
||||
URL profileUrl = new URL(profileLocation);
|
||||
int size = (int) (profileFile.exists() ? profileFile.length() : 0);
|
||||
|
||||
|
|
@ -322,6 +329,8 @@ public class DownloadWorker extends Worker {
|
|||
private void downloadSegment(String segmentBaseUrl, String segmentName) throws IOException, InterruptedException {
|
||||
File segmentFile = new File(baseDir, SEGMENTS_DIR + segmentName);
|
||||
File segmentFileTemp = new File(segmentFile.getAbsolutePath() + "_tmp");
|
||||
if (bHttpDownloadProblem) segmentBaseUrl = segmentBaseUrl.replace("https://", "http://");
|
||||
|
||||
if (DEBUG) Log.d(LOG_TAG, "Download " + segmentName + " " + version + " " + versionChanged);
|
||||
try {
|
||||
if (segmentFile.exists()) {
|
||||
|
|
@ -329,6 +338,7 @@ public class DownloadWorker extends Worker {
|
|||
String md5 = Rd5DiffManager.getMD5(segmentFile);
|
||||
if (DEBUG) Log.d(LOG_TAG, "Calculating local checksum " + md5);
|
||||
String segmentDeltaLocation = segmentBaseUrl + "diff/" + segmentName.replace(SEGMENT_SUFFIX, "/" + md5 + SEGMENT_DIFF_SUFFIX);
|
||||
if (bHttpDownloadProblem) segmentDeltaLocation = segmentDeltaLocation.replace("https://", "http://");
|
||||
URL segmentDeltaUrl = new URL(segmentDeltaLocation);
|
||||
if (httpFileExists(segmentDeltaUrl)) {
|
||||
File segmentDeltaFile = new File(segmentFile.getAbsolutePath() + "_diff");
|
||||
|
|
@ -372,13 +382,28 @@ public class DownloadWorker extends Worker {
|
|||
}
|
||||
|
||||
private boolean httpFileExists(URL downloadUrl) throws IOException {
|
||||
HttpURLConnection connection = (HttpURLConnection) downloadUrl.openConnection();
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setRequestMethod("HEAD");
|
||||
connection.setDoInput(false);
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
connection = (HttpURLConnection) downloadUrl.openConnection();
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setRequestMethod("HEAD");
|
||||
connection.setDoInput(false);
|
||||
connection.connect();
|
||||
return connection.getResponseCode() == HttpURLConnection.HTTP_OK;
|
||||
} catch (javax.net.ssl.SSLHandshakeException e) {
|
||||
String url = downloadUrl.toString().replace("https://", "http://");
|
||||
downloadUrl = new URL(url);
|
||||
try {
|
||||
connection = (HttpURLConnection) downloadUrl.openConnection();
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setRequestMethod("HEAD");
|
||||
connection.setDoInput(false);
|
||||
connection.connect();
|
||||
bHttpDownloadProblem = true;
|
||||
return connection.getResponseCode() == HttpURLConnection.HTTP_OK;
|
||||
} finally {
|
||||
connection.disconnect();
|
||||
}
|
||||
} finally {
|
||||
connection.disconnect();
|
||||
}
|
||||
|
|
@ -387,14 +412,24 @@ public class DownloadWorker extends Worker {
|
|||
|
||||
private boolean downloadFile(URL downloadUrl, File outputFile, int fileSize, boolean limitDownloadSpeed, DownloadType type) throws IOException, InterruptedException {
|
||||
if (DEBUG) Log.d(LOG_TAG, "download " + outputFile.getAbsolutePath());
|
||||
HttpURLConnection connection = (HttpURLConnection) downloadUrl.openConnection();
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setDefaultUseCaches(false);
|
||||
|
||||
HttpURLConnection connection = null;
|
||||
InputStream input = null;
|
||||
OutputStream output = null;
|
||||
try {
|
||||
connection.connect();
|
||||
try {
|
||||
connection = (HttpURLConnection) downloadUrl.openConnection();
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setDefaultUseCaches(false);
|
||||
connection.connect();
|
||||
} catch (javax.net.ssl.SSLHandshakeException e) {
|
||||
String url = downloadUrl.toString().replace("https://", "http://");
|
||||
downloadUrl = new URL(url);
|
||||
connection = (HttpURLConnection) downloadUrl.openConnection();
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setDefaultUseCaches(false);
|
||||
connection.connect();
|
||||
bHttpDownloadProblem = true;
|
||||
}
|
||||
|
||||
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
throw new IOException("HTTP Request failed: " + downloadUrl + " returned " + connection.getResponseCode());
|
||||
|
|
|
|||
|
|
@ -4,11 +4,14 @@ import android.app.Activity;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.window.OnBackInvokedCallback;
|
||||
import android.window.OnBackInvokedDispatcher;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
|
@ -144,7 +147,7 @@ public class RoutingParameterDialog extends AppCompatActivity {
|
|||
list.add(p);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
}
|
||||
}
|
||||
} while (line != null);
|
||||
|
|
@ -167,41 +170,57 @@ public class RoutingParameterDialog extends AppCompatActivity {
|
|||
new OnBackInvokedCallback() {
|
||||
@Override
|
||||
public void onBackInvoked() {
|
||||
StringBuilder sb = null;
|
||||
if (sharedValues != null) {
|
||||
// fill preference with used params
|
||||
// for direct use in the BRouter interface "extraParams"
|
||||
sb = new StringBuilder();
|
||||
for (Map.Entry<String, ?> entry : sharedValues.getAll().entrySet()) {
|
||||
if (!entry.getKey().equals("params")) {
|
||||
sb.append(sb.length() > 0 ? "&" : "")
|
||||
.append(entry.getKey())
|
||||
.append("=");
|
||||
String s = entry.getValue().toString();
|
||||
if (s.equals("true")) s = "1";
|
||||
else if (s.equals("false")) s = "0";
|
||||
sb.append(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
// and return the array
|
||||
// one should be enough
|
||||
Intent i = new Intent();
|
||||
// i.putExtra("PARAMS", listParams);
|
||||
i.putExtra("PROFILE", profile);
|
||||
i.putExtra("PROFILE_HASH", profile_hash);
|
||||
if (sb != null) i.putExtra("PARAMS_VALUES", sb.toString());
|
||||
|
||||
setResult(Activity.RESULT_OK, i);
|
||||
finish();
|
||||
handleBackPressed();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
} else {
|
||||
OnBackPressedCallback callback = new OnBackPressedCallback(true) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
handleBackPressed();
|
||||
}
|
||||
};
|
||||
getOnBackPressedDispatcher().addCallback(this, callback);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleBackPressed() {
|
||||
StringBuilder sb = null;
|
||||
if (sharedValues != null) {
|
||||
// fill preference with used params
|
||||
// for direct use in the BRouter interface "extraParams"
|
||||
sb = new StringBuilder();
|
||||
for (Map.Entry<String, ?> entry : sharedValues.getAll().entrySet()) {
|
||||
if (!entry.getKey().equals("params")) {
|
||||
sb.append(sb.length() > 0 ? "&" : "")
|
||||
.append(entry.getKey())
|
||||
.append("=");
|
||||
String s = entry.getValue().toString();
|
||||
if (s.equals("true")) s = "1";
|
||||
else if (s.equals("false")) s = "0";
|
||||
sb.append(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
// and return the array
|
||||
// one should be enough
|
||||
Intent i = new Intent();
|
||||
// i.putExtra("PARAMS", listParams);
|
||||
i.putExtra("PROFILE", profile);
|
||||
i.putExtra("PROFILE_HASH", profile_hash);
|
||||
if (sb != null) i.putExtra("PARAMS_VALUES", sb.toString());
|
||||
|
||||
setResult(Activity.RESULT_OK, i);
|
||||
finish();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
|
||||
public static class MyPreferenceFragment extends PreferenceFragmentCompat {
|
||||
|
||||
|
|
@ -222,6 +241,7 @@ public class RoutingParameterDialog extends AppCompatActivity {
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
|
|
@ -244,10 +264,10 @@ public class RoutingParameterDialog extends AppCompatActivity {
|
|||
|
||||
if (i.hasExtra("PARAMS")) {
|
||||
List<?> result;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
result = (List<?>) i.getExtras().getSerializable("PARAMS", ArrayList.class);
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
result = (List<?>) i.getExtras().getSerializable("PARAMS");
|
||||
} else {
|
||||
result = (List<?>) i.getExtras().getSerializable("PARAMS", ArrayList.class);
|
||||
}
|
||||
if (result instanceof ArrayList) {
|
||||
for (Object o : result) {
|
||||
|
|
@ -259,7 +279,7 @@ public class RoutingParameterDialog extends AppCompatActivity {
|
|||
sparams = i.getExtras().getString("PARAMS_VALUES", "");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
}
|
||||
|
||||
getPreferenceManager().setSharedPreferencesName("prefs_profile_" + profile_hash);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package btools.routingapp;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
|
|
@ -13,6 +14,9 @@ import java.util.zip.ZipEntry;
|
|||
import java.util.zip.ZipInputStream;
|
||||
|
||||
public class ServerConfig {
|
||||
|
||||
private static final String TAG = "ServerConfig";
|
||||
|
||||
private static String mServerConfigName = "serverconfig.txt";
|
||||
|
||||
private String mSegmentUrl = "https://brouter.de/brouter/segments4/";
|
||||
|
|
@ -52,7 +56,7 @@ public class ServerConfig {
|
|||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
} finally {
|
||||
try {
|
||||
if (br != null) br.close();
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@
|
|||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@
|
|||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
|
|
|
|||
94
brouter-routing-app/src/main/res/values-ar/strings.xml
Normal file
94
brouter-routing-app/src/main/res/values-ar/strings.xml
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<plurals name="numberOfSegments" tools:ignore="MissingQuantity">
|
||||
<item quantity="one">%d قطعة</item>
|
||||
<item quantity="other">%d قطع</item>
|
||||
</plurals>
|
||||
<string name="cancel_download">إلغاء التنزيل</string>
|
||||
<string name="import_profile">استيراد ملف تعريف</string>
|
||||
<string name="action_download">تنزيل %s</string>
|
||||
<string name="action_delete">حذف %s</string>
|
||||
<string name="action_update">تحديث %s</string>
|
||||
<string name="action_select">حدد القطع</string>
|
||||
<string name="action_cancel">إيقاف التنزيل</string>
|
||||
<string name="summary_segments">الحجم=%1$s\nالحجم المتوفر=%2$s</string>
|
||||
<string name="notification_title">تحميل القطع</string>
|
||||
|
||||
<string name="action_choose_folder">اختر مكان قاعدة بيانات brouter:</string>
|
||||
<string name="action_select_profile">اختر ملف تعريف التوجيه</string>
|
||||
<string name="main_action">حدد الإجراء الرئيسي</string>
|
||||
<string name="main_action_1">مدير التنزيلات</string>
|
||||
<string name="main_action_2">تطبيق BRouter</string>
|
||||
|
||||
<string name="cancel">إلغاء</string>
|
||||
<string name="i_know">أعرف ذلك</string>
|
||||
<string name="close">إغلاق</string>
|
||||
<string name="exit">خروج</string>
|
||||
<string name="ok">موافق</string>
|
||||
<string name="success">تم بنجاح</string>
|
||||
<string name="error">حدث خطأ ما</string>
|
||||
|
||||
<string name="title_download">مدير تنزيلات BRouter</string>
|
||||
<string name="summary_download">*** تحذير:***
|
||||
\n\nيتم استخدام مدير التنزيل لتنزيل ملفات بيانات التوجيه عبر الطرق
|
||||
والتي يمكن أن يصل حجمها إلى 170 ميجابايت، لذلك لا تقم بتشغيل
|
||||
"مدير التنزيلات" حينما تكون متصلاً عبر البيانات الخلوية ومحدوداً بحجم التنزيلات!
|
||||
سرعة التنزيل محدودة على 16 ميجابايت/بالثانية.</string>
|
||||
<string name="title_timeoutfree">أنجزت عملية الحساب بنجاح وبدون تأخير</string>
|
||||
<string name="summary_timeoutfree">لقد نجحت في تكرار عملية حسابية كانت قد انتهت في السابق
|
||||
عند بدايتها من خلال أداة الخريطة، إذا قمت بتكرار نفس الطلب من
|
||||
أداة الخريطة الخاصة بك ومع نفس الوجهة بالضبط وبنقطة بداية
|
||||
قريبة، فسيضمن لك التطبيق عدم انتهاء مهلة هذا الطلب.</string>
|
||||
<string name="title_sdcard">أدخل مسار الذاكرة الخارجية:</string>
|
||||
<string name="title_action">اختر الإجراء</string>
|
||||
|
||||
<string name="action_via_select">التحقق من النقاط الوسيطة:</string>
|
||||
<string name="action_nogo_select">التحقق من النقاط المسبتعدة:</string>
|
||||
<string name="action_servermode">وضع-الخادم</string>
|
||||
<string name="action_info">معلومات</string>
|
||||
<string name="action_calc_route">حساب الطريق</string>
|
||||
<string name="action_profile_settings">إعدادات ملف التعريف</string>
|
||||
<string name="action_share">مشاركة ملف GPX</string>
|
||||
<string name="action_select_from">اختر من</string>
|
||||
<string name="action_select_to">اختر إلى/عبر</string>
|
||||
|
||||
<string name="msg_no_profile">لا توجد بيانات ملف التعريف</string>
|
||||
<string name="msg_no_used_profile">، لا يوجد ملف تعريف مستخدم</string>
|
||||
<string name="msg_too_much_data">هناك الكثير من البيانات للتنزيل، من فضلك قم بتقليلها.</string>
|
||||
<string name="msg_download_start">تمت جدولة التنزيل، وتحقق من اتصالك بالإنترنت إذا لم يبدأ التنزيل.</string>
|
||||
<string name="msg_wpt_selection">نقاط الطريق الحالية المحددة:\n</string>
|
||||
<string name="msg_no_wpt_selection">نقاط الطريق المتوقعة المحددة\n</string>
|
||||
<string name="msg_alternative">البديل</string>
|
||||
<string name="msg_status_result">الإصدار = BRouter-%1$s \n
|
||||
الذاكرة = %2$s \n
|
||||
المسافة = %3$s كم\n
|
||||
التصاعد المرشح = %4$s م\n
|
||||
التصاعد العادي = %5$s م\n
|
||||
الوقت المقدر = %6$s</string>
|
||||
<string name="msg_read_wpt_error">خطأ في قراءة نقاط الطريق</string>
|
||||
<string name="msg_no_wpt">لا يحتوي مصدر الإحداثيات على أي نقاط الطريق!</string>
|
||||
<string name="msg_too_much_wpts">مصدر الإحداثيات يحتوي على عدد كبير جدًا من نقاط الطريق: %1$d (يرجى استخدام أسماء النقاط من/إلى/عبر from/to/via)</string>
|
||||
|
||||
<string name="no">لا</string>
|
||||
<string name="yes">نعم</string>
|
||||
|
||||
<string name="title_delete">تأكيد الحذف</string>
|
||||
<string name="summary_delete">هل ترغب بالحذف؟</string>
|
||||
<string name="title_version">مشكلة في الإصدار</string>
|
||||
<string name="summary_version">لقد تغير الإصدار الأساسي للصور المتجانبة، ما الإجراء المناسب لفعله؟</string>
|
||||
<string name="action_version1">متابعة التنزيل الحالي، وحذف البيانات الأخرى القديمة</string>
|
||||
<string name="action_version2">تحديد الكل للتنزيل والبدء</string>
|
||||
<string name="action_version3">قم بالإلغاء في الوقت الحالي، واستكمله لاحقاً</string>
|
||||
<string name="title_version_diff">اختلافات الإصدارات</string>
|
||||
<string name="summary_version_diff">الإصدار الأساسي لبعض الصور المتجانبة مختلف. ما الإجراء المناسب لفعله؟</string>
|
||||
<string name="action_version_diff1">تحميل المختلف من الصور المتجانبة</string>
|
||||
<string name="action_version_diff2">حذف كل الصور المتجانبة المختلفة عن الأخرى</string>
|
||||
<string name="action_version_diff3">قم بالإلغاء في الوقت الحالي، واستكمله لاحقاً</string>
|
||||
<string name="summary_new_version">يحتاج إصدار البيانات الجديد إلى وجود التطبيق الجديد، لذا نرجوا منك تحديث BRouter أولاً</string>
|
||||
|
||||
<string name="msg_download_failed">فشل التنزيل</string>
|
||||
<string name="msg_download_cancel">تم إلغاء التنزيل</string>
|
||||
<string name="msg_download_succeed">تم التنزيل بنجاح</string>
|
||||
<string name="msg_download_started">جار التنزيل…</string>
|
||||
|
||||
</resources>
|
||||
94
brouter-routing-app/src/main/res/values-ca/strings.xml
Normal file
94
brouter-routing-app/src/main/res/values-ca/strings.xml
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<plurals name="numberOfSegments" tools:ignore="MissingQuantity">
|
||||
<item quantity="one">%d segment</item>
|
||||
<item quantity="other">%d segments</item>
|
||||
</plurals>
|
||||
<string name="cancel_download">Cancel·lar descàrrega</string>
|
||||
<string name="import_profile">Importar perfil</string>
|
||||
<string name="action_download">Descàrrega %s</string>
|
||||
<string name="action_delete">Eliminar %s</string>
|
||||
<string name="action_update">Actualitzar %s</string>
|
||||
<string name="action_select">Seleccionar segments</string>
|
||||
<string name="action_cancel">Aturar Descàrrega</string>
|
||||
<string name="summary_segments">Espai=%1$s\nLliure=%2$s</string>
|
||||
<string name="notification_title">Descarregar segments</string>
|
||||
|
||||
<string name="action_choose_folder">Escollir directori base brouter:</string>
|
||||
<string name="action_select_profile">Seleccionar un perfil d\'enrutament</string>
|
||||
<string name="main_action">Seleccionar Acció Principal</string>
|
||||
<string name="main_action_1">Gestor de Baixades</string>
|
||||
<string name="main_action_2">App BRouter</string>
|
||||
|
||||
<string name="cancel">Cancel·lar</string>
|
||||
<string name="i_know">Ho sé</string>
|
||||
<string name="close">Tancar</string>
|
||||
<string name="exit">Sortir</string>
|
||||
<string name="ok">D\'acord</string>
|
||||
<string name="success">Èxit</string>
|
||||
<string name="error">Ha aparegut un error</string>
|
||||
|
||||
<string name="title_download">Gestor de baixades BRouter</string>
|
||||
<string name="summary_download">*** Atenció:***
|
||||
\n\nEl Gestor de Baixades es fa servir per descarregar fitxers de dades
|
||||
d\'enrutament, que poden arribar als 170 Mb cadascun. No inicies el Gestor
|
||||
des d\'un mòbil sense un pla de dades!
|
||||
La velocitat de baixada està limitada a 16 Mbit/s.</string>
|
||||
<string name="title_timeoutfree">S\'ha preparat correctament un càlcul sense límit de temps</string>
|
||||
<string name="summary_timeoutfree">S\'ha repetit amb èxit un càlcul a través
|
||||
de l\'aplicació de cartografia que prèviament havia superat el temps d\'espera.
|
||||
Si repeteixes la mateixa petició amb exactament el mateix destí i un punt de partida proper,
|
||||
es garanteix que la petició no esgotarà el límit de temps.</string>
|
||||
<string name="title_sdcard">Introdueix el directori base de la tarja SD:</string>
|
||||
<string name="title_action">Seleccionar Acció</string>
|
||||
|
||||
<string name="action_via_select">Comprovar Selecció VIA:</string>
|
||||
<string name="action_nogo_select">Comprovar Selecció NoGo:</string>
|
||||
<string name="action_servermode">Mode-Servidor</string>
|
||||
<string name="action_info">Info</string>
|
||||
<string name="action_calc_route">Calc Ruta</string>
|
||||
<string name="action_profile_settings">Ajustaments del perfil</string>
|
||||
<string name="action_share">Compartir GPX</string>
|
||||
<string name="action_select_from">Seleccionar des de</string>
|
||||
<string name="action_select_to">Seleccionar a/via</string>
|
||||
|
||||
<string name="msg_no_profile">no hi ha dades al perfil</string>
|
||||
<string name="msg_no_used_profile">, cap perfil utilitzat</string>
|
||||
<string name="msg_too_much_data">Massa dades per baixar. Si us plau, redueix-les.</string>
|
||||
<string name="msg_download_start">Baixada programada. Comprovar la connexió a internet si no comença.</string>
|
||||
<string name="msg_wpt_selection">selecció actual de fita:\n</string>
|
||||
<string name="msg_no_wpt_selection">Esperant selecció de fita\n</string>
|
||||
<string name="msg_alternative">Alternativa</string>
|
||||
<string name="msg_status_result">versió = BRouter-%1$s \n
|
||||
memòria = %2$s \n
|
||||
distància = %3$s km\n
|
||||
ascensió filtrada = %4$s m\n
|
||||
ascens en pla = %5$s m\n
|
||||
temps estimat = %6$s</string>
|
||||
<string name="msg_read_wpt_error">Error llegint fites</string>
|
||||
<string name="msg_no_wpt">la font de coordenades no conté cap fita!</string>
|
||||
<string name="msg_too_much_wpts">la font de coordenades conté massa fites: %1$d (si us plau, fes servir noms des de/a/via)</string>
|
||||
|
||||
<string name="no">No</string>
|
||||
<string name="yes">Si</string>
|
||||
|
||||
<string name="title_delete">Confirmar Eliminar</string>
|
||||
<string name="summary_delete">Voleu realment eliminar?</string>
|
||||
<string name="title_version">Problema de versió</string>
|
||||
<string name="summary_version">La versió base per les tesel·les ha canviat. Què vols fer?</string>
|
||||
<string name="action_version1">Continuar amb la baixada, eliminar altres dades antigues</string>
|
||||
<string name="action_version2">Seleccionar-ho tot per baixar i iniciar</string>
|
||||
<string name="action_version3">Cancel·lar ara, completar un altre dia</string>
|
||||
<string name="title_version_diff">Diferències de Versió</string>
|
||||
<string name="summary_version_diff">La versió base de diverses tesel·les és diferent. Què vols fer?</string>
|
||||
<string name="action_version_diff1">Baixar totes les tesel·les diferents</string>
|
||||
<string name="action_version_diff2">Descartar les tesel·les diferents</string>
|
||||
<string name="action_version_diff3">Cancel·lar ara, completar un altre dia</string>
|
||||
<string name="summary_new_version">La nova versió de dades necessita una aplicació nova. Sisplau, actualitza BRouter primer</string>
|
||||
|
||||
<string name="msg_download_failed">Baixada fallida</string>
|
||||
<string name="msg_download_cancel">Baixada cancel·lada</string>
|
||||
<string name="msg_download_succeed">Baixada exitosa</string>
|
||||
<string name="msg_download_started">Baixant…</string>
|
||||
|
||||
</resources>
|
||||
94
brouter-routing-app/src/main/res/values-de/strings.xml
Normal file
94
brouter-routing-app/src/main/res/values-de/strings.xml
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<plurals name="numberOfSegments" tools:ignore="MissingQuantity">
|
||||
<item quantity="one">%d Segment</item>
|
||||
<item quantity="other">%d Segmente</item>
|
||||
</plurals>
|
||||
<string name="cancel_download">Download abbrechen</string>
|
||||
<string name="import_profile">Profil importieren</string>
|
||||
<string name="action_download">%s downloaden</string>
|
||||
<string name="action_delete">%s löschen</string>
|
||||
<string name="action_update">%s aktualisieren</string>
|
||||
<string name="action_select">Segmente auswählen</string>
|
||||
<string name="action_cancel">Download stoppen</string>
|
||||
<string name="summary_segments">Größe=%1$s\nFrei=%2$s</string>
|
||||
<string name="notification_title">Segmente herunterladen</string>
|
||||
|
||||
<string name="action_choose_folder">BRouter-Datenbankverzeichnis wählen:</string>
|
||||
<string name="action_select_profile">Routenprofil wählen</string>
|
||||
<string name="main_action">Standardaktion wählen</string>
|
||||
<string name="main_action_1">Downloadmanager</string>
|
||||
<string name="main_action_2">BRouter-App</string>
|
||||
|
||||
<string name="cancel">Abbrechen</string>
|
||||
<string name="i_know">Ich weiß</string>
|
||||
<string name="close">Schließen</string>
|
||||
<string name="exit">Verlassen</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="success">Erfolg</string>
|
||||
<string name="error">Ein Fehler ist aufgetreten</string>
|
||||
|
||||
<string name="title_download">BRouter Downloadmanager</string>
|
||||
<string name="summary_download">*** Achtung:***
|
||||
\n\nDer Downloadmanager wird zum Herunterladen von Routingdaten verwendet
|
||||
die jeweils bis zu 170MB groß sein können. Starten Sie den Downloadmanager
|
||||
nicht auf Mobiltelefonen ohne Mobilfunktdatentarif!
|
||||
Die Downloadgeschwindigkeit ist auf 16 MBit/s begrenzt.</string>
|
||||
<string name="title_timeoutfree">Berechnung ohne Zeitüberschreitung erfolgreich</string>
|
||||
<string name="summary_timeoutfree">Sie haben eine Berechnung erfolgreich wiederholt, bei
|
||||
der zuvor beim Start von Ihrem Karten-Tool aus eine Zeitüberschreitung auftrat.
|
||||
Wenn Sie dieselbe Anfrage von Ihrem Karten-Tool aus wiederholen, mit genau demselben
|
||||
Zielpunkt und einem nahe gelegenen Startpunkt, wird diese Anfrage garantiert nicht abbrechen.</string>
|
||||
<string name="title_sdcard">SD-Karten Verzeichnis wählen:</string>
|
||||
<string name="title_action">Aktion wählen</string>
|
||||
|
||||
<string name="action_via_select">Via-Auswahl prüfen:</string>
|
||||
<string name="action_nogo_select">NoGo-Auswahl prüfen:</string>
|
||||
<string name="action_servermode">Server-Modus</string>
|
||||
<string name="action_info">Info</string>
|
||||
<string name="action_calc_route">Route berechnen</string>
|
||||
<string name="action_profile_settings">Profileinstellungen</string>
|
||||
<string name="action_share">GPX teilen</string>
|
||||
<string name="action_select_from">"Von" wählen</string>
|
||||
<string name="action_select_to">"Nach"/Via wählen</string>
|
||||
|
||||
<string name="msg_no_profile">Keine Profildaten</string>
|
||||
<string name="msg_no_used_profile">, kein verwendetes Profil</string>
|
||||
<string name="msg_too_much_data">Zu viele Daten für den Download. Bitte reduzieren.</string>
|
||||
<string name="msg_download_start">Download geplant. Überprüfen Sie die Internetverbindung, wenn der Download nicht startet.</string>
|
||||
<string name="msg_wpt_selection">aktuelle Wegpunktauswahl:\n</string>
|
||||
<string name="msg_no_wpt_selection">Erwarte Wegpunktauswahl\n</string>
|
||||
<string name="msg_alternative">Alternative</string>
|
||||
<string name="msg_status_result">Version = BRouter-%1$s\n
|
||||
Speicher = %2$s \n
|
||||
Abstand = %3$s km\n
|
||||
gefilterter Aufstieg = %4$s m\n
|
||||
flacher Aufstieg = %5$s m\n
|
||||
geschätzte Zeit = %6$s</string>
|
||||
<string name="msg_read_wpt_error">Fehler beim Lesen von Wegpunkten</string>
|
||||
<string name="msg_no_wpt">Die Koordinatenquelle enthält keine Wegpunkte!</string>
|
||||
<string name="msg_too_much_wpts">Die Koordinatenquelle enthält zu viele Wegpunkte: %1$d (bitte von/nach/via-Namen verwenden)</string>
|
||||
|
||||
<string name="no">Nein</string>
|
||||
<string name="yes">Ja</string>
|
||||
|
||||
<string name="title_delete">Löschen bestätigen</string>
|
||||
<string name="summary_delete">Wirklich löschen?</string>
|
||||
<string name="title_version">Versionsproblem</string>
|
||||
<string name="summary_version">Die Datenversion der Kacheln hat sich geändert. Bitte auswählen:</string>
|
||||
<string name="action_version1">Download fortsetzen und alte Daten löschen?</string>
|
||||
<string name="action_version2">Alle auswählen und Download starten</string>
|
||||
<string name="action_version3">Abbrechen und später fortsetzen</string>
|
||||
<string name="title_version_diff">Versionskonflikt</string>
|
||||
<string name="summary_version_diff">Die Datenversion für einige Kacheln ist unterschiedlich. Bitte auswählen:</string>
|
||||
<string name="action_version_diff1">Download alle unterschiedlichen Kacheln</string>
|
||||
<string name="action_version_diff2">Überspringe alle unterschiedlichen Kacheln</string>
|
||||
<string name="action_version_diff3">Abbrechen und später fortsetzen</string>
|
||||
<string name="summary_new_version">Die neue Datenversion verlangt ein BRouter-Update. Bitte aktualisieren</string>
|
||||
|
||||
<string name="msg_download_failed">Download fehlgeschlagen</string>
|
||||
<string name="msg_download_cancel">Download abgebrochen</string>
|
||||
<string name="msg_download_succeed">Download erfolgreich</string>
|
||||
<string name="msg_download_started">Download läuft…</string>
|
||||
|
||||
</resources>
|
||||
94
brouter-routing-app/src/main/res/values-el/strings.xml
Normal file
94
brouter-routing-app/src/main/res/values-el/strings.xml
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<plurals name="numberOfSegments" tools:ignore="MissingQuantity">
|
||||
<item quantity="one">%d τμήμα</item>
|
||||
<item quantity="other">%d τμήματα</item>
|
||||
</plurals>
|
||||
<string name="cancel_download">Ακύρωση λήψης</string>
|
||||
<string name="import_profile">Εισαγωγή προφίλ</string>
|
||||
<string name="action_download">Λήψη %s</string>
|
||||
<string name="action_delete">Διαγραφή %s</string>
|
||||
<string name="action_update">Ενημέρωση %s</string>
|
||||
<string name="action_select">Επιλογή τμημάτων</string>
|
||||
<string name="action_cancel">Διακοπή λήψης</string>
|
||||
<string name="summary_segments">Μέγεθος=%1$s\nΕλεύθερο=%2$s</string>
|
||||
<string name="notification_title">Λήψη τμημάτων</string>
|
||||
|
||||
<string name="action_choose_folder">Επιλέξτε φάκελο δεδομένων brouter:</string>
|
||||
<string name="action_select_profile">Επιλέξτε ένα προφίλ δρομολόγησης</string>
|
||||
<string name="main_action">Επιλέξτε ενέργεια</string>
|
||||
<string name="main_action_1">Διαχειριστής λήψεων</string>
|
||||
<string name="main_action_2">Εφαρμογή BRouter</string>
|
||||
|
||||
<string name="cancel">Ακύρωση</string>
|
||||
<string name="i_know">Γνωρίζω</string>
|
||||
<string name="close">Κλείσιμο</string>
|
||||
<string name="exit">Έξοδος</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="success">Επιτυχία</string>
|
||||
<string name="error">Παρουσιάστηκε σφάλμα</string>
|
||||
|
||||
<string name="title_download">BRouter διαχειριστής λήψεων</string>
|
||||
<string name="summary_download">*** Προσοχή:***
|
||||
\n\nΟ διαχειριστής λήψεων χρησιμοποιείται για τη λήψη αρχείων δεδομένων δρομολόγησης
|
||||
που μπορεί να είναι έως 170MB το καθένα. Μην ξεκινήσετε το διαχειριστή λήψεων
|
||||
σε σύνδεση δεδομένων κινητής τηλεφωνίας χωρίς πρόγραμμα δεδομένων!
|
||||
Η ταχύτητα λήψης περιορίζεται στα 16 MBit/s.</string>
|
||||
<string name="title_timeoutfree">Ετοιμάστηκε επιτυχώς ένας υπολογισμός χωρίς χρονικό όριο</string>
|
||||
<string name="summary_timeoutfree">Επαναλάβατε με επιτυχία έναν υπολογισμό που πριν είχε χρονικό όριο
|
||||
όταν ξεκίνησε από το εργαλείο χαρτών σας. Εάν επαναλάβετε το ίδιο αίτημα
|
||||
από το εργαλείο χαρτών σας, με τον ίδιο ακριβώς προορισμό και μια κοντινή αφετηρία,
|
||||
αυτό το αίτημα είναι εγγυημένο ότι δεν θα λήξει.</string>
|
||||
<string name="title_sdcard">Εισάγετε φάκελο SDCARD:</string>
|
||||
<string name="title_action">Επιλέξτε ενέργεια</string>
|
||||
|
||||
<string name="action_via_select">Ελέγξτε την επιλογή VIA:</string>
|
||||
<string name="action_nogo_select">Ελέγξτε την επιλογή NoGo:</string>
|
||||
<string name="action_servermode">Λειτουργία διακομιστή</string>
|
||||
<string name="action_info">Πληροφορίες</string>
|
||||
<string name="action_calc_route">Υπολογισμός διαδρομής</string>
|
||||
<string name="action_profile_settings">Ρυθμίσεις προφίλ</string>
|
||||
<string name="action_share">Κοινή χρήση GPX</string>
|
||||
<string name="action_select_from">Επιλέξτε από</string>
|
||||
<string name="action_select_to">Επιλέξτε προς/μέσω</string>
|
||||
|
||||
<string name="msg_no_profile">μη δεδομένα προφίλ</string>
|
||||
<string name="msg_no_used_profile">, μη χρησιμοποιημένο προφίλ</string>
|
||||
<string name="msg_too_much_data">Πάρα πολλά δεδομένα για λήψη. Παρακαλώ μειώστε.</string>
|
||||
<string name="msg_download_start">Προγραμματισμένη λήψη. Ελέγξτε τη σύνδεση στο διαδίκτυο εάν δεν ξεκινά.</string>
|
||||
<string name="msg_wpt_selection">τρέχουσα επιλογή σημείου:\n</string>
|
||||
<string name="msg_no_wpt_selection">Αναμένεται επιλογή σημείου\n</string>
|
||||
<string name="msg_alternative">Εναλλακτική</string>
|
||||
<string name="msg_status_result">έκδοση = BRouter-%1$s \n
|
||||
μνήμη = %2$s \n
|
||||
απόσταση = %3$s km\n
|
||||
φιλτραρισμένη άνοδος = %4$s m\n
|
||||
απλή άνοδος = %5$s m\n
|
||||
εκτιμώμενος χρόνος = %6$s</string>
|
||||
<string name="msg_read_wpt_error">Σφάλμα ανάγνωσης σημείων</string>
|
||||
<string name="msg_no_wpt">η πηγή συντεταγμένων δεν περιέχει σημεία!</string>
|
||||
<string name="msg_too_much_wpts">η πηγή συντεταγμένων περιέχει πάρα πολλά σημεία: %1$d (παρακαλώ χρησιμοποιήστε από/προς/μέσω ονόματα)</string>
|
||||
|
||||
<string name="no">Όχι</string>
|
||||
<string name="yes">Ναι</string>
|
||||
|
||||
<string name="title_delete">Επιβεβαίωση διαγραφής</string>
|
||||
<string name="summary_delete">Να γίνει διαγραφή;</string>
|
||||
<string name="title_version">Πρόβλημα έκδοσης</string>
|
||||
<string name="summary_version">Η βασική έκδοση για τμήματα άλλαξε. Τι να κάνετε;</string>
|
||||
<string name="action_version1">Συνέχεια με την τρέχουσα λήψη, διαγραφή άλλων παλαιών δεδομένων</string>
|
||||
<string name="action_version2">Επιλέξτε όλα για λήψη και έναρξη</string>
|
||||
<string name="action_version3">Ακύρωση τώρα, ολοκλήρωση άλλη μέρα</string>
|
||||
<string name="title_version_diff">Διαφορές έκδοσης</string>
|
||||
<string name="summary_version_diff">Η βασική έκδοση για ορισμένα τμήματα είναι διαφορετική. Τι να κάνετε;</string>
|
||||
<string name="action_version_diff1">Λήψη όλων των διαφορετικών τμημάτων</string>
|
||||
<string name="action_version_diff2">Απόρριψη όλων των διαφορετικών τμημάτων</string>
|
||||
<string name="action_version_diff3">Ακύρωση τώρα, ολοκλήρωση άλλη μέρα</string>
|
||||
<string name="summary_new_version">Η νέα έκδοση δεδομένων χρειάζεται νέα εφαρμογή. Ενημερώστε πρώτα το BRouter</string>
|
||||
|
||||
<string name="msg_download_failed">Η λήψη απέτυχε</string>
|
||||
<string name="msg_download_cancel">Η λήψη ακυρώθηκε</string>
|
||||
<string name="msg_download_succeed">Η λήψη ολοκληρώθηκε</string>
|
||||
<string name="msg_download_started">Λήψη…</string>
|
||||
|
||||
</resources>
|
||||
94
brouter-routing-app/src/main/res/values-es/strings.xml
Normal file
94
brouter-routing-app/src/main/res/values-es/strings.xml
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<plurals name="numberOfSegments" tools:ignore="MissingQuantity">
|
||||
<item quantity="one">%d segmento</item>
|
||||
<item quantity="other">%d segmentos</item>
|
||||
</plurals>
|
||||
<string name="cancel_download">Cancelar descarga</string>
|
||||
<string name="import_profile">Importar perfil</string>
|
||||
<string name="action_download">Descargar %s</string>
|
||||
<string name="action_delete">Eliminar %s</string>
|
||||
<string name="action_update">Actualizar %s</string>
|
||||
<string name="action_select">Seleccionar segmentos</string>
|
||||
<string name="action_cancel">Detener descarga</string>
|
||||
<string name="summary_segments">Tamaño=%1$s\nGratis=%2$s</string>
|
||||
<string name="notification_title">Descargar segmentos</string>
|
||||
|
||||
<string name="action_choose_folder">Seleccionar directorio base brouter:</string>
|
||||
<string name="action_select_profile">Seleccionar un perfil de enrutamiento</string>
|
||||
<string name="main_action">Seleccionar Acción Principal</string>
|
||||
<string name="main_action_1">Gestor de Descargas</string>
|
||||
<string name="main_action_2">App BRouter</string>
|
||||
|
||||
<string name="cancel">Cancelar</string>
|
||||
<string name="i_know">Lo se</string>
|
||||
<string name="close">Cerrar</string>
|
||||
<string name="exit">Salir</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="success">Salir</string>
|
||||
<string name="error">Ha aparecido un error</string>
|
||||
|
||||
<string name="title_download">Gestor de descargas BRouter</string>
|
||||
<string name="summary_download">*** Atención:***
|
||||
\n\nEl Gestor de Descargas se usa para descargar ficheros de datos
|
||||
de ruta, que pueden llegar a los 170 Mb cada uno. No inicies el Gestor
|
||||
desde un terminal sin plan de datos!
|
||||
La velocidad de descarga está limitada a 16 Mbit/s.</string>
|
||||
<string name="title_timeoutfree">Se ha preparado correctamente un cálculo sin límite de tiempo</string>
|
||||
<string name="summary_timeoutfree">Se ha repetido un cálculo a través
|
||||
de la aplicación de mapas que previamente había superado el tiempo de espera.
|
||||
Si repites la misma petición con exactamente el mismo destino y un punto de partida cercano,
|
||||
se garantiza que la petición no agotará el límite de tiempo.</string>
|
||||
<string name="title_sdcard">Introduce el directorio base de la tarjeta SD:</string>
|
||||
<string name="title_action">Seleccionar Acción</string>
|
||||
|
||||
<string name="action_via_select">Comprobar Selección VIA:</string>
|
||||
<string name="action_nogo_select">Comprobar Selección NoGo:</string>
|
||||
<string name="action_servermode">Modo-Servidor</string>
|
||||
<string name="action_info">Info</string>
|
||||
<string name="action_calc_route">Calc Ruta</string>
|
||||
<string name="action_profile_settings">Ajustes del perfil</string>
|
||||
<string name="action_share">Compartir GPX</string>
|
||||
<string name="action_select_from">Seleccionar desde</string>
|
||||
<string name="action_select_to">Seleccionar a/vía</string>
|
||||
|
||||
<string name="msg_no_profile">no hay datos en el perfil</string>
|
||||
<string name="msg_no_used_profile">, ningún perfil utilizado</string>
|
||||
<string name="msg_too_much_data">Demasiados datos a descargar. Por favor, reducidlos.</string>
|
||||
<string name="msg_download_start">Descarga programada. Comprueba la conexión a internet si no se inicia.</string>
|
||||
<string name="msg_wpt_selection">selección actual de waypoint:\n</string>
|
||||
<string name="msg_no_wpt_selection">Esperando selección de waypoint\n</string>
|
||||
<string name="msg_alternative">Alternativa</string>
|
||||
<string name="msg_status_result">versión = BRouter-%1$s \n
|
||||
memoria = %2$s \n
|
||||
distancia = %3$s km\n
|
||||
ascensión filtrada = %4$s m\n
|
||||
ascensión en llano = %5$s m\n
|
||||
tiempo estimado = %6$s</string>
|
||||
<string name="msg_read_wpt_error">Error leyendo waypoints</string>
|
||||
<string name="msg_no_wpt">la fuente de coordenadas no contiene ningún waypoint!</string>
|
||||
<string name="msg_too_much_wpts">la fuente de coordenadas contiene demasiados waypoints: %1$d (por favor, usa nombres desde/a/vía)</string>
|
||||
|
||||
<string name="no">No</string>
|
||||
<string name="yes">Si</string>
|
||||
|
||||
<string name="title_delete">Confirmar Eliminar</string>
|
||||
<string name="summary_delete">¿Quieres realmente eliminar?</string>
|
||||
<string name="title_version">Problema de versión</string>
|
||||
<string name="summary_version">La versión base para as teselas ha cambiado. ¿Qué quieres hacer?</string>
|
||||
<string name="action_version1">Continuar con la descarga, eliminar otros datos antiguos</string>
|
||||
<string name="action_version2">Seleccionar todo para descargar e iniciar</string>
|
||||
<string name="action_version3">Cancelar ahora, completar otro día</string>
|
||||
<string name="title_version_diff">Diferencias de versión</string>
|
||||
<string name="summary_version_diff">La versión base de varias teselas es distinta. ¿Qué quieres hacer?</string>
|
||||
<string name="action_version_diff1">Descargar todas las teselas distintas</string>
|
||||
<string name="action_version_diff2">Descartar las teselas distintas</string>
|
||||
<string name="action_version_diff3">Cancelar ahora, completar otro día</string>
|
||||
<string name="summary_new_version">La nueva versión de datos necesita un aplicación nueva. Por favor, actualiza BRouter primero</string>
|
||||
|
||||
<string name="msg_download_failed">Descarga fallida</string>
|
||||
<string name="msg_download_cancel">Descarga cancelada</string>
|
||||
<string name="msg_download_succeed">Descarga exitosa</string>
|
||||
<string name="msg_download_started">Descargando…</string>
|
||||
|
||||
</resources>
|
||||
94
brouter-routing-app/src/main/res/values-fr/strings.xml
Normal file
94
brouter-routing-app/src/main/res/values-fr/strings.xml
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<plurals name="numberOfSegments" tools:ignore="MissingQuantity">
|
||||
<item quantity="one">%d segment</item>
|
||||
<item quantity="other">%d segments</item>
|
||||
</plurals>
|
||||
<string name="cancel_download">Annuler le téléchargement</string>
|
||||
<string name="import_profile">Importer le profil</string>
|
||||
<string name="action_download">Télécharger %s</string>
|
||||
<string name="action_delete">Supprimer %s</string>
|
||||
<string name="action_update">Mettre à jour %s</string>
|
||||
<string name="action_select">Sélectionner les segments</string>
|
||||
<string name="action_cancel">Arrêter le téléchargement</string>
|
||||
<string name="summary_segments">Taille=%1$s\nGratuit=%2$s</string>
|
||||
<string name="notification_title">Télécharger les segments</string>
|
||||
|
||||
<string name="action_choose_folder">Choisissez le répertoire de la base de données brouter:</string>
|
||||
<string name="action_select_profile">Sélectionnez un profil de routage</string>
|
||||
<string name="main_action">Sélectionner l\'action principale</string>
|
||||
<string name="main_action_1">Gestionnaire de téléchargement</string>
|
||||
<string name="main_action_2">Application BRouter</string>
|
||||
|
||||
<string name="cancel">Annuler</string>
|
||||
<string name="i_know">Je sais</string>
|
||||
<string name="close">Fermer</string>
|
||||
<string name="exit">Quitter</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="success">Succès</string>
|
||||
<string name="error">Une erreur s\'est produite</string>
|
||||
|
||||
<string name="title_download">Gestionnaire de téléchargement BRouter</string>
|
||||
<string name="summary_download">*** Attention :***
|
||||
\n\nLe gestionnaire de téléchargement est utilisé pour télécharger les données de routage
|
||||
fichiers pouvant atteindre 170MB chacun. Ne démarrez pas le gestionnaire de téléchargement
|
||||
sur une connexion de données cellulaires sans forfait de données !
|
||||
La vitesse de téléchargement est limitée à 16 MBit/s.</string>
|
||||
<string name="title_timeoutfree">Préparation réussie d\'un calcul sans délai d\'attente</string>
|
||||
<string name="summary_timeoutfree">Vous avez répété avec succès un calcul qui avait précédemment expiré
|
||||
lorsqu\'il est démarré à partir de votre outil cartographique. Si vous répétez la même demande de votre
|
||||
maptool, avec exactement le même point de destination et un point de départ à proximité,
|
||||
il est garanti que cette requête n\'expirera pas.</string>
|
||||
<string name="title_sdcard">Entrez le répertoire de base de la SDCARD:</string>
|
||||
<string name="title_action">Sélectionner une action</string>
|
||||
|
||||
<string name="action_via_select">Vérifier la sélection VIA:</string>
|
||||
<string name="action_nogo_select">Vérifier la sélection NoGo:</string>
|
||||
<string name="action_servermode">Mode serveur</string>
|
||||
<string name="action_info">Informations</string>
|
||||
<string name="action_calc_route">Calculer l\'itinéraire</string>
|
||||
<string name="action_profile_settings">Paramètres du profil</string>
|
||||
<string name="action_share">Partager GPX</string>
|
||||
<string name="action_select_from">Sélectionner de</string>
|
||||
<string name="action_select_to">Sélectionner vers/via</string>
|
||||
|
||||
<string name="msg_no_profile">aucune donnée de profil</string>
|
||||
<string name="msg_no_used_profile">, aucun profil utilisé</string>
|
||||
<string name="msg_too_much_data">Trop de données à télécharger. Veuillez réduire.</string>
|
||||
<string name="msg_download_start">Téléchargement planifié. Vérifiez la connexion Internet si elle ne démarre pas.</string>
|
||||
<string name="msg_wpt_selection">sélection actuelle du waypoint:\n</string>
|
||||
<string name="msg_no_wpt_selection">Sélection de waypoint en attente\n</string>
|
||||
<string name="msg_alternative">Alternative</string>
|
||||
<string name="msg_status_result">version = BRouter-%1$s \n
|
||||
mémoire = %2$s \n
|
||||
distance = %3$s km\n
|
||||
montée filtrée = %4$s m\n
|
||||
montée simple = %5$s m\n
|
||||
temps estimé = %6$s</string>
|
||||
<string name="msg_read_wpt_error">Erreur lors de la lecture des waypoints</string>
|
||||
<string name="msg_no_wpt">la source de coordonnées ne contient aucun waypoint!</string>
|
||||
<string name="msg_too_much_wpts">la source de coordonnées contient trop de waypoints: %1$d (veuillez utiliser les noms de/vers/via)</string>
|
||||
|
||||
<string name="no">Non</string>
|
||||
<string name="yes">Oui</string>
|
||||
|
||||
<string name="title_delete">Confirmer la suppression</string>
|
||||
<string name="summary_delete">Vraiment supprimer?</string>
|
||||
<string name="title_version">Problème de version</string>
|
||||
<string name="summary_version">La version de base des vignettes a changé. Que faire?</string>
|
||||
<string name="action_version1">Continuer le téléchargement en cours, supprimer les autres anciennes données</string>
|
||||
<string name="action_version2">Sélectionnez tout pour télécharger et démarrer</string>
|
||||
<string name="action_version3">Annuler maintenant, terminer un autre jour</string>
|
||||
<string name="title_version_diff">Différences de version</string>
|
||||
<string name="summary_version_diff">La version de base de certaines vignettes est différente. Que faire?</string>
|
||||
<string name="action_version_diff1">Télécharger toutes les différentes vignettes</string>
|
||||
<string name="action_version_diff2">Supprimez toutes les différentes vignettes</string>
|
||||
<string name="action_version_diff3">Annuler maintenant, terminer un autre jour</string>
|
||||
<string name="summary_new_version">La nouvelle version des données nécessite une nouvelle application. Veuillez d\'abord mettre à jour BRouter</string>
|
||||
|
||||
<string name="msg_download_failed">Téléchargement échoué</string>
|
||||
<string name="msg_download_cancel">Téléchargement annulé</string>
|
||||
<string name="msg_download_succeed">Téléchargement réussi</string>
|
||||
<string name="msg_download_started">Téléchargement…</string>
|
||||
|
||||
</resources>
|
||||
94
brouter-routing-app/src/main/res/values-it/strings.xml
Normal file
94
brouter-routing-app/src/main/res/values-it/strings.xml
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<plurals name="numberOfSegments" tools:ignore="MissingQuantity">
|
||||
<item quantity="one">%d segmento</item>
|
||||
<item quantity="other">%d segmenti</item>
|
||||
</plurals>
|
||||
<string name="cancel_download">Annulla download</string>
|
||||
<string name="import_profile">Importa profilo</string>
|
||||
<string name="action_download">Scarica %s</string>
|
||||
<string name="action_delete">Elimina %s</string>
|
||||
<string name="action_update">Aggiorna %s</string>
|
||||
<string name="action_select">Seleziona segmenti</string>
|
||||
<string name="action_cancel">Interrompi download</string>
|
||||
<string name="summary_segments">Taglia=%1$s\nGratis=%2$s</string>
|
||||
<string name="notification_title">Scarica segmenti</string>
|
||||
|
||||
<string name="action_choose_folder">Seleziona la directory del database brouter:</string>
|
||||
<string name="action_select_profile">Seleziona un profilo di instradamento</string>
|
||||
<string name="main_action">Seleziona azione principale</string>
|
||||
<string name="main_action_1">Gestore dei download</string>
|
||||
<string name="main_action_2">Applicazione BRouter</string>
|
||||
|
||||
<string name="cancel">Annulla</string>
|
||||
<string name="i_know">Lo so</string>
|
||||
<string name="close">Chiudi</string>
|
||||
<string name="exit">Esci</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="success">Successo</string>
|
||||
<string name="error">Si è verificato un errore</string>
|
||||
|
||||
<string name="title_download">Gestore download BRouter</string>
|
||||
<string name="summary_download">*** Attenzione:***
|
||||
\n\nIl Download Manager viene utilizzato per scaricare i dati di routing
|
||||
file che possono pesare fino a 170 MB ciascuno. Non avviare il Download Manager
|
||||
su una connessione dati cellulare senza un piano dati!
|
||||
La velocità di download è limitata a 16 MBit/s.</string>
|
||||
<string name="title_timeoutfree">Preparato con successo un calcolo senza timeout</string>
|
||||
<string name="summary_timeoutfree">Hai ripetuto con successo un calcolo che in precedenza era terminato con un timeout
|
||||
quando avviato dal tuo strumento mappa. Se ripeti la stessa richiesta dal tuo
|
||||
maptool, con lo stesso identico punto di destinazione e un punto di partenza vicino,
|
||||
è garantito che questa richiesta non vada in timeout.</string>
|
||||
<string name="title_sdcard">Inserisci la directory base della SDCARD:</string>
|
||||
<string name="title_action">Seleziona azione</string>
|
||||
|
||||
<string name="action_via_select">Controlla la selezione VIA:</string>
|
||||
<string name="action_nogo_select">Controlla la selezione NoGo:</string>
|
||||
<string name="action_servermode">Modalità server</string>
|
||||
<string name="action_info">Informazioni</string>
|
||||
<string name="action_calc_route">Calcola percorso</string>
|
||||
<string name="action_profile_settings">Impostazioni profilo</string>
|
||||
<string name="action_share">Condividi GPX</string>
|
||||
<string name="action_select_from">Seleziona da</string>
|
||||
<string name="action_select_to">Seleziona a/via</string>
|
||||
|
||||
<string name="msg_no_profile">nessun dato del profilo</string>
|
||||
<string name="msg_no_used_profile">, nessun profilo utilizzato</string>
|
||||
<string name="msg_too_much_data">Troppi dati per il download. Per favore riduci.</string>
|
||||
<string name="msg_download_start">Download programmato. Controlla la connessione Internet se non si avvia.</string>
|
||||
<string name="msg_wpt_selection">selezione del waypoint corrente:\n</string>
|
||||
<string name="msg_no_wpt_selection">Attesa selezione waypoint\n</string>
|
||||
<string name="msg_alternative">Alternativa</string>
|
||||
<string name="msg_status_result">versione = BRouter-%1$s \n
|
||||
memoria = %2$s \n
|
||||
distanza = %3$s km\n
|
||||
salita filtrata = %4$s m\n
|
||||
salita semplice = %5$s m\n
|
||||
tempo stimato = %6$s</string>
|
||||
<string name="msg_read_wpt_error">Errore durante la lettura dei waypoint</string>
|
||||
<string name="msg_no_wpt">la fonte delle coordinate non contiene alcun waypoint!</string>
|
||||
<string name="msg_too_much_wpts">la fonte delle coordinate contiene troppi waypoint: %1$d (usa i nomi da/a/via)</string>
|
||||
|
||||
<string name="no">No</string>
|
||||
<string name="yes">Sì</string>
|
||||
|
||||
<string name="title_delete">Conferma eliminazione</string>
|
||||
<string name="summary_delete">Eliminare davvero?</string>
|
||||
<string name="title_version">Problema di versione</string>
|
||||
<string name="summary_version">La versione base per i riquadri è cambiata. Cosa fare?</string>
|
||||
<string name="action_version1">Continua con il download corrente, elimina altri vecchi dati</string>
|
||||
<string name="action_version2">Seleziona tutto per il download e avvia</string>
|
||||
<string name="action_version3">Annulla ora, completa un altro giorno</string>
|
||||
<string name="title_version_diff">Differenze di versione</string>
|
||||
<string name="summary_version_diff">La versione base di alcuni riquadri è diversa. Cosa fare?</string>
|
||||
<string name="action_version_diff1">Scarica tutti i diversi riquadri</string>
|
||||
<string name="action_version_diff2">Rilascia tutti i diversi riquadri</string>
|
||||
<string name="action_version_diff3">Annulla ora, completa un altro giorno</string>
|
||||
<string name="summary_new_version">La nuova versione dei dati necessita di una nuova app. Per favore aggiorna prima BRouter</string>
|
||||
|
||||
<string name="msg_download_failed">Download fallito</string>
|
||||
<string name="msg_download_cancel">Download annullato</string>
|
||||
<string name="msg_download_succeed">Download riuscito</string>
|
||||
<string name="msg_download_started">Download in corso…</string>
|
||||
|
||||
</resources>
|
||||
94
brouter-routing-app/src/main/res/values-ko/strings.xml
Normal file
94
brouter-routing-app/src/main/res/values-ko/strings.xml
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<plurals name="numberOfSegments" tools:ignore="MissingQuantity">
|
||||
<item quantity="one">%d 구간</item>
|
||||
<item quantity="other">%d 구간</item>
|
||||
</plurals>
|
||||
<string name="cancel_download">다운로드 취소</string>
|
||||
<string name="import_profile">프로필 가져오기</string>
|
||||
<string name="action_download">다운로드 %s</string>
|
||||
<string name="action_delete">삭제 %s</string>
|
||||
<string name="action_update">업데이트 %s</string>
|
||||
<string name="action_select">구간 선택</string>
|
||||
<string name="action_cancel">다운로드 중지</string>
|
||||
<string name="summary_segments">크기=%1$s\n여유=%2$s</string>
|
||||
<string name="notification_title">구간 다운로드</string>
|
||||
|
||||
<string name="action_choose_folder">brouter 데이터 베이스 선택 dir:</string>
|
||||
<string name="action_select_profile">루트 프로필 선택</string>
|
||||
<string name="main_action">주 활동 선택</string>
|
||||
<string name="main_action_1">다운로드 관리자</string>
|
||||
<string name="main_action_2">BRouter 앱</string>
|
||||
|
||||
<string name="cancel">취소</string>
|
||||
<string name="i_know">알고 있습니다</string>
|
||||
<string name="close">가까운</string>
|
||||
<string name="exit">나가기</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="success">성공</string>
|
||||
<string name="error">에러가 발생됐습니다</string>
|
||||
|
||||
<string name="title_download">BRouter 다운로드 관리자</string>
|
||||
<string name="summary_download">*** 주의:***
|
||||
\n\n다운로드 관리자는 라우팅 데이터를 다운로드하는 데 사용됩니다.
|
||||
파일당 최대 170MB까지 가능합니다. 다운로드 관리자를 시작하지 마십시오
|
||||
데이터 요금제 없이 셀룰러 데이터 연결로!
|
||||
다운로드 속도는 16 MBit/s로 제한됩니다.</string>
|
||||
<string name="title_timeoutfree">시간 초과 없는 계산을 성공적으로 준비했습니다</string>
|
||||
<string name="summary_timeoutfree">이전에 시간 초과가 발생한 계산을 성공적으로 반복하셨습니다.
|
||||
지도 도구에서 시작할 때. 귀하가 귀하로부터 동일한 요청을 반복하는 경우
|
||||
정확히 동일한 목적지와 가까운 시작점이 있는 지도 도구,
|
||||
이 요청은 시간 초과되지 않음이 보장됩니다.</string>
|
||||
<string name="title_sdcard">SDCARD 기본 디렉토리 입력:</string>
|
||||
<string name="title_action">작업 선택</string>
|
||||
|
||||
<string name="action_via_select">경유 선택 체크:</string>
|
||||
<string name="action_nogo_select">NoGo 선택 체크:</string>
|
||||
<string name="action_servermode">서버-모드</string>
|
||||
<string name="action_info">정보</string>
|
||||
<string name="action_calc_route">루트 계산</string>
|
||||
<string name="action_profile_settings">프로필 설정</string>
|
||||
<string name="action_share">GPX 공유</string>
|
||||
<string name="action_select_from">~로부터 선택</string>
|
||||
<string name="action_select_to">선택 ~로/경유하여</string>
|
||||
|
||||
<string name="msg_no_profile">프로필 데이터 없음</string>
|
||||
<string name="msg_no_used_profile">, 사용된 프로필 없음</string>
|
||||
<string name="msg_too_much_data">다운로드 하기에 너무 많은 데이터. 줄이도록 하세요.</string>
|
||||
<string name="msg_download_start">다운로드 계획되어 있음. 인터넷 연결 체크 그렇지 않다면 시작.</string>
|
||||
<string name="msg_wpt_selection">현재 장소 선택:\n</string>
|
||||
<string name="msg_no_wpt_selection">장소 선택 기대\n</string>
|
||||
<string name="msg_alternative">대체 가능한</string>
|
||||
<string name="msg_status_result">버전 = BRouter-%1$s \n
|
||||
메모리 = %2$s \n
|
||||
거리 = %3$s km\n
|
||||
필터링된 오름차순 = %4$s m\n
|
||||
일반 오름차순 = %5$s m\n
|
||||
예상 시간 = %6$s</string>
|
||||
<string name="msg_read_wpt_error">장소 읽는데 에러</string>
|
||||
<string name="msg_no_wpt">좌표정보는 어떤 장소도 포함하고 있지 않습니다!</string>
|
||||
<string name="msg_too_much_wpts">좌표정보는 너무 많은 장소를 포함하고 있습니다: %1$d (~로 부터/~로/경유 이름 사용하세요)</string>
|
||||
|
||||
<string name="no">아니요</string>
|
||||
<string name="yes">예</string>
|
||||
|
||||
<string name="title_delete">삭제 확인</string>
|
||||
<string name="summary_delete">정말 삭제하시겠습니까?</string>
|
||||
<string name="title_version">버전 문제</string>
|
||||
<string name="summary_version">타일을 위한 기본 버전이 바뀌었습니다. 무엇을 해야죠?</string>
|
||||
<string name="action_version1">현재 다운로드 계속, 다른 오래된 데이터 삭제</string>
|
||||
<string name="action_version2">다운로드 위해 모두 선택하고 시작</string>
|
||||
<string name="action_version3">지금 취소, 다른 날 완료</string>
|
||||
<string name="title_version_diff">버전 차이</string>
|
||||
<string name="summary_version_diff">어떤 타일을 위한 기본 버전은 다릅니다, 무엇을 해야죠?</string>
|
||||
<string name="action_version_diff1">모든 다른 타일 다운로드</string>
|
||||
<string name="action_version_diff2">모든 다른 타일 백지화</string>
|
||||
<string name="action_version_diff3">지금 취소, 다른 날 완료</string>
|
||||
<string name="summary_new_version">새로운 데이터 버전은 새로운 앱을 필요로 합니다. 우선 BRouter를 업데이트 하세요</string>
|
||||
|
||||
<string name="msg_download_failed">다운로드 실패</string>
|
||||
<string name="msg_download_cancel">다운로드 취소됨</string>
|
||||
<string name="msg_download_succeed">다운로드 성공</string>
|
||||
<string name="msg_download_started">다운로딩…</string>
|
||||
|
||||
</resources>
|
||||
94
brouter-routing-app/src/main/res/values-nl/strings.xml
Normal file
94
brouter-routing-app/src/main/res/values-nl/strings.xml
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<plurals name="numberOfSegments" tools:ignore="MissingQuantity">
|
||||
<item quantity="one">%d segment</item>
|
||||
<item quantity="other">%d segmenten</item>
|
||||
</plurals>
|
||||
<string name="cancel_download">Download annuleren</string>
|
||||
<string name="import_profile">Profiel importeren</string>
|
||||
<string name="action_download">Downloaden %s</string>
|
||||
<string name="action_delete">Verwijderen %s</string>
|
||||
<string name="action_update">Bijwerken %s</string>
|
||||
<string name="action_select">Segmenten selecteren</string>
|
||||
<string name="action_cancel">Download stoppen</string>
|
||||
<string name="summary_segments">Grootte=%1$s\nGratis=%2$s</string>
|
||||
<string name="notification_title">Segmenten downloaden</string>
|
||||
|
||||
<string name="action_choose_folder">Kies de brouter database map:</string>
|
||||
<string name="action_select_profile">Selecteer een routingprofiel</string>
|
||||
<string name="main_action">Selecteer de hoofdactie</string>
|
||||
<string name="main_action_1">Download beheerder</string>
|
||||
<string name="main_action_2">BRouter App</string>
|
||||
|
||||
<string name="cancel">Annuleer</string>
|
||||
<string name="i_know">Ik weet het</string>
|
||||
<string name="close">Sluiten</string>
|
||||
<string name="exit">Verlaat</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="success">Succes</string>
|
||||
<string name="error">Er is een fout opgetreden</string>
|
||||
|
||||
<string name="title_download">BRouter Download Manager</string>
|
||||
<string name="summary_download">*** OPgelet:***
|
||||
\n\nDe Download Manager wordt gebruikt voor het downloaden van routing-gegevens
|
||||
bestanden die elk maximaal 170 MB groot kunnen zijn. Start de Download Manager
|
||||
niet op een mobiele dataverbinding zonder data-abonnement!
|
||||
De downloadsnelheid is beperkt tot 16 MBit/s.</string>
|
||||
<string name="title_timeoutfree">Een time-outvrije berekening is succesvol voorbereid</string>
|
||||
<string name="summary_timeoutfree">Je hebt met succes een berekening herhaald die eerder op een time-out
|
||||
stuitte toen deze vanuit je map tool werd gestart. Als u hetzelfde verzoek herhaalt
|
||||
vanuit uw map tool, met exact hetzelfde bestemmingspunt en een dichtbijgelegen beginpunt,
|
||||
zal deze aanvraag gegarandeerd geen time-out krijgen.</string>
|
||||
<string name="title_sdcard">De SDCARD basis directory invoeren:</string>
|
||||
<string name="title_action">Actie selecteren</string>
|
||||
|
||||
<string name="action_via_select">Controleer de VIA selectie:</string>
|
||||
<string name="action_nogo_select">Controleer de NoGo selectie:</string>
|
||||
<string name="action_servermode">Server-mode</string>
|
||||
<string name="action_info">Info</string>
|
||||
<string name="action_calc_route">Bereken route</string>
|
||||
<string name="action_profile_settings">Profiel instellingen</string>
|
||||
<string name="action_share">GPX delen</string>
|
||||
<string name="action_select_from">Selecteer van</string>
|
||||
<string name="action_select_to">Selecteer naar/via</string>
|
||||
|
||||
<string name="msg_no_profile">geen profiel data</string>
|
||||
<string name="msg_no_used_profile">, geen gebruikt profiel</string>
|
||||
<string name="msg_too_much_data">Te veel gegevens om te downloaden. Verminder a.u.b.</string>
|
||||
<string name="msg_download_start">Download is gepland. Controleer de internetverbinding als deze niet start.</string>
|
||||
<string name="msg_wpt_selection">huidige waypointselectie:\n</string>
|
||||
<string name="msg_no_wpt_selection">Verwacht waypointselectie\n</string>
|
||||
<string name="msg_alternative">Alternatief</string>
|
||||
<string name="msg_status_result">versie = BRouter-%1$s \n
|
||||
geheugen = %2$s \n
|
||||
afstand = %3$s km\n
|
||||
gefilterde opstijging = %4$s m\n
|
||||
simpel opstijging = %5$s m\n
|
||||
geschatte tijd = %6$s</string>
|
||||
<string name="msg_read_wpt_error">Fout bij het lezen van waypoints</string>
|
||||
<string name="msg_no_wpt">coördinaten bron bevat geen waypoints!</string>
|
||||
<string name="msg_too_much_wpts">De coördinatenbron bevat te veel waypoints: %1$d (gebruik van/naar/via namen)</string>
|
||||
|
||||
<string name="no">Nee</string>
|
||||
<string name="yes">Ja</string>
|
||||
|
||||
<string name="title_delete">Verwijderen bevestigen</string>
|
||||
<string name="summary_delete">Echt verwijderen?</string>
|
||||
<string name="title_version">Versie probleem</string>
|
||||
<string name="summary_version">De basisversie voor de tegels is gewijzigd. Wat moet er gebeuren?</string>
|
||||
<string name="action_version1">Doorgaan met de huidige download, verwijder de oude gegevens.</string>
|
||||
<string name="action_version2">Selecteer alles om te downloaden en start</string>
|
||||
<string name="action_version3">Annuleer nu, voltooi op een andere dag</string>
|
||||
<string name="title_version_diff">Versieverschillen</string>
|
||||
<string name="summary_version_diff">De basisversie voor sommige tiles is anders. Wat moet er gebeuren?</string>
|
||||
<string name="action_version_diff1">Download alle verschillende tegels</string>
|
||||
<string name="action_version_diff2">Laat alle verschillende tegels vallen</string>
|
||||
<string name="action_version_diff3">Annuleer nu, en voltooi op een andere dag</string>
|
||||
<string name="summary_new_version">Voor de nieuwe gegevensversie is een nieuwe app nodig. Update eerst de BRouter</string>
|
||||
|
||||
<string name="msg_download_failed">Download is mislukt</string>
|
||||
<string name="msg_download_cancel">Download is geannuleerd</string>
|
||||
<string name="msg_download_succeed">Download is geslaagd</string>
|
||||
<string name="msg_download_started">Downloaden…</string>
|
||||
|
||||
</resources>
|
||||
94
brouter-routing-app/src/main/res/values-pl/strings.xml
Normal file
94
brouter-routing-app/src/main/res/values-pl/strings.xml
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<plurals name="numberOfSegments" tools:ignore="MissingQuantity">
|
||||
<item quantity="one">%d segment</item>
|
||||
<item quantity="other">%d segmenty/ów</item>
|
||||
</plurals>
|
||||
<string name="cancel_download">Anuluj pobieranie</string>
|
||||
<string name="import_profile">Importuj profil</string>
|
||||
<string name="action_download">Pobierz %s</string>
|
||||
<string name="action_delete">Usuń %s</string>
|
||||
<string name="action_update">Zaktualizuj %s</string>
|
||||
<string name="action_select">Wybierz segmenty</string>
|
||||
<string name="action_cancel">Zatrzymaj pobieranie</string>
|
||||
<string name="summary_segments">Rozmiar=%1$s\nDostępne=%2$s</string>
|
||||
<string name="notification_title">Pobieranie segmentów</string>
|
||||
|
||||
<string name="action_choose_folder">Wybierz katalog bazy danych BRoutera:</string>
|
||||
<string name="action_select_profile">Wybierz profil routingu</string>
|
||||
<string name="main_action">Wybierz akcję główną</string>
|
||||
<string name="main_action_1">Menedżer pobierania</string>
|
||||
<string name="main_action_2">Aplikacja BRouter</string>
|
||||
|
||||
<string name="cancel">Anuluj</string>
|
||||
<string name="i_know">Rozumiem</string>
|
||||
<string name="close">Zamknij</string>
|
||||
<string name="exit">Wyjdź</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="success">Sukces</string>
|
||||
<string name="error">Wystąpił błąd</string>
|
||||
|
||||
<string name="title_download">Menedżer pobierania BRoutera</string>
|
||||
<string name="summary_download">*** Uwaga: ***
|
||||
\n\nMenedżer pobierania służy do pobierania plików danych routingu,
|
||||
które mogą mieć do 170 MB każdy. Nie uruchamiaj Menedżera pobierania,
|
||||
jeżeli korzystasz z komórkowej transmisji danych bez planu taryfowego!
|
||||
Prędkość pobierania jest ograniczona do 16 MBit/s.</string>
|
||||
<string name="title_timeoutfree">Pomyślnie przygotowano obliczenia nie przekraczając limitu czasu</string>
|
||||
<string name="summary_timeoutfree">Pomyślnie powtórzono obliczenia, które wcześniej przekroczyły limit czasu
|
||||
po uruchomieniu z narzędzia mapowego. Jeśli powtórzysz to samo żądanie ze swojego
|
||||
narzędzia mapowego, z dokładnie tym samym punktem docelowym i pobliskim punktem początkowym,
|
||||
gwarantuję, że to żądanie nie przekroczy limitu czasu.</string>
|
||||
<string name="title_sdcard">Wybierz katalog SDCARD dla bazy:</string>
|
||||
<string name="title_action">Wybierz akcję</string>
|
||||
|
||||
<string name="action_via_select">Sprawdź wybór VIA:</string>
|
||||
<string name="action_nogo_select">Sprawdź wybór NoGo:</string>
|
||||
<string name="action_servermode">Tryb serwera</string>
|
||||
<string name="action_info">Informacje</string>
|
||||
<string name="action_calc_route">Oblicz trasę</string>
|
||||
<string name="action_profile_settings">Ustawienia profilu</string>
|
||||
<string name="action_share">Udostępnij GPX</string>
|
||||
<string name="action_select_from">Wybierz z</string>
|
||||
<string name="action_select_to">Wybierz do/przez</string>
|
||||
|
||||
<string name="msg_no_profile">brak danych profilu</string>
|
||||
<string name="msg_no_used_profile">, brak używanego profilu</string>
|
||||
<string name="msg_too_much_data">Za dużo danych do pobrania. Proszę ogranicz.</string>
|
||||
<string name="msg_download_start">Pobieranie zaplanowane. Jeśli się nie rozpocznie, sprawdź połączenie internetowe.</string>
|
||||
<string name="msg_wpt_selection">bieżący wybór punktu trasy:\n</string>
|
||||
<string name="msg_no_wpt_selection">Oczekuję na wybór punktu trasy\n</string>
|
||||
<string name="msg_alternative">Alternatywa</string>
|
||||
<string name="msg_status_result">wersja = BRouter-%1$s \n
|
||||
pamięć = %2$s \n
|
||||
odległość = %3$s km\n
|
||||
filtrowane wznoszenie = %4$sm\n
|
||||
zwykłe wznoszenie = %5$sm\n
|
||||
szacowany czas = %6$s</string>
|
||||
<string name="msg_read_wpt_error">Błąd podczas odczytu punktów trasy</string>
|
||||
<string name="msg_no_wpt">Źródło współrzędnych nie zawiera żadnych punktów trasy!</string>
|
||||
<string name="msg_too_much_wpts">Źródło współrzędnych zawiera zbyt dużo punktów trasy: %1$d (proszę używać nazw z/do/przez)</string>
|
||||
|
||||
<string name="no">Nie</string>
|
||||
<string name="yes">Tak</string>
|
||||
|
||||
<string name="title_delete">Potwierdź usunięcie</string>
|
||||
<string name="summary_delete">Naprawdę usunąć?</string>
|
||||
<string name="title_version">Problem z wersją</string>
|
||||
<string name="summary_version">Zmieniła się podstawowa wersja kafelków. Co robić?</string>
|
||||
<string name="action_version1">Kontynuuj bieżące pobieranie, usuń inne stare dane</string>
|
||||
<string name="action_version2">Wybierz wszystko i rozpocznij pobieranie</string>
|
||||
<string name="action_version3">Anuluj teraz, dokończ innego dnia</string>
|
||||
<string name="title_version_diff">Różnice wersji</string>
|
||||
<string name="summary_version_diff">Wersja podstawowa dla niektórych kafelków jest inna. Co robić?</string>
|
||||
<string name="action_version_diff1">Pobierz różne kafelki</string>
|
||||
<string name="action_version_diff2">Opuść wszystkie różne kafelki</string>
|
||||
<string name="action_version_diff3">Anuluj teraz, dokończ innego dnia</string>
|
||||
<string name="summary_new_version">Nowa wersja danych wymaga nowej aplikacji. Najpierw zaktualizuj BRoutera</string>
|
||||
|
||||
<string name="msg_download_failed">Pobieranie nie powiodło się</string>
|
||||
<string name="msg_download_cancel">Pobieranie anulowane</string>
|
||||
<string name="msg_download_succeed">Pobieranie powiodło się</string>
|
||||
<string name="msg_download_started">Pobieranie…</string>
|
||||
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">BRouter</string>
|
||||
<string name="profile_filename_example">filename.brf</string>
|
||||
<string name="notification_channel_id">brouter_download</string>
|
||||
<string name="channel_name">Downloads</string>
|
||||
</resources>
|
||||
|
|
@ -1,37 +1,95 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<plurals name="numberOfSegments">
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<plurals name="numberOfSegments" tools:ignore="MissingQuantity">
|
||||
<item quantity="one">%d segment</item>
|
||||
<item quantity="other">%d segments</item>
|
||||
</plurals>
|
||||
<string name="app_name">BRouter</string>
|
||||
<string name="cancel_download">Cancel Download</string>
|
||||
<string name="import_profile">Import Profile</string>
|
||||
<string name="profile_filename_example">filename.brf</string>
|
||||
<string name="download_info_start">Starting download…</string>
|
||||
<string name="download_info_cancel">Cancelling…</string>
|
||||
<string name="cancel_download">Cancel download</string>
|
||||
<string name="import_profile">Import profile</string>
|
||||
<string name="action_download">Download %s</string>
|
||||
<string name="action_delete">Delete %s</string>
|
||||
<string name="action_update">Update %s</string>
|
||||
<string name="action_select">Select segments</string>
|
||||
<string name="action_cancel">Stop Download</string>
|
||||
<string name="summary_segments">Size=%s\nFree=%s</string>
|
||||
<string name="notification_channel_id">brouter_download</string>
|
||||
<string name="notification_title">Download Segments</string>
|
||||
<string name="channel_name">Downloads</string>
|
||||
<string name="action_cancel">Stop download</string>
|
||||
<string name="summary_segments">Size=%1$s\nFree=%2$s</string>
|
||||
<string name="notification_title">Download segments</string>
|
||||
|
||||
<string name="action_choose_folder">Choose brouter data base dir:</string>
|
||||
<string name="action_select_profile">Select a routing profile</string>
|
||||
<string name="main_action">Select Main Action</string>
|
||||
<string name="main_action_1">Download Manager</string>
|
||||
<string name="main_action_2">BRouter App</string>
|
||||
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="i_know">I know</string>
|
||||
<string name="close">Close</string>
|
||||
<string name="exit">Exit</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="success">Success</string>
|
||||
<string name="error">An Error occurred</string>
|
||||
|
||||
<string name="title_download">BRouter Download Manager</string>
|
||||
<string name="summary_download">*** Attention:***
|
||||
\n\nThe Download Manager is used to download routing-data
|
||||
files which can be up to 170MB each. Do not start the Download Manager
|
||||
on a cellular data connection without a data plan!
|
||||
Download speed is restricted to 16 MBit/s.</string>
|
||||
<string name="title_timeoutfree">Successfully prepared a timeout-free calculation</string>
|
||||
<string name="summary_timeoutfree">You successfully repeated a calculation that previously run into a timeout
|
||||
when started from your map tool. If you repeat the same request from your
|
||||
map tool, with the exact same destination point and a close-by starting point,
|
||||
this request is guaranteed not to time out.</string>
|
||||
<string name="title_sdcard">Enter SDCARD base dir:</string>
|
||||
<string name="title_action">Select Action</string>
|
||||
|
||||
<string name="action_via_select">Check VIA Selection:</string>
|
||||
<string name="action_nogo_select">Check NoGo Selection:</string>
|
||||
<string name="action_servermode">Server-Mode</string>
|
||||
<string name="action_info">Info</string>
|
||||
<string name="action_calc_route">Calc Route</string>
|
||||
<string name="action_profile_settings">Profile Settings</string>
|
||||
<string name="action_share">Share GPX</string>
|
||||
<string name="action_select_from">Select from</string>
|
||||
<string name="action_select_to">Select to/via</string>
|
||||
|
||||
<string name="msg_no_profile">no profile data</string>
|
||||
<string name="msg_no_used_profile">, no used profile</string>
|
||||
<string name="msg_too_much_data">Too much data for download. Please reduce.</string>
|
||||
<string name="msg_download_start">Download scheduled. Check internet connection if it doesn\'t start.</string>
|
||||
<string name="msg_wpt_selection">current waypoint selection:\n</string>
|
||||
<string name="msg_no_wpt_selection">Expecting waypoint selection\n</string>
|
||||
<string name="msg_alternative">Alternative</string>
|
||||
<string name="msg_status_result">version = BRouter-%1$s \n
|
||||
mem = %2$s \n
|
||||
distance = %3$s km\n
|
||||
filtered ascend = %4$s m\n
|
||||
plain ascend = %5$s m\n
|
||||
estimated time = %6$s</string>
|
||||
<string name="msg_read_wpt_error">Error reading waypoints</string>
|
||||
<string name="msg_no_wpt">coordinate source does not contain any waypoints!</string>
|
||||
<string name="msg_too_much_wpts">coordinate source contains too much waypoints: %1$d (please use from/to/via names)</string>
|
||||
|
||||
<string name="no">No</string>
|
||||
<string name="yes">Yes</string>
|
||||
|
||||
<string name="title_delete">Confirm Delete</string>
|
||||
<string name="summary_delete">Really delete?</string>
|
||||
<string name="title_version">Version Problem</string>
|
||||
<string name="summary_version">The base version for tiles has changed. What to do?</string>
|
||||
<string name="action_version1">Continue with current download, delete other old data</string>
|
||||
<string name="action_version2">Select all for download and start</string>
|
||||
<string name="action_version3">Cancel now, complete on another day</string>
|
||||
<string name="title_version_diff">Version Differences</string>
|
||||
<string name="summary_version_diff">The base version for some tiles is different. What to do?</string>
|
||||
<string name="action_version_diff1">Download all different tiles</string>
|
||||
<string name="action_version_diff2">Drop all different tiles</string>
|
||||
<string name="action_version_diff3">Cancel now, complete on another day</string>
|
||||
<string name="summary_new_version">The new data version needs a new app. Please update BRouter first</string>
|
||||
|
||||
<string name="msg_download_failed">Download failed</string>
|
||||
<string name="msg_download_cancel">Download cancelled</string>
|
||||
<string name="msg_download_succeed">Download succeeded</string>
|
||||
<string name="msg_download_started">Downloading…</string>
|
||||
|
||||
|
||||
</resources>
|
||||
|
|
|
|||
1
brouter-server/.gitignore
vendored
1
brouter-server/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
/build/
|
||||
|
|
@ -1,13 +1,10 @@
|
|||
plugins {
|
||||
id 'application'
|
||||
id 'brouter.application-conventions'
|
||||
}
|
||||
|
||||
|
||||
application {
|
||||
mainClass.set('btools.server.BRouter')
|
||||
|
||||
distTar.enabled = false
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
attributes "Main-Class": getMainClass(), "Implementation-Version": project.version
|
||||
|
|
@ -35,6 +32,7 @@ application {
|
|||
|
||||
distZip {
|
||||
dependsOn fatJar
|
||||
if (file('../local.properties').exists()) dependsOn (':brouter-routing-app:assemble')
|
||||
archiveFileName = 'brouter-' + project.version + '.zip'
|
||||
}
|
||||
|
||||
|
|
@ -77,6 +75,5 @@ dependencies {
|
|||
implementation project(':brouter-mapaccess')
|
||||
implementation project(':brouter-util')
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
testImplementation 'org.json:json:20180813'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,60 +1,48 @@
|
|||
package btools.server;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.io.File;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import btools.router.OsmNodeNamed;
|
||||
import btools.router.OsmTrack;
|
||||
import btools.router.RoutingContext;
|
||||
import btools.router.RoutingEngine;
|
||||
import btools.router.SearchBoundary;
|
||||
import btools.router.RoutingParamCollector;
|
||||
|
||||
public class BRouter {
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length == 2) { // cgi-input-mode
|
||||
if (args.length == 3 || args.length == 4) { // cgi-input-mode
|
||||
try {
|
||||
String queryString = args[1];
|
||||
int sepIdx = queryString.indexOf('=');
|
||||
if (sepIdx >= 0) queryString = queryString.substring(sepIdx + 1);
|
||||
System.setProperty("segmentBaseDir", args[0]);
|
||||
System.setProperty("profileBaseDir", args[1]);
|
||||
String queryString = args[2];
|
||||
|
||||
queryString = URLDecoder.decode(queryString, "ISO-8859-1");
|
||||
int ntokens = 1;
|
||||
for (int ic = 0; ic < queryString.length(); ic++) {
|
||||
if (queryString.charAt(ic) == '_') ntokens++;
|
||||
}
|
||||
String[] a2 = new String[ntokens + 1];
|
||||
int idx = 1;
|
||||
int pos = 0;
|
||||
for (; ; ) {
|
||||
int p = queryString.indexOf('_', pos);
|
||||
if (p < 0) {
|
||||
a2[idx++] = queryString.substring(pos);
|
||||
break;
|
||||
}
|
||||
a2[idx++] = queryString.substring(pos, p);
|
||||
pos = p + 1;
|
||||
|
||||
int lonIdx = queryString.indexOf("lonlats=");
|
||||
int sepIdx = queryString.indexOf("&", lonIdx);
|
||||
String lonlats = queryString.substring(lonIdx + 8, sepIdx);
|
||||
|
||||
RoutingContext rc = new RoutingContext();
|
||||
RoutingParamCollector routingParamCollector = new RoutingParamCollector();
|
||||
List<OsmNodeNamed> wplist = routingParamCollector.getWayPointList(lonlats);
|
||||
|
||||
Map<String, String> 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();
|
||||
OsmNodeNamed from = readPosition(a2, 1, "from");
|
||||
OsmNodeNamed to = readPosition(a2, 3, "to");
|
||||
|
||||
|
||||
int airDistance = from.calcDistance(to);
|
||||
|
||||
String airDistanceLimit = System.getProperty("airDistanceLimit");
|
||||
if (airDistanceLimit != null) {
|
||||
int maxKm = Integer.parseInt(airDistanceLimit);
|
||||
if (airDistance > maxKm * 1000) {
|
||||
System.out.println("airDistance " + (airDistance / 1000) + "km exceeds limit for online router (" + maxKm + "km)");
|
||||
return;
|
||||
}
|
||||
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
|
||||
|
|
@ -63,11 +51,7 @@ public class BRouter {
|
|||
maxRunningTime = Integer.parseInt(sMaxRunningTime) * 1000;
|
||||
}
|
||||
|
||||
List<OsmNodeNamed> wplist = new ArrayList<>();
|
||||
wplist.add(from);
|
||||
wplist.add(to);
|
||||
|
||||
RoutingEngine re = new RoutingEngine(null, null, new File(args[0]), wplist, readRoutingContext(a2));
|
||||
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());
|
||||
|
|
@ -78,66 +62,57 @@ public class BRouter {
|
|||
System.exit(0);
|
||||
}
|
||||
System.out.println("BRouter " + OsmTrack.version + " / " + OsmTrack.versionDate);
|
||||
if (args.length < 6) {
|
||||
if (args.length < 5) {
|
||||
System.out.println("Find routes in an OSM map");
|
||||
System.out.println("usage: java -jar brouter.jar <segmentdir> <lon-from> <lat-from> <lon-to> <lat-to> <profile>");
|
||||
return;
|
||||
System.out.println("usage: java -jar brouter.jar <segmentdir> <profiledir> <engineMode> <profile> <lonlats-list> [parameter-list] [profile-parameter-list] ");
|
||||
System.out.println(" or: java -cp %CLASSPATH% btools.server.BRouter <segmentdir>> <profiledir> <engineMode> <profile> <lonlats-list> [parameter-list] [profile-parameter-list]");
|
||||
System.out.println(" or: java -jar brouter.jar <segmentdir> <profiledir> <parameter-list> [output-filename]");
|
||||
System.exit(0);
|
||||
}
|
||||
List<OsmNodeNamed> wplist = new ArrayList<>();
|
||||
wplist.add(readPosition(args, 1, "from"));
|
||||
RoutingEngine re = null;
|
||||
if ("seed".equals(args[3])) {
|
||||
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)));
|
||||
int engineMode = 0;
|
||||
try {
|
||||
engineMode = Integer.parseInt(args[2]);
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
RoutingParamCollector routingParamCollector = new RoutingParamCollector();
|
||||
List<OsmNodeNamed> 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<String, String> params = routingParamCollector.getUrlParams(moreParams);
|
||||
routingParamCollector.setParams(rc, wplist, params);
|
||||
}
|
||||
if (profileParams != null) {
|
||||
Map<String, String> 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);
|
||||
}
|
||||
dos.close();
|
||||
} else {
|
||||
wplist.add(readPosition(args, 3, "to"));
|
||||
RoutingContext rc = readRoutingContext(args);
|
||||
re = new RoutingEngine("mytrack", "mylog", new File(args[0]), wplist, rc);
|
||||
re.doRun(0);
|
||||
|
||||
}
|
||||
if (re.getErrorMessage() != null) {
|
||||
System.out.println(re.getErrorMessage());
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
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]));
|
||||
}
|
||||
}
|
||||
c.memoryclass = (int) (Runtime.getRuntime().maxMemory() / 1024 / 1024);
|
||||
// c.startDirection= Integer.valueOf( 150 );
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ public class IpAccessMonitor {
|
|||
synchronized (sync) {
|
||||
Long lastTime = ipAccess.get(ip);
|
||||
ipAccess.put(ip, t);
|
||||
return lastTime == null || t - lastTime.longValue() > MAX_IDLE;
|
||||
return lastTime == null || t - lastTime > MAX_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -31,9 +31,9 @@ public class IpAccessMonitor {
|
|||
}
|
||||
|
||||
private static void cleanup(long t) {
|
||||
HashMap<String, Long> newMap = new HashMap<>(ipAccess.size());
|
||||
Map<String, Long> newMap = new HashMap<>(ipAccess.size());
|
||||
for (Map.Entry<String, Long> e : ipAccess.entrySet()) {
|
||||
if (t - e.getValue().longValue() <= MAX_IDLE) {
|
||||
if (t - e.getValue() <= MAX_IDLE) {
|
||||
newMap.put(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package btools.server;
|
|||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class Polygon {
|
||||
|
|
@ -15,7 +16,7 @@ public class Polygon {
|
|||
private int maxy = Integer.MIN_VALUE;
|
||||
|
||||
public Polygon(BufferedReader br) throws IOException {
|
||||
ArrayList<String> lines = new ArrayList<>();
|
||||
List<String> lines = new ArrayList<>();
|
||||
|
||||
for (; ; ) {
|
||||
String line = br.readLine();
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
|
|
@ -29,6 +30,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;
|
||||
|
|
@ -57,7 +59,7 @@ public class RouteServer extends Thread implements Comparable<RouteServer> {
|
|||
if (e != null) e.terminate();
|
||||
}
|
||||
|
||||
private static DateFormat tsFormat = new SimpleDateFormat("dd.MM.yy HH:mm", new Locale("en", "US"));
|
||||
private static DateFormat tsFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", new Locale("en", "US"));
|
||||
|
||||
private static String formattedTimeStamp(long t) {
|
||||
synchronized (tsFormat) {
|
||||
|
|
@ -146,7 +148,9 @@ public class RouteServer extends Thread implements Comparable<RouteServer> {
|
|||
}
|
||||
|
||||
String url = getline.split(" ")[1];
|
||||
Map<String, String> params = getUrlParams(url);
|
||||
|
||||
RoutingParamCollector routingParamCollector = new RoutingParamCollector();
|
||||
Map<String, String> params = routingParamCollector.getUrlParams(url);
|
||||
|
||||
long maxRunningTime = getMaxRunningTime();
|
||||
|
||||
|
|
@ -186,33 +190,21 @@ public class RouteServer extends Thread implements Comparable<RouteServer> {
|
|||
return;
|
||||
}
|
||||
RoutingContext rc = handler.readRoutingContext();
|
||||
List<OsmNodeNamed> wplist = handler.readWayPointList();
|
||||
List<OsmNodeNamed> wplist = routingParamCollector.getWayPointList(params.get("lonlats"));
|
||||
|
||||
if (wplist.size() < 10) {
|
||||
SuspectManager.nearRecentWps.add(wplist);
|
||||
}
|
||||
int engineMode = 0;
|
||||
for (Map.Entry<String, String> 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("profile")) {
|
||||
// already handled in readRoutingContext
|
||||
params.remove("profile");
|
||||
}
|
||||
int engineMode = 0;
|
||||
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 +216,29 @@ public class RouteServer extends Thread implements Comparable<RouteServer> {
|
|||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -297,7 +300,7 @@ public class RouteServer extends Thread implements Comparable<RouteServer> {
|
|||
|
||||
ProfileCache.setSize(2 * maxthreads);
|
||||
|
||||
PriorityQueue<RouteServer> threadQueue = new PriorityQueue<>();
|
||||
Queue<RouteServer> threadQueue = new PriorityQueue<>();
|
||||
|
||||
ServerSocket serverSocket = args.length > 5 ? new ServerSocket(Integer.parseInt(args[3]), 100, InetAddress.getByName(args[5])) : new ServerSocket(Integer.parseInt(args[3]));
|
||||
|
||||
|
|
@ -362,7 +365,7 @@ public class RouteServer extends Thread implements Comparable<RouteServer> {
|
|||
|
||||
|
||||
private static Map<String, String> getUrlParams(String url) throws UnsupportedEncodingException {
|
||||
HashMap<String, String> params = new HashMap<>();
|
||||
Map<String, String> params = new HashMap<>();
|
||||
String decoded = URLDecoder.decode(url, "UTF-8");
|
||||
StringTokenizer tk = new StringTokenizer(decoded, "?&");
|
||||
while (tk.hasMoreTokens()) {
|
||||
|
|
@ -415,7 +418,7 @@ public class RouteServer extends Thread implements Comparable<RouteServer> {
|
|||
bw.write("\n");
|
||||
}
|
||||
|
||||
private static void cleanupThreadQueue(PriorityQueue<RouteServer> threadQueue) {
|
||||
private static void cleanupThreadQueue(Queue<RouteServer> threadQueue) {
|
||||
for (; ; ) {
|
||||
boolean removedItem = false;
|
||||
for (RouteServer t : threadQueue) {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue