brouter/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java
2023-12-11 14:02:45 +01:00

979 lines
32 KiB
Java

package btools.routingapp;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import btools.expressions.BExpressionMetaData;
import btools.mapaccess.OsmNode;
import btools.router.OsmNodeNamed;
import btools.router.OsmNogoPolygon;
import btools.router.OsmNogoPolygon.Point;
import btools.router.OsmTrack;
import btools.router.RoutingContext;
import btools.router.RoutingEngine;
import btools.router.RoutingHelper;
import btools.util.CheapRuler;
public class BRouterView extends View {
private final int memoryClass;
RoutingEngine cr;
private int imgw;
private int imgh;
private int centerLon;
private int centerLat;
private double scaleLon; // ilon -> pixel
private double scaleLat; // ilat -> pixel
private double scaleMeter2Pixel;
private List<OsmNodeNamed> wpList;
private List<OsmNodeNamed> nogoList;
private List<OsmNodeNamed> nogoVetoList;
private OsmTrack rawTrack;
private File retryBaseDir;
private File modesDir;
private File tracksDir;
private File segmentDir;
private File profileDir;
private String profileName;
private boolean waitingForSelection = false;
private boolean waitingForMigration = false;
private String rawTrackPath;
private String oldMigrationPath;
private String trackOutfile;
private boolean needsViaSelection;
private boolean needsNogoSelection;
private boolean needsWaypointSelection;
private long lastDataTime = System.currentTimeMillis();
private CoordinateReader cor;
private int[] imgPixels;
private long lastTs = System.currentTimeMillis();
private long startTime = 0L;
public BRouterView(Context context, int memoryClass) {
super(context);
this.memoryClass = memoryClass;
}
public void stopRouting() {
if (cr != null) cr.terminate();
}
public void init(boolean silent) {
try {
// get base dir from private file
File baseDir = ConfigHelper.getBaseDir(getContext());
// check if valid
boolean bdValid = false;
if (baseDir != null) {
bdValid = baseDir.isDirectory();
File brd = new File(baseDir, "brouter");
if (brd.isDirectory()) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q &&
!brd.getAbsolutePath().contains("/Android/media/btools.routingapp")) {
// don't ask twice
String version = "v" + getContext().getString(R.string.app_version);
File vFile = new File(brd, "profiles2/" + version);
if (vFile.exists()) {
startSetup(baseDir, false, silent);
return;
}
String message = "(previous basedir " + baseDir + " has to migrate )";
((BRouterActivity) getContext()).selectBasedir(((BRouterActivity) getContext()).getStorageDirectories(), message);
waitingForSelection = true;
waitingForMigration = true;
oldMigrationPath = brd.getAbsolutePath();
} else {
startSetup(baseDir, false, silent);
}
return;
}
}
String message = baseDir == null ? "(no basedir configured previously)" : "(previous basedir " + baseDir
+ (bdValid ? " does not contain 'brouter' subfolder)" : " is not valid)");
((BRouterActivity) getContext()).selectBasedir(((BRouterActivity) getContext()).getStorageDirectories(), message);
waitingForSelection = true;
} catch (Exception e) {
String msg = e instanceof IllegalArgumentException ? e.getMessage() : e.toString();
AppLogger.log(msg);
AppLogger.log(AppLogger.formatThrowable(e));
((BRouterActivity) getContext()).showErrorMessage(msg);
}
}
public void startSetup(File baseDir, boolean storeBasedir, boolean silent) {
if (baseDir == null) {
baseDir = retryBaseDir;
retryBaseDir = null;
}
if (storeBasedir) {
File td = new File(baseDir, "brouter");
try {
td.mkdirs();
} catch (Exception e) {
Log.d("BRouterView", "Error creating base directory: " + e.getMessage());
e.printStackTrace();
}
if (!td.isDirectory()) {
if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
retryBaseDir = baseDir;
ActivityCompat.requestPermissions((BRouterActivity) getContext(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
} else {
((BRouterActivity) getContext()).selectBasedir(((BRouterActivity) getContext()).getStorageDirectories(), "Cannot access " + baseDir.getAbsolutePath() + "; select another");
}
return;
}
ConfigHelper.writeBaseDir(getContext(), baseDir);
}
try {
cor = null;
String basedir = baseDir.getAbsolutePath();
AppLogger.log("using basedir: " + basedir);
populateBasedir(basedir);
// new init is done move old files
if (waitingForMigration) {
Log.d("BR", "path " + oldMigrationPath + " " + basedir);
Thread t = new Thread(new Runnable() {
@Override
public void run() {
if (!oldMigrationPath.equals(basedir + "/brouter"))
moveFolders(oldMigrationPath, basedir + "/brouter");
}});
t.start();
try {
t.join(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
waitingForMigration = false;
}
cor = CoordinateReader.obtainValidReader(basedir);
wpList = cor.waypoints;
nogoList = cor.nogopoints;
nogoVetoList = new ArrayList<>();
needsViaSelection = wpList.size() > 2;
needsNogoSelection = nogoList.size() > 0;
needsWaypointSelection = wpList.size() == 0;
if (cor.tracksdir != null) {
tracksDir = new File(cor.basedir, cor.tracksdir);
assertDirectoryExists("track directory", tracksDir, null, null);
}
if (tracksDir == null) {
tracksDir = new File(basedir, "brouter"); // fallback
}
String[] fileNames = profileDir.list();
ArrayList<String> profiles = new ArrayList<>();
boolean lookupsFound = false;
if (fileNames != null) {
for (String fileName : fileNames) {
if (fileName.endsWith(".brf")) {
profiles.add(fileName.substring(0, fileName.length() - 4));
}
if (fileName.equals("lookups.dat"))
lookupsFound = true;
}
}
// add a "last timeout" dummy profile
File lastTimeoutFile = new File(modesDir + "/timeoutdata.txt");
long lastTimeoutTime = lastTimeoutFile.lastModified();
if (lastTimeoutTime > 0 && System.currentTimeMillis() - lastTimeoutTime < 1800000) {
BufferedReader br = new BufferedReader(new FileReader(lastTimeoutFile));
String repeatProfile = br.readLine();
br.close();
profiles.add(0, "<repeat:" + repeatProfile + ">");
}
if (!lookupsFound) {
throw new IllegalArgumentException("The profile-directory " + profileDir + " does not contain the lookups.dat file."
+ " see brouter.de/brouter for setup instructions.");
}
if (profiles.size() == 0) {
throw new IllegalArgumentException("The profile-directory " + profileDir + " contains no routing profiles (*.brf)."
+ " see brouter.de/brouter for setup instructions.");
}
if (silent) {
Intent intent = new Intent(getContext(), BInstallerActivity.class);
getContext().startActivity(intent);
return;
};
if (!RoutingHelper.hasDirectoryAnyDatafiles(segmentDir)) {
((BRouterActivity) getContext()).startDownloadManager();
waitingForSelection = true;
return;
}
((BRouterActivity) getContext()).selectProfile(profiles.toArray(new String[0]));
} catch (Exception e) {
String msg = e instanceof IllegalArgumentException ? e.getMessage()
+ (cor == null ? "" : " (coordinate-source: " + cor.basedir + cor.rootdir + ")") : e.toString();
AppLogger.log(msg);
AppLogger.log(AppLogger.formatThrowable(e));
((BRouterActivity) getContext()).showErrorMessage(msg + "\n" + AppLogger.formatThrowable(e));
}
waitingForSelection = true;
}
private void populateBasedir(String basedir) {
String version = "v" + getContext().getString(R.string.app_version);
// create missing directories
assertDirectoryExists("project directory", new File(basedir, "brouter"), null, null);
segmentDir = new File(basedir, "/brouter/segments4");
if (assertDirectoryExists("data directory", segmentDir, "segments4.zip", null)) {
ConfigMigration.tryMigrateStorageConfig(
new File(basedir + "/brouter/segments3/storageconfig.txt"),
new File(basedir + "/brouter/segments4/storageconfig.txt"));
} else {
ServerConfig.checkForUpdate(getContext(), segmentDir, "segments4.zip");
}
profileDir = new File(basedir, "brouter/profiles2");
assertDirectoryExists("profile directory", profileDir, "profiles2.zip", version);
modesDir = new File(basedir, "/brouter/modes");
assertDirectoryExists("modes directory", modesDir, "modes.zip", version);
assertDirectoryExists("readmes directory", new File(basedir, "brouter/readmes"), "readmes.zip", version);
File inputDir = new File(basedir, "brouter/import");
assertDirectoryExists("input directory", inputDir, null, version);
}
private void moveFolders(String oldMigrationPath, String basedir) {
File oldDir = new File(oldMigrationPath);
File[] oldFiles = oldDir.listFiles();
if (oldFiles != null) {
for (File f : oldFiles) {
if (f.isDirectory()) {
int index = f.getAbsolutePath().lastIndexOf("/");
String tmpdir = basedir + f.getAbsolutePath().substring(index);
moveFolders(f.getAbsolutePath(), tmpdir);
} else {
if (!f.getName().startsWith("v1.6")) {
moveFile(oldMigrationPath, f.getName(), basedir);
}
}
}
}
}
private void copyFile(String inputPath, String inputFile, String outputPath) {
InputStream in;
OutputStream out;
try {
//create output directory if it doesn't exist
File dir = new File(outputPath);
if (!dir.exists()) {
dir.mkdirs();
}
in = new FileInputStream(new File(inputPath, inputFile));
out = new FileOutputStream(new File(outputPath, inputFile));
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
// write the output file
out.flush();
out.close();
} catch (FileNotFoundException fileNotFoundException) {
Log.e("tag", fileNotFoundException.getMessage());
} catch (Exception e) {
Log.e("tag", e.getMessage());
}
}
private void moveFile(String inputPath, String inputFile, String outputPath) {
copyFile(inputPath, inputFile, outputPath);
// delete the original file
new File(inputPath, inputFile).delete();
}
public boolean hasUpToDateLookups() {
BExpressionMetaData meta = new BExpressionMetaData();
meta.readMetaData(new File(profileDir, "lookups.dat"));
return meta.lookupVersion == 10;
}
public void continueProcessing() {
waitingForSelection = false;
invalidate();
}
public void updateViaList(Set<String> selectedVias) {
ArrayList<OsmNodeNamed> filtered = new ArrayList<>(wpList.size());
for (OsmNodeNamed n : wpList) {
String name = n.name;
if ("from".equals(name) || "to".equals(name) || selectedVias.contains(name))
filtered.add(n);
}
wpList = filtered;
}
public void updateNogoList(boolean[] enabled) {
for (int i = nogoList.size() - 1; i >= 0; i--) {
if (enabled[i]) {
nogoVetoList.add(nogoList.get(i));
nogoList.remove(i);
}
}
}
public void pickWaypoints() {
String msg = null;
if (cor.allpoints == null) {
try {
cor.readAllPoints();
} catch (Exception e) {
msg = getContext().getString(R.string.msg_read_wpt_error)+ ": " + e;
}
int size = cor.allpoints.size();
if (size < 1)
msg = getContext().getString(R.string.msg_no_wpt);
if (size > 1000)
msg = String.format(getContext().getString(R.string.msg_too_much_wpts), size);
}
if (msg != null) {
((BRouterActivity) getContext()).showErrorMessage(msg);
} else {
String[] wpts = new String[cor.allpoints.size()];
int i = 0;
for (OsmNodeNamed wp : cor.allpoints)
wpts[i++] = wp.name;
((BRouterActivity) getContext()).selectWaypoint(wpts);
}
}
public void updateWaypointList(String waypoint) {
for (OsmNodeNamed wp : cor.allpoints) {
if (wp.name.equals(waypoint)) {
if (wp.ilat != 0 || wp.ilon != 0) {
int nwp = wpList.size();
if (nwp == 0 || wpList.get(nwp - 1) != wp) {
wpList.add(wp);
}
}
return;
}
}
}
public void finishWaypointSelection() {
needsWaypointSelection = false;
}
private List<OsmNodeNamed> readWpList(BufferedReader br, boolean isNogo) throws Exception {
int cnt = Integer.parseInt(br.readLine());
List<OsmNodeNamed> res = new ArrayList<>(cnt);
for (int i = 0; i < cnt; i++) {
OsmNodeNamed wp = OsmNodeNamed.decodeNogo(br.readLine());
wp.isNogo = isNogo;
res.add(wp);
}
return res;
}
public void startProcessing(String profile) {
rawTrackPath = null;
if (profile.startsWith("<repeat")) {
needsViaSelection = needsNogoSelection = needsWaypointSelection = false;
try {
File lastTimeoutFile = new File(modesDir + "/timeoutdata.txt");
BufferedReader br = new BufferedReader(new FileReader(lastTimeoutFile));
profile = br.readLine();
rawTrackPath = br.readLine();
wpList = readWpList(br, false);
nogoList = readWpList(br, true);
br.close();
} catch (Exception e) {
AppLogger.log(AppLogger.formatThrowable(e));
((BRouterActivity) getContext()).showErrorMessage(e.toString());
}
} else if ("remote".equals(profileName)) {
rawTrackPath = modesDir + "/remote_rawtrack.dat";
}
String profilePath = profileDir + "/" + profile + ".brf";
profileName = profile;
if (needsViaSelection) {
needsViaSelection = false;
String[] availableVias = new String[wpList.size() - 2];
for (int viaidx = 0; viaidx < wpList.size() - 2; viaidx++)
availableVias[viaidx] = wpList.get(viaidx + 1).name;
((BRouterActivity) getContext()).selectVias(availableVias);
return;
}
if (needsNogoSelection) {
needsNogoSelection = false;
((BRouterActivity) getContext()).selectNogos(nogoList);
return;
}
if (needsWaypointSelection) {
StringBuilder msg;
if (wpList.size() == 0) {
msg = new StringBuilder(getContext().getString(R.string.msg_no_wpt_selection) + "(coordinate-source: " + cor.basedir + cor.rootdir + ")");
} else {
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(getContext().getString(R.string.title_action), msg.toString(), wpList.size());
return;
}
try {
waitingForSelection = false;
RoutingContext rc = new RoutingContext();
rc.localFunction = profilePath;
rc.turnInstructionMode = cor.getTurnInstructionMode();
int plain_distance = 0;
int maxlon = Integer.MIN_VALUE;
int minlon = Integer.MAX_VALUE;
int maxlat = Integer.MIN_VALUE;
int minlat = Integer.MAX_VALUE;
OsmNode prev = null;
for (OsmNode n : wpList) {
maxlon = Math.max(n.ilon, maxlon);
minlon = Math.min(n.ilon, minlon);
maxlat = Math.max(n.ilat, maxlat);
minlat = Math.min(n.ilat, minlat);
if (prev != null) {
plain_distance += n.calcDistance(prev);
}
prev = n;
}
toast("Plain distance = " + plain_distance / 1000. + " km");
centerLon = (maxlon + minlon) / 2;
centerLat = (maxlat + minlat) / 2;
double[] lonlat2m = CheapRuler.getLonLatToMeterScales(centerLat);
double dlon2m = lonlat2m[0];
double dlat2m = lonlat2m[1];
double difflon = (maxlon - minlon) * dlon2m;
double difflat = (maxlat - minlat) * dlat2m;
scaleLon = imgw / (difflon * 1.5);
scaleLat = imgh / (difflat * 1.5);
scaleMeter2Pixel = Math.min(scaleLon, scaleLat);
scaleLon = scaleMeter2Pixel * dlon2m;
scaleLat = scaleMeter2Pixel * dlat2m;
startTime = System.currentTimeMillis();
RoutingContext.prepareNogoPoints(nogoList);
rc.nogopoints = nogoList;
rc.memoryclass = memoryClass;
if (memoryClass < 16) {
rc.memoryclass = 16;
} else if (memoryClass > 256) {
rc.memoryclass = 256;
}
// for profile remote, use ref-track logic same as service interface
rc.rawTrackPath = rawTrackPath;
cr = new RoutingEngine(tracksDir.getAbsolutePath() + "/brouter", null, segmentDir, wpList, rc);
cr.start();
invalidate();
} catch (Exception e) {
String msg = e instanceof IllegalArgumentException ? e.getMessage() : e.toString();
toast(msg);
}
}
private boolean assertDirectoryExists(String message, File path, String assetZip, String versionTag) {
boolean exists = path.exists();
if (!exists) {
path.mkdirs();
}
if (versionTag != null) {
File vtag = new File(path, versionTag);
try {
exists = !vtag.createNewFile();
} catch (IOException ignored) {
} // well..
}
if (!exists) {
// default contents from assets archive
if (assetZip != null) {
try {
AssetManager assetManager = getContext().getAssets();
InputStream is = assetManager.open(assetZip);
ZipInputStream zis = new ZipInputStream(is);
byte[] data = new byte[1024];
for (; ; ) {
ZipEntry ze = zis.getNextEntry();
if (ze == null)
break;
if (ze.isDirectory()) {
continue;
}
String name = ze.getName();
File outfile = new File(path, name);
String canonicalPath = outfile.getCanonicalPath();
if (canonicalPath.startsWith(path.getCanonicalPath()) &&
!outfile.exists() &&
outfile.getParentFile() != null) {
outfile.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(outfile);
for (; ; ) {
int len = zis.read(data, 0, 1024);
if (len < 0)
break;
fos.write(data, 0, len);
}
fos.close();
}
}
zis.close();
is.close();
return true;
} catch (IOException io) {
throw new RuntimeException("error expanding " + assetZip + ": " + io);
}
}
}
if (!path.exists() || !path.isDirectory())
throw new IllegalArgumentException(message + ": " + path + " cannot be created");
return false;
}
private void paintPosition(int ilon, int ilat, int color, int with) {
int lon = ilon - centerLon;
int lat = ilat - centerLat;
int x = imgw / 2 + (int) (scaleLon * lon);
int y = imgh / 2 - (int) (scaleLat * lat);
for (int nx = x - with; nx <= x + with; nx++)
for (int ny = y - with; ny <= y + with; ny++) {
if (nx >= 0 && nx < imgw && ny >= 0 && ny < imgh) {
imgPixels[nx + imgw * ny] = color;
}
}
}
private void paintCircle(Canvas canvas, OsmNodeNamed n, int color, int minradius) {
int lon = n.ilon - centerLon;
int lat = n.ilat - centerLat;
int x = imgw / 2 + (int) (scaleLon * lon);
int y = imgh / 2 - (int) (scaleLat * lat);
int ir = (int) (n.radius * scaleMeter2Pixel);
if (ir > minradius) {
Paint paint = new Paint();
paint.setColor(color);
paint.setStyle(Paint.Style.STROKE);
canvas.drawCircle((float) x, (float) y, (float) ir, paint);
}
}
private void paintLine(Canvas canvas, final int ilon0, final int ilat0, final int ilon1, final int ilat1, final Paint paint) {
final int lon0 = ilon0 - centerLon;
final int lat0 = ilat0 - centerLat;
final int lon1 = ilon1 - centerLon;
final int lat1 = ilat1 - centerLat;
final int x0 = imgw / 2 + (int) (scaleLon * lon0);
final int y0 = imgh / 2 - (int) (scaleLat * lat0);
final int x1 = imgw / 2 + (int) (scaleLon * lon1);
final int y1 = imgh / 2 - (int) (scaleLat * lat1);
canvas.drawLine((float) x0, (float) y0, (float) x1, (float) y1, paint);
}
private void paintPolygon(Canvas canvas, OsmNogoPolygon p, int minradius) {
final int ir = (int) (p.radius * scaleMeter2Pixel);
if (ir > minradius) {
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
Point p0 = p.isClosed ? p.points.get(p.points.size() - 1) : null;
for (final Point p1 : p.points) {
if (p0 != null) {
paintLine(canvas, p0.x, p0.y, p1.x, p1.y, paint);
}
p0 = p1;
}
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
imgw = w;
imgh = h;
}
private void toast(String msg) {
Toast.makeText(getContext(), msg, Toast.LENGTH_LONG).show();
lastDataTime += 4000; // give time for the toast before exiting
}
@Override
protected void onDraw(Canvas canvas) {
try {
_onDraw(canvas);
} catch (Throwable t) {
// on out of mem, try to stop the show
if (cr != null)
cr.cleanOnOOM();
cr = null;
try {
Thread.sleep(2000);
} catch (InterruptedException ignored) {
}
((BRouterActivity) getContext()).showErrorMessage(t.toString());
waitingForSelection = true;
}
}
private void _onDraw(Canvas canvas) {
if (waitingForSelection)
return;
long currentTs = System.currentTimeMillis();
long diffTs = currentTs - lastTs;
long sleeptime = 500 - diffTs;
while (sleeptime < 200)
sleeptime += 500;
try {
Thread.sleep(sleeptime);
} catch (InterruptedException ignored) {
}
lastTs = System.currentTimeMillis();
if (cr == null || cr.isFinished()) {
if (cr != null) {
if (cr.getErrorMessage() != null) {
((BRouterActivity) getContext()).showErrorMessage(cr.getErrorMessage());
} else {
String memstat = memoryClass + "mb pathPeak " + ((cr.getPathPeak() + 500) / 1000) + "k";
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();
// for profile "remote", always persist referencetrack
if (cr.getAlternativeIndex() == 0 && rawTrackPath != null) {
writeRawTrackToPath(rawTrackPath);
}
String title = getContext().getString(R.string.success);
if (cr.getAlternativeIndex() > 0)
title += " / " + cr.getAlternativeIndex() + ". " + getContext().getString(R.string.msg_alternative);
((BRouterActivity) getContext()).showResultMessage(title, result, rawTrackPath == null ? -1 : -3);
trackOutfile = cr.getOutfile();
}
cr = null;
waitingForSelection = true;
return;
} else if (System.currentTimeMillis() > lastDataTime) {
System.exit(0);
}
} else {
lastDataTime = System.currentTimeMillis();
imgPixels = new int[imgw * imgh];
int[] openSet = cr.getOpenSet();
for (int si = 0; si < openSet.length; si += 2) {
paintPosition(openSet[si], openSet[si + 1], 0xffffff, 1);
}
// paint nogos on top (red)
int minradius = 4;
for (int ngi = 0; ngi < nogoList.size(); ngi++) {
OsmNodeNamed n = nogoList.get(ngi);
int color = 0xff0000;
paintPosition(n.ilon, n.ilat, color, minradius);
}
// paint start/end/vias on top (yellow/green/blue)
for (int wpi = 0; wpi < wpList.size(); wpi++) {
OsmNodeNamed n = wpList.get(wpi);
int color = wpi == 0 ? 0xffff00 : wpi < wpList.size() - 1 ? 0xff : 0xff00;
paintPosition(n.ilon, n.ilat, color, minradius);
}
Bitmap bmp = Bitmap.createBitmap(imgPixels, imgw, imgh, Bitmap.Config.RGB_565);
canvas.drawBitmap(bmp, 0, 0, null);
// nogo circles if any
for (int ngi = 0; ngi < nogoList.size(); ngi++) {
OsmNodeNamed n = nogoList.get(ngi);
if (n instanceof OsmNogoPolygon) {
paintPolygon(canvas, (OsmNogoPolygon) n, minradius);
} else {
int color = Color.RED;
paintCircle(canvas, n, color, minradius);
}
}
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTextSize(20);
long mseconds = System.currentTimeMillis() - startTime;
long links = cr.getLinksProcessed();
long perS = (1000 * links) / mseconds;
String msg = "Links: " + cr.getLinksProcessed() + " in " + (mseconds / 1000) + "s (" + perS + " l/s)";
canvas.drawText(msg, 10, 25, paint);
}
// and make sure to redraw asap
invalidate();
}
private void writeRawTrackToMode(String mode) {
writeRawTrackToPath(modesDir + "/" + mode + "_rawtrack.dat");
}
private void writeRawTrackToPath(String rawTrackPath) {
if (rawTrack != null) {
try {
rawTrack.writeBinary(rawTrackPath);
} catch (Exception ignored) {
}
} else {
new File(rawTrackPath).delete();
}
}
public void startConfigureService() {
String[] modes = new String[]
{"foot_short", "foot_fast", "bicycle_short", "bicycle_fast", "motorcar_short", "motorcar_fast"};
boolean[] modesChecked = new boolean[6];
String msg = "Choose service-modes to configure (" + profileName + " [" + nogoVetoList.size() + "])";
((BRouterActivity) getContext()).selectRoutingModes(modes, modesChecked, msg);
}
public void configureService(String[] routingModes, boolean[] checkedModes) {
// read in current config
TreeMap<String, ServiceModeConfig> map = new TreeMap<>();
BufferedReader br = null;
String modesFile = modesDir + "/serviceconfig.dat";
try {
br = new BufferedReader(new FileReader(modesFile));
for (; ; ) {
String line = br.readLine();
if (line == null)
break;
ServiceModeConfig smc = new ServiceModeConfig(line);
map.put(smc.mode, smc);
}
} catch (Exception ignored) {
} finally {
if (br != null)
try {
br.close();
} catch (Exception ignored) {
}
}
// replace selected modes
for (int i = 0; i < 6; i++) {
if (checkedModes[i]) {
writeRawTrackToMode(routingModes[i]);
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) {
smc.nogoVetos.add(nogo.ilon + "," + nogo.ilat);
}
map.put(smc.mode, smc);
}
}
// no write new config
BufferedWriter bw = null;
StringBuilder msg = new StringBuilder("Mode mapping is now:\n");
msg.append("( [");
msg.append(nogoVetoList.size() > 0 ? nogoVetoList.size() : "..").append("] counts nogo-vetos)\n");
try {
bw = new BufferedWriter(new FileWriter(modesFile));
for (ServiceModeConfig smc : map.values()) {
bw.write(smc.toLine());
bw.write('\n');
msg.append(smc).append('\n');
}
} catch (Exception ignored) {
} finally {
if (bw != null)
try {
bw.close();
} catch (Exception ignored) {
}
}
((BRouterActivity) getContext()).showModeConfigOverview(msg.toString());
}
public void configureServiceParams(String profile, String sparams) {
List<ServiceModeConfig> map = new ArrayList<>();
BufferedReader br = null;
String modesFile = modesDir + "/serviceconfig.dat";
try {
br = new BufferedReader(new FileReader(modesFile));
for (; ; ) {
String line = br.readLine();
if (line == null)
break;
ServiceModeConfig smc = new ServiceModeConfig(line);
if (smc.profile.equals(profile)) smc.params = sparams;
map.add(smc);
}
} catch (Exception ignored) {
} finally {
if (br != null)
try {
br.close();
} catch (Exception ignored) {
}
}
// now write new config
BufferedWriter bw = null;
StringBuilder msg = new StringBuilder("Mode mapping is now:\n");
msg.append("( [");
msg.append(nogoVetoList.size() > 0 ? nogoVetoList.size() : "..").append("] counts nogo-vetos)\n");
try {
bw = new BufferedWriter(new FileWriter(modesFile));
for (ServiceModeConfig smc : map) {
bw.write(smc.toLine());
bw.write('\n');
msg.append(smc).append('\n');
}
} catch (Exception ignored) {
} finally {
if (bw != null)
try {
bw.close();
} catch (Exception ignored) {
}
}
((BRouterActivity) getContext()).showModeConfigOverview(msg.toString());
}
public String getConfigureServiceParams(String profile) {
List<ServiceModeConfig> map = new ArrayList<>();
BufferedReader br = null;
String modesFile = modesDir + "/serviceconfig.dat";
try {
br = new BufferedReader(new FileReader(modesFile));
for (; ; ) {
String line = br.readLine();
if (line == null)
break;
ServiceModeConfig smc = new ServiceModeConfig(line);
if (smc.profile.equals(profile)) {
if (!smc.params.equals("noparams")) return smc.params;
else return "";
}
map.add(smc);
}
} catch (Exception ignored) {
} finally {
if (br != null)
try {
br.close();
} catch (Exception ignored) {
}
}
// no profile found
return null;
}
public void shareTrack() {
File track = new File(trackOutfile);
// Copy file to cache to ensure FileProvider allows sharing the file
File cacheDir = getContext().getCacheDir();
copyFile(track.getParent(), track.getName(), cacheDir.getAbsolutePath());
Intent intent = new Intent();
intent.setDataAndType(FileProvider.getUriForFile(getContext(), "btools.routing.fileprovider", new File(cacheDir, track.getName())),
"application/gpx+xml");
intent.setAction(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
getContext().startActivity(intent);
}
}