brouter/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java
2021-08-31 11:29:05 +02:00

1175 lines
33 KiB
Java

package btools.routingapp;
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.InputStreamReader;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.os.Environment;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import btools.expressions.BExpressionContextWay;
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
{
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 profilePath;
private String profileName;
private String sourceHint;
private boolean waitingForSelection = false;
private boolean waitingForMigration = false;
private String rawTrackPath;
private String oldMigrationPath;
private boolean needsViaSelection;
private boolean needsNogoSelection;
private boolean needsWaypointSelection;
private WpDatabaseScanner dataBaseScanner;
private long lastDataTime = System.currentTimeMillis();
private CoordinateReader cor;
private int[] imgPixels;
private int memoryClass;
public boolean canAccessSdCard;
public void stopRouting()
{
if ( cr != null ) cr.terminate();
}
public BRouterView( Context context, int memoryClass )
{
super( context );
this.memoryClass = memoryClass;
}
public void init()
{
try
{
DisplayMetrics metrics = new DisplayMetrics();
( (Activity) getContext() ).getWindowManager().getDefaultDisplay().getMetrics( metrics );
imgw = metrics.widthPixels;
imgh = metrics.heightPixels;
// 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 (brd.getAbsolutePath().contains("/Android/data/")) {
String message = "(previous basedir " + baseDir + " has to migrate )" ;
( (BRouterActivity) getContext() ).selectBasedir( ( (BRouterActivity) getContext() ).getStorageDirectories(), guessBaseDir(), message );
waitingForSelection = true;
waitingForMigration = true;
oldMigrationPath = brd.getAbsolutePath();
return;
} else {
startSetup( baseDir, false );
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(), guessBaseDir(), 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 )
{
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 ( ( (BRouterActivity) getContext() ).checkSelfPermission (getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
// if (ContextCompat.checkSelfPermission (getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
retryBaseDir = baseDir;
} else {
( (BRouterActivity) getContext() ).selectBasedir( ( (BRouterActivity) getContext() ).getStorageDirectories (), guessBaseDir(), "Cannot access " + baseDir.getAbsolutePath () + "; select another");
}
return;
}
ConfigHelper.writeBaseDir( getContext(), baseDir );
}
try
{
cor = null;
String basedir = baseDir.getAbsolutePath();
AppLogger.log( "using basedir: " + 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" ) );
}
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, "/import");
assertDirectoryExists( "input directory", inputDir, null, version );
// new init is done move old files
if (waitingForMigration) {
moveFolders(oldMigrationPath, basedir + "/brouter");
waitingForMigration = false;
}
int deviceLevel = android.os.Build.VERSION.SDK_INT;
int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
canAccessSdCard = deviceLevel < 23 || targetSdkVersion == 10;
if ( canAccessSdCard )
{
cor = CoordinateReader.obtainValidReader( basedir, segmentDir );
}
else
{
if (deviceLevel >= android.os.Build.VERSION_CODES.Q) {
cor = new CoordinateReaderInternal(basedir);
} else {
cor = new CoordinateReaderNone();
}
cor.readFromTo();
}
wpList = cor.waypoints;
nogoList = cor.nogopoints;
nogoVetoList = new ArrayList<OsmNodeNamed>();
sourceHint = "(dev/trgt=" + deviceLevel + "/" + targetSdkVersion + " coordinate-source: " + cor.basedir + cor.rootdir + ")";
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 );
// output redirect: look for a pointerfile in tracksdir
File tracksDirPointer = new File( tracksDir, "brouter.redirect" );
if ( tracksDirPointer.isFile() )
{
String tracksDirStr = readSingleLineFile( tracksDirPointer );
if ( tracksDirStr == null )
throw new IllegalArgumentException( "redirect pointer file is empty: " + tracksDirPointer );
tracksDir = new File (tracksDirStr);
if ( !( tracksDir.isDirectory() ) )
throw new IllegalArgumentException( "redirect pointer file " + tracksDirPointer + " does not point to a directory: " + tracksDir );
}
else
{
File writeTest = new File( tracksDir + "/brouter.writetest" );
try
{
writeTest.createNewFile();
writeTest.delete();
}
catch( Exception e )
{
tracksDir = null;
}
}
}
if ( tracksDir == null )
{
tracksDir = new File (basedir, "router"); // fallback
}
String[] fileNames = profileDir.list();
ArrayList<String> profiles = new ArrayList<String>();
boolean lookupsFound = false;
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 ( !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 moveFolders(String oldMigrationPath, String basedir) {
File oldDir = new File(oldMigrationPath);
File[] oldFiles = oldDir.listFiles();
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 moveFile(String inputPath, String inputFile, String outputPath) {
InputStream in = null;
OutputStream out = null;
try {
//create output directory if it doesn't exist
File dir = new File (outputPath);
if (!dir.exists())
{
dir.mkdirs();
}
in = new FileInputStream(inputPath + "/" + inputFile);
out = new FileOutputStream(outputPath + "/" + inputFile);
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
in = null;
// write the output file
out.flush();
out.close();
out = null;
// delete the original file
new File(inputPath + "/" + inputFile).delete();
}
catch (FileNotFoundException fnfe1) {
Log.e("tag", fnfe1.getMessage());
}
catch (Exception e) {
Log.e("tag", e.getMessage());
}
}
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<OsmNodeNamed>( 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 = "Error reading waypoints: " + e.toString();
}
int size = cor.allpoints.size();
if ( size < 1 )
msg = "coordinate source does not contain any waypoints!";
if ( size > 1000 )
msg = "coordinate source contains too much waypoints: " + size + "(please use from/to/via names)";
}
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 startWpDatabaseScan()
{
dataBaseScanner = new WpDatabaseScanner();
dataBaseScanner.start();
invalidate();
}
public void saveMaptoolDir( String dir )
{
ConfigMigration.saveAdditionalMaptoolDir( segmentDir, dir );
( (BRouterActivity) getContext() ).showResultMessage( "Success", "please restart to use new config", -1 );
}
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<OsmNodeNamed>(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";
}
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 )
{
String msg;
if ( wpList.size() == 0 )
{
msg = "Expecting waypoint selection\n" + sourceHint;
}
else
{
msg = "current waypoint selection:\n";
for ( int i = 0; i < wpList.size(); i++ )
msg += ( i > 0 ? "->" : "" ) + wpList.get( i ).name;
}
( (BRouterActivity) getContext() ).showResultMessage( "Select Action", msg, cor instanceof CoordinateReaderNone ? -2 : 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 + "/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 io ) { } // 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;
String name = ze.getName();
File outfile = new File( path, name );
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();
}
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.RED );
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 )
{
}
private void toast( String msg )
{
Toast.makeText( getContext(), msg, Toast.LENGTH_LONG ).show();
lastDataTime += 4000; // give time for the toast before exiting
}
private long lastTs = System.currentTimeMillis();
private long startTime = 0L;
@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 ie)
{
}
( (BRouterActivity) getContext() ).showErrorMessage( t.toString() );
waitingForSelection = true;
}
}
private void showDatabaseScanning( Canvas canvas )
{
try
{
Thread.sleep( 100 );
}
catch (InterruptedException ie)
{
}
Paint paint1 = new Paint();
paint1.setColor( Color.WHITE );
paint1.setTextSize( 20 );
Paint paint2 = new Paint();
paint2.setColor( Color.WHITE );
paint2.setTextSize( 10 );
String currentDir = dataBaseScanner.getCurrentDir();
String bestGuess = dataBaseScanner.getBestGuess();
if ( currentDir == null ) // scan finished
{
if ( bestGuess.length() == 0 )
{
( (BRouterActivity) getContext() ).showErrorMessage( "scan did not find any possible waypoint database" );
}
else
{
( (BRouterActivity) getContext() ).showWpDatabaseScanSuccess( bestGuess);
}
cr = null;
dataBaseScanner = null;
waitingForSelection = true;
return;
}
canvas.drawText( "Scanning:", 10, 30, paint1 );
canvas.drawText( currentDir, 0, 60, paint2 );
canvas.drawText( "Best Guess:", 10, 90, paint1 );
canvas.drawText( bestGuess, 0, 120, paint2 );
canvas.drawText( "Last Error:", 10, 150, paint1 );
canvas.drawText( dataBaseScanner.getLastError(), 0, 180, paint2 );
invalidate();
}
private void _onDraw( Canvas canvas )
{
if ( dataBaseScanner != null )
{
showDatabaseScanning( canvas );
return;
}
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 ie)
{
}
lastTs = System.currentTimeMillis();
if ( cr == null || cr.isFinished() )
{
if ( cr != null )
{
if ( cr.getErrorMessage() != null )
{
( (BRouterActivity) getContext() ).showErrorMessage( cr.getErrorMessage() );
cr = null;
waitingForSelection = true;
return;
}
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();
rawTrack = cr.getFoundRawTrack();
// for profile "remote", always persist referencetrack
if ( cr.getAlternativeIndex() == 0 && rawTrackPath != null )
{
writeRawTrackToPath( rawTrackPath );
}
String title = "Success";
if ( cr.getAlternativeIndex() > 0 )
title += " / " + cr.getAlternativeIndex() + ". Alternative";
( (BRouterActivity) getContext() ).showResultMessage( title, result, rawTrackPath == null ? -1 : -3 );
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)
for ( int ngi = 0; ngi < nogoList.size(); ngi++ )
{
OsmNodeNamed n = nogoList.get( ngi );
int color = 0xff0000;
paintPosition( n.ilon, n.ilat, color, 4 );
}
// 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, 4 );
}
canvas.drawBitmap( imgPixels, 0, imgw, (float) 0., (float) 0., imgw, imgh, false, 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, 4 );
}
else
{
int color = 0xff0000;
paintCircle( canvas, n, color, 4 );
}
}
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 String guessBaseDir()
{
File basedir = Environment.getExternalStorageDirectory();
try
{
File bd2 = new File( basedir, "external_sd" );
ArrayList<String> basedirGuesses = new ArrayList<String>();
basedirGuesses.add( basedir.getAbsolutePath() );
if ( bd2.exists() )
{
basedir = bd2;
basedirGuesses.add( basedir.getAbsolutePath() );
}
ArrayList<CoordinateReader> rl = new ArrayList<CoordinateReader>();
for ( String bdg : basedirGuesses )
{
rl.add( new CoordinateReaderOsmAnd( bdg ) );
rl.add( new CoordinateReaderLocus( bdg ) );
rl.add( new CoordinateReaderOrux( bdg ) );
}
long tmax = 0;
CoordinateReader cor = null;
for ( CoordinateReader r : rl )
{
long t = r.getTimeStamp();
if ( t > tmax )
{
tmax = t;
cor = r;
}
}
if ( cor != null )
{
return cor.basedir;
}
}
catch (Exception e)
{
System.out.println( "guessBaseDir:" + e );
}
return basedir.getAbsolutePath();
}
private void writeRawTrackToMode( String mode )
{
writeRawTrackToPath( modesDir + "/" + mode + "_rawtrack.dat" );
}
private void writeRawTrackToPath( String rawTrackPath )
{
if ( rawTrack != null )
{
try
{
rawTrack.writeBinary( rawTrackPath );
}
catch (Exception e)
{
}
}
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<String, ServiceModeConfig>();
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 e)
{
}
finally
{
if ( br != null )
try
{
br.close();
}
catch (Exception ee)
{
}
}
// replace selected modes
for ( int i = 0; i < 6; i++ )
{
if ( checkedModes[i] )
{
writeRawTrackToMode( routingModes[i] );
ServiceModeConfig smc = new ServiceModeConfig( routingModes[i], profileName );
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.toString() ).append( '\n' );
}
}
catch (Exception e)
{
}
finally
{
if ( bw != null )
try
{
bw.close();
}
catch (Exception ee)
{
}
}
( (BRouterActivity) getContext() ).showModeConfigOverview( msg.toString() );
}
private String readSingleLineFile( File f )
{
try ( FileInputStream fis = new FileInputStream (f);
InputStreamReader isr = new InputStreamReader (fis);
BufferedReader br = new BufferedReader (isr)) {
return br.readLine();
}
catch (Exception e)
{
return null;
}
}
}