diff --git a/brouter-core/src/main/java/btools/router/OsmTrack.java b/brouter-core/src/main/java/btools/router/OsmTrack.java index 8de42ce..0b6d5d7 100644 --- a/brouter-core/src/main/java/btools/router/OsmTrack.java +++ b/brouter-core/src/main/java/btools/router/OsmTrack.java @@ -268,7 +268,7 @@ public final class OsmTrack 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-1.3.1\" version=\"1.1\">\n" ); + sb.append( " creator=\"BRouter-1.3.2\" version=\"1.1\">\n" ); sb.append( " \n" ); sb.append( " " ).append( name ).append( "\n" ); sb.append( " \n" ); diff --git a/brouter-core/src/main/java/btools/router/RoutingEngine.java b/brouter-core/src/main/java/btools/router/RoutingEngine.java index 7338029..c8dba05 100644 --- a/brouter-core/src/main/java/btools/router/RoutingEngine.java +++ b/brouter-core/src/main/java/btools/router/RoutingEngine.java @@ -236,7 +236,12 @@ public class RoutingEngine extends Thread { try { - MatchedWaypoint seedPoint = matchNodeForPosition( waypoints.get(0) ); + MatchedWaypoint seedPoint = new MatchedWaypoint(); + seedPoint.waypoint = waypoints.get(0); + List listOne = new ArrayList(); + listOne.add( seedPoint ); + matchWaypointsToNodes( listOne ); + routingContext.countTraffic = true; findTrack( "seededSearch", seedPoint, null, null, null, false ); diff --git a/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java b/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java index 3d4df10..553e0b5 100644 --- a/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java +++ b/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java @@ -577,6 +577,10 @@ public abstract class BExpressionContext public void parseFile( File file, String readOnlyContext ) { + if ( !file.exists() ) + { + throw new IllegalArgumentException( "profile " + file + " does not exist" ); + } try { if ( readOnlyContext != null ) diff --git a/brouter-map-creator/src/main/java/btools/mapcreator/TrafficData2Png.java b/brouter-map-creator/src/main/java/btools/mapcreator/TrafficData2Png.java index 9f7ba24..fc100cc 100644 --- a/brouter-map-creator/src/main/java/btools/mapcreator/TrafficData2Png.java +++ b/brouter-map-creator/src/main/java/btools/mapcreator/TrafficData2Png.java @@ -9,146 +9,146 @@ import btools.util.Raster2Png; public class TrafficData2Png { - private static int minLon; - private static int minLat; - private static int maxLon; - private static int maxLat; - private static int ncols; - private static int nrows; - private static int[] pixels; + private static int minLon; + private static int minLat; + private static int maxLon; + private static int maxLat; + private static int ncols; + private static int nrows; + private static int[] pixels; - public static void main( String[] args) throws Exception + public static void main( String[] args ) throws Exception + { + if ( args.length == 8 ) { - if ( args.length == 8 ) - { - doConvert( args[0], args[1], - Double.parseDouble( args[2] ), Double.parseDouble( args[3] ), Double.parseDouble( args[4] ), Double.parseDouble( args[5] ), - Integer.parseInt( args[6] ), Integer.parseInt( args[7] ) ); - } - else if ( args.length == 4 ) - { - int lon0 = Integer.parseInt( args[0] ); - int lat0 = Integer.parseInt( args[1] ); - String inputFile = "traffic/E" + lon0 + "_N" + lat0 + ".trf"; - for( int lon = lon0; lon < lon0+5; lon++ ) - for( int lat = lat0; lat < lat0+5; lat++ ) - { - String imageFile = "traffic_pics/E" + lon + "_N" + lat + ".png"; - System.out.println( "file=" + inputFile + " image=" + imageFile ); - doConvert( inputFile, imageFile, lon, lat, lon+1, lat+1, Integer.parseInt( args[2] ), Integer.parseInt( args[3] ) ); - } - } - + doConvert( args[0], args[1], Double.parseDouble( args[2] ), Double.parseDouble( args[3] ), Double.parseDouble( args[4] ), + Double.parseDouble( args[5] ), Integer.parseInt( args[6] ), Integer.parseInt( args[7] ) ); } - - public static void doConvert( String inputFile, String imageFile, double lon0, double lat0, double lon1, double lat1, - int cols, int rows ) throws Exception - { - OsmTrafficMap trafficMap = new OsmTrafficMap(); - minLon = (int)(lon0 * 1000000 + 180000000); - maxLon = (int)(lon1 * 1000000 + 180000000); - minLat = (int)(lat0 * 1000000 + 90000000); - maxLat = (int)(lat1 * 1000000 + 90000000); - ncols = cols; - nrows = rows; - - long[] keys = trafficMap.load( new File( inputFile ), minLon, minLat, maxLon, maxLat, true ); - - pixels = new int[cols*rows]; - - int[] tclasses = new int[] { 1,2,3,4,5,6,7, -1 }; - for( int tclass : tclasses ) - { - for(long key : keys ) + else if ( args.length == 4 ) + { + int lon0 = Integer.parseInt( args[0] ); + int lat0 = Integer.parseInt( args[1] ); + String inputFile = "traffic/E" + lon0 + "_N" + lat0 + ".trf"; + for ( int lon = lon0; lon < lon0 + 5; lon++ ) + for ( int lat = lat0; lat < lat0 + 5; lat++ ) { - OsmTrafficMap.OsmTrafficElement e = trafficMap.getElement(key ); - while( e != null ) - { - long key2 = e.node2; - e = e.next; - int trafficClass = trafficMap.getTrafficClass( key, key2 ); - if ( trafficClass != tclass ) continue; + String imageFile = "traffic_pics/E" + lon + "_N" + lat + ".png"; + System.out.println( "file=" + inputFile + " image=" + imageFile ); + doConvert( inputFile, imageFile, lon, lat, lon + 1, lat + 1, Integer.parseInt( args[2] ), Integer.parseInt( args[3] ) ); + } + } - int[] from = getImagePosition( key ); - int[] to = getImagePosition( key2 ); - - int rgb = 0; - if ( trafficClass == -1 ) rgb = 0x0000ff; // blue - else if ( trafficClass == 1 ) rgb = 0x404040; // dark grey - else if ( trafficClass == 2 ) rgb = 0xa0a0a0; // light grey - else if ( trafficClass == 3 ) rgb = 0x00ff00; // green - else if ( trafficClass == 4 ) rgb = 0xf4e500; // yellow - else if ( trafficClass == 5 ) rgb = 0xf18e1c; // orange - else if ( trafficClass == 6 ) rgb = 0xe32322; // red - else if ( trafficClass == 7 ) rgb = 0xc0327d; // pink - if ( rgb != 0 ) - { - drawLine( from, to, rgb ); - } + } + + public static void doConvert( String inputFile, String imageFile, double lon0, double lat0, double lon1, double lat1, int cols, int rows ) + throws Exception + { + OsmTrafficMap trafficMap = new OsmTrafficMap(); + minLon = (int) ( lon0 * 1000000 + 180000000 ); + maxLon = (int) ( lon1 * 1000000 + 180000000 ); + minLat = (int) ( lat0 * 1000000 + 90000000 ); + maxLat = (int) ( lat1 * 1000000 + 90000000 ); + ncols = cols; + nrows = rows; + + long[] keys = trafficMap.load( new File( inputFile ), minLon, minLat, maxLon, maxLat, true ); + + pixels = new int[cols * rows]; + + int[] tclasses = new int[] + { 1, 2, 3, 4, 5, 6, 7, -1 }; + for ( int tclass : tclasses ) + { + for ( long key : keys ) + { + OsmTrafficMap.OsmTrafficElement e = trafficMap.getElement( key ); + while (e != null) + { + long key2 = e.node2; + e = e.next; + int trafficClass = trafficMap.getTrafficClass( key, key2 ); + if ( trafficClass != tclass ) + continue; + + int[] from = getImagePosition( key ); + int[] to = getImagePosition( key2 ); + + int rgb = 0; + if ( trafficClass == -1 ) rgb = 0x0000ff; // blue + else if ( trafficClass == 1 ) rgb = 0x404040; // dark grey + else if ( trafficClass == 2 ) rgb = 0xa0a0a0; // light grey + else if ( trafficClass == 3 ) rgb = 0x00ff00; // green + else if ( trafficClass == 4 ) rgb = 0xf4e500; // yellow + else if ( trafficClass == 5 ) rgb = 0xf18e1c; // orange + else if ( trafficClass == 6 ) rgb = 0xe32322; // red + else if ( trafficClass == 7 ) rgb = 0xc0327d; // pink + if ( rgb != 0 ) + { + drawLine( from, to, rgb ); } } } - - - Raster2Png r2p = new Raster2Png( Raster2Png.FILTER_NONE, 6, cols, rows, pixels ); - byte[] png = r2p.pngEncode( ); - - System.out.println( "got png of size: " + png.length ); - DataOutputStream dos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( imageFile ) ) ); - dos.write(png); - dos.close(); } - - private static void drawLine( int[] from, int[] to, int rgb ) - { - int ix = from[0]; - int iy = from[1]; - int ixx = to[0]; - int iyy = to[1]; - - int sx = ixx > ix ? 1 : -1; - int sy = iyy > iy ? 1 : -1; - - int dx = (ixx-ix)*sx; - int dy = (iyy-iy)*sy; - - int sum = 0; - - for(;;) - { - drawPixel( ix, iy, rgb ); - if ( ix == ixx && iy == iyy ) break; - if ( Math.abs( sum+dx ) < Math.abs( sum-dy ) ) - { - iy+= sy; - sum += dx; - } - else - { - ix+= sx; - sum -= dy; - } + byte[] png = new Raster2Png().pngEncode( cols, rows, pixels ); + + System.out.println( "got png of size: " + png.length ); + DataOutputStream dos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( imageFile ) ) ); + dos.write( png ); + dos.close(); + } + + private static void drawLine( int[] from, int[] to, int rgb ) + { + int ix = from[0]; + int iy = from[1]; + int ixx = to[0]; + int iyy = to[1]; + + int sx = ixx > ix ? 1 : -1; + int sy = iyy > iy ? 1 : -1; + + int dx = ( ixx - ix ) * sx; + int dy = ( iyy - iy ) * sy; + + int sum = 0; + + for ( ;; ) + { + drawPixel( ix, iy, rgb ); + if ( ix == ixx && iy == iyy ) + break; + + if ( Math.abs( sum + dx ) < Math.abs( sum - dy ) ) + { + iy += sy; + sum += dx; + } + else + { + ix += sx; + sum -= dy; } } - - private static void drawPixel( int ix, int iy, int rgb ) + } + + private static void drawPixel( int ix, int iy, int rgb ) + { + if ( ix >= 0 && ix < ncols && iy >= 0 && iy < nrows ) { - if ( ix >= 0 && ix < ncols && iy >= 0 && iy < nrows ) - { - pixels[ (nrows-1-iy)*ncols + ix ] = rgb; - } - } - - private static int[] getImagePosition( long key ) - { - int ilon = (int)(key >> 32); - int ilat = (int)(key & 0xffffffff); - double lonDelta = maxLon-minLon; - double latDelta = maxLat-minLat; - int[] res = new int[2]; - res[0] = (int)( ( (ilon-minLon)/lonDelta ) *ncols ); - res[1] = (int)( ( (ilat-minLat)/latDelta ) *nrows ); - return res; + pixels[( nrows - 1 - iy ) * ncols + ix] = rgb; } + } + + private static int[] getImagePosition( long key ) + { + int ilon = (int) ( key >> 32 ); + int ilat = (int) ( key & 0xffffffff ); + double lonDelta = maxLon - minLon; + double latDelta = maxLat - minLat; + int[] res = new int[2]; + res[0] = (int) ( ( ( ilon - minLon ) / lonDelta ) * ncols ); + res[1] = (int) ( ( ( ilat - minLat ) / latDelta ) * nrows ); + return res; + } } diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/StorageConfigHelper.java b/brouter-mapaccess/src/main/java/btools/mapaccess/StorageConfigHelper.java index 6e2a382..923d05d 100644 --- a/brouter-mapaccess/src/main/java/btools/mapaccess/StorageConfigHelper.java +++ b/brouter-mapaccess/src/main/java/btools/mapaccess/StorageConfigHelper.java @@ -11,45 +11,52 @@ import java.io.FileReader; public class StorageConfigHelper { - public static File getSecondarySegmentDir( String segmentDir ) - { - return getStorageLocation( segmentDir, "secondary_segment_dir=" ); - } + public static File getSecondarySegmentDir( String segmentDir ) + { + return getStorageLocation( segmentDir, "secondary_segment_dir=" ); + } - public static File getAdditionalMaptoolDir( String segmentDir ) - { - return getStorageLocation( segmentDir, "additional_maptool_dir=" ); - } + public static File getAdditionalMaptoolDir( String segmentDir ) + { + return getStorageLocation( segmentDir, "additional_maptool_dir=" ); + } - private static File getStorageLocation( String segmentDir, String tag ) - { - File res = null; - BufferedReader br = null; - String configFile = segmentDir + "/storageconfig.txt"; + private static File getStorageLocation( String segmentDir, String tag ) + { + File res = null; + BufferedReader br = null; + String configFile = segmentDir + "/storageconfig.txt"; + try + { + br = new BufferedReader( new FileReader( configFile ) ); + for ( ;; ) + { + String line = br.readLine(); + if ( line == null ) break; + line = line.trim(); + if ( line.startsWith( "#" ) ) continue; + if ( line.startsWith( tag ) ) + { + String path = line.substring( tag.length() ).trim(); + res = path.startsWith( "/" ) ? new File( path ) : new File( new File( segmentDir ), path ); + if ( !res.exists() ) res = null; + break; + } + } + } + catch (Exception e) { /* ignore */ } + finally + { + if ( br != null ) + { try { - br = new BufferedReader( new FileReader (configFile ) ); - for(;;) - { - String line = br.readLine(); - if ( line == null ) break; - line = line.trim(); - if ( line.startsWith( "#") ) continue; - if ( line.startsWith( tag ) ) - { - String path = line.substring( tag.length() ).trim(); - res = path.startsWith( "/" ) ? new File( path ) : new File( new File( segmentDir ) , path ); - if ( !res.exists() ) res = null; - break; - } - } + br.close(); } - catch( Exception e ) {} - finally - { - if ( br != null ) try { br.close(); } catch( Exception ee ) {} - } - return res; - } + catch (Exception ee) { /* ignore */ } + } + } + return res; + } } diff --git a/brouter-routing-app/AndroidManifest.xml b/brouter-routing-app/AndroidManifest.xml index 3763706..f933813 100644 --- a/brouter-routing-app/AndroidManifest.xml +++ b/brouter-routing-app/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="9" + android:versionName="1.3.2" package="btools.routingapp"> /brouter directory and start a new setup by calling the " - + "BRouter App again." ) - .setPositiveButton( "OK", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - finish(); - } - }); - return builder.create(); - case DIALOG_ROUTINGMODES_ID: - builder = new AlertDialog.Builder(this); - builder.setTitle( message ); - builder.setMultiChoiceItems(routingModes, routingModesChecked, new DialogInterface.OnMultiChoiceClickListener() { - @Override - public void onClick(DialogInterface dialog, int which, - boolean isChecked) { - routingModesChecked[which] = isChecked; - } - }); - builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - mBRouterView.configureService(routingModes,routingModesChecked); - } - }); - return builder.create(); - case DIALOG_EXCEPTION_ID: - builder = new AlertDialog.Builder(this); - builder.setTitle( "An Error occured" ) - .setMessage( errorMessage ) - .setPositiveButton( "OK", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - mBRouterView.continueProcessing(); - } - }); - return builder.create(); - case DIALOG_TEXTENTRY_ID: - builder = new AlertDialog.Builder(this); - builder.setTitle("Enter SDCARD base dir:"); - builder.setMessage(message); - final EditText input = new EditText(this); - input.setText( defaultbasedir ); - builder.setView(input); - builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - String basedir = input.getText().toString(); - mBRouterView.startSetup(basedir, true ); - } - }); - return builder.create(); - case DIALOG_SELECTBASEDIR_ID: - builder = new AlertDialog.Builder(this); - builder.setTitle("Select an SDCARD base dir:"); - builder.setSingleChoiceItems(basedirOptions, 0, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int item ) - { - selectedBasedir = item; - } - }); - builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) - { - if ( selectedBasedir < availableBasedirs.size() ) - { - mBRouterView.startSetup(availableBasedirs.get(selectedBasedir), true ); - } - else - { - showDialog( DIALOG_TEXTENTRY_ID ); - } - } - }); - return builder.create(); - case DIALOG_VIASELECT_ID: - builder = new AlertDialog.Builder(this); - builder.setTitle("Check VIA Selection:"); - builder.setMultiChoiceItems(availableVias, getCheckedBooleanArray( availableVias.length ), - new DialogInterface.OnMultiChoiceClickListener() { - @Override - public void onClick(DialogInterface dialog, int which, - boolean isChecked) { - if (isChecked) - { - selectedVias.add(availableVias[which]); - } - else - { - selectedVias.remove(availableVias[which]); - } - } - }); - builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - mBRouterView.updateViaList( selectedVias ); - mBRouterView.startProcessing(selectedProfile); - } - }); - return builder.create(); - case DIALOG_NOGOSELECT_ID: - builder = new AlertDialog.Builder(this); - builder.setTitle("Check NoGo Selection:"); - String[] nogoNames = new String[nogoList.size()]; - for( int i=0; i 0 ? "Select to/via" : "Select from" ); - builder.setItems(availableWaypoints, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int item) { - mBRouterView.updateWaypointList( availableWaypoints[item] ); - mBRouterView.startProcessing(selectedProfile); - } - }); - return builder.create(); - - default: - return null; + public void onClick( DialogInterface dialog, int item ) + { + selectedProfile = availableProfiles[item]; + mBRouterView.startProcessing( selectedProfile ); } + } ); + return builder.create(); + case DIALOG_MAINACTION_ID: + builder = new AlertDialog.Builder( this ); + builder.setTitle( "Select Main Action" ); + builder.setItems( new String[] + { "Download Manager", "BRouter App" }, new DialogInterface.OnClickListener() + { + public void onClick( DialogInterface dialog, int item ) + { + if ( item == 0 ) + startDownloadManager(); + else + showDialog( DIALOG_SELECTPROFILE_ID ); + } + } ); + return builder.create(); + case DIALOG_SHOW_DM_INFO_ID: + builder = new AlertDialog.Builder( this ); + builder + .setTitle( "BRouter Download Manager" ) + .setMessage( + "*** Attention: ***\n\n" + "The Download Manager is used to download routing-data " + + "files which can be up to 100MB each. Do not start the Download Manager " + "on a cellular data connection without a data plan! " + + "Download speed is restricted to 2 MBit/s." ).setPositiveButton( "I know", new DialogInterface.OnClickListener() + { + public void onClick( DialogInterface dialog, int id ) + { + Intent intent = new Intent( BRouterActivity.this, BInstallerActivity.class ); + startActivity( intent ); + finish(); + } + } ).setNegativeButton( "Cancel", new DialogInterface.OnClickListener() + { + public void onClick( DialogInterface dialog, int id ) + { + finish(); + } + } ); + return builder.create(); + case DIALOG_OLDDATAHINT_ID: + builder = new AlertDialog.Builder( this ); + builder + .setTitle( "Local setup needs reset" ) + .setMessage( + "You are currently using an old version of the lookup-table " + "together with routing data made for this old table. " + + "Before downloading new datafiles made for the new table, " + + "you have to reset your local setup by 'moving away' (or deleting) " + + "your /brouter directory and start a new setup by calling the " + "BRouter App again." ) + .setPositiveButton( "OK", new DialogInterface.OnClickListener() + { + public void onClick( DialogInterface dialog, int id ) + { + finish(); + } + } ); + return builder.create(); + case DIALOG_ROUTINGMODES_ID: + builder = new AlertDialog.Builder( this ); + builder.setTitle( message ); + builder.setMultiChoiceItems( routingModes, routingModesChecked, new DialogInterface.OnMultiChoiceClickListener() + { + @Override + public void onClick( DialogInterface dialog, int which, boolean isChecked ) + { + routingModesChecked[which] = isChecked; + } + } ); + builder.setPositiveButton( "Ok", new DialogInterface.OnClickListener() + { + public void onClick( DialogInterface dialog, int whichButton ) + { + mBRouterView.configureService( routingModes, routingModesChecked ); + } + } ); + return builder.create(); + case DIALOG_EXCEPTION_ID: + builder = new AlertDialog.Builder( this ); + builder.setTitle( "An Error occured" ).setMessage( errorMessage ).setPositiveButton( "OK", new DialogInterface.OnClickListener() + { + public void onClick( DialogInterface dialog, int id ) + { + mBRouterView.continueProcessing(); + } + } ); + return builder.create(); + case DIALOG_TEXTENTRY_ID: + builder = new AlertDialog.Builder( this ); + builder.setTitle( "Enter SDCARD base dir:" ); + builder.setMessage( message ); + final EditText input = new EditText( this ); + input.setText( defaultbasedir ); + builder.setView( input ); + builder.setPositiveButton( "Ok", new DialogInterface.OnClickListener() + { + public void onClick( DialogInterface dialog, int whichButton ) + { + String basedir = input.getText().toString(); + mBRouterView.startSetup( basedir, true ); + } + } ); + return builder.create(); + case DIALOG_SELECTBASEDIR_ID: + builder = new AlertDialog.Builder( this ); + builder.setTitle( "Select an SDCARD base dir:" ); + builder.setSingleChoiceItems( basedirOptions, 0, new DialogInterface.OnClickListener() + { + @Override + public void onClick( DialogInterface dialog, int item ) + { + selectedBasedir = item; + } + } ); + builder.setPositiveButton( "Ok", new DialogInterface.OnClickListener() + { + public void onClick( DialogInterface dialog, int whichButton ) + { + if ( selectedBasedir < availableBasedirs.size() ) + { + mBRouterView.startSetup( availableBasedirs.get( selectedBasedir ), true ); + } + else + { + showDialog( DIALOG_TEXTENTRY_ID ); + } + } + } ); + return builder.create(); + case DIALOG_VIASELECT_ID: + builder = new AlertDialog.Builder( this ); + builder.setTitle( "Check VIA Selection:" ); + builder.setMultiChoiceItems( availableVias, getCheckedBooleanArray( availableVias.length ), new DialogInterface.OnMultiChoiceClickListener() + { + @Override + public void onClick( DialogInterface dialog, int which, boolean isChecked ) + { + if ( isChecked ) + { + selectedVias.add( availableVias[which] ); + } + else + { + selectedVias.remove( availableVias[which] ); + } + } + } ); + builder.setPositiveButton( "Ok", new DialogInterface.OnClickListener() + { + public void onClick( DialogInterface dialog, int whichButton ) + { + mBRouterView.updateViaList( selectedVias ); + mBRouterView.startProcessing( selectedProfile ); + } + } ); + return builder.create(); + case DIALOG_NOGOSELECT_ID: + builder = new AlertDialog.Builder( this ); + builder.setTitle( "Check NoGo Selection:" ); + String[] nogoNames = new String[nogoList.size()]; + for ( int i = 0; i < nogoList.size(); i++ ) + nogoNames[i] = nogoList.get( i ).name; + final boolean[] nogoEnabled = getCheckedBooleanArray( nogoList.size() ); + builder.setMultiChoiceItems( nogoNames, getCheckedBooleanArray( nogoNames.length ), new DialogInterface.OnMultiChoiceClickListener() + { + @Override + public void onClick( DialogInterface dialog, int which, boolean isChecked ) + { + nogoEnabled[which] = isChecked; + } + } ); + builder.setPositiveButton( "Ok", new DialogInterface.OnClickListener() + { + public void onClick( DialogInterface dialog, int whichButton ) + { + mBRouterView.updateNogoList( nogoEnabled ); + mBRouterView.startProcessing( selectedProfile ); + } + } ); + return builder.create(); + case DIALOG_SHOWRESULT_ID: + String leftLabel = wpCount < 0 ? "Exit" : ( wpCount == 0 ? "Select from" : "Select to/via" ); + String rightLabel = wpCount < 2 ? "Server-Mode" : "Calc Route"; + builder = new AlertDialog.Builder( this ); + builder.setTitle( title ).setMessage( errorMessage ).setPositiveButton( leftLabel, new DialogInterface.OnClickListener() + { + public void onClick( DialogInterface dialog, int id ) + { + if ( wpCount < 0 ) + finish(); + else + mBRouterView.pickWaypoints(); + } + } ).setNegativeButton( rightLabel, new DialogInterface.OnClickListener() + { + public void onClick( DialogInterface dialog, int id ) + { + if ( wpCount < 2 ) + mBRouterView.startConfigureService(); + else + { + mBRouterView.finishWaypointSelection(); + mBRouterView.startProcessing( selectedProfile ); + } + } + } ); + return builder.create(); + case DIALOG_MODECONFIGOVERVIEW_ID: + builder = new AlertDialog.Builder( this ); + builder.setTitle( "Success" ).setMessage( message ).setPositiveButton( "Exit", new DialogInterface.OnClickListener() + { + public void onClick( DialogInterface dialog, int id ) + { + finish(); + } + } ); + return builder.create(); + case DIALOG_PICKWAYPOINT_ID: + builder = new AlertDialog.Builder( this ); + builder.setTitle( wpCount > 0 ? "Select to/via" : "Select from" ); + builder.setItems( availableWaypoints, new DialogInterface.OnClickListener() + { + public void onClick( DialogInterface dialog, int item ) + { + mBRouterView.updateWaypointList( availableWaypoints[item] ); + mBRouterView.startProcessing( selectedProfile ); + } + } ); + return builder.create(); + default: + return null; } + } - private boolean[] getCheckedBooleanArray( int size ) + private boolean[] getCheckedBooleanArray( int size ) + { + boolean[] checked = new boolean[size]; + for ( int i = 0; i < checked.length; i++ ) checked[i] = true; + return checked; + } + + private String[] availableProfiles; + private String selectedProfile = null; + + private List availableBasedirs; + private String[] basedirOptions; + private int selectedBasedir; + + private String[] availableWaypoints; + + private String[] routingModes; + private boolean[] routingModesChecked; + + private String defaultbasedir = null; + private String message = null; + + private String[] availableVias; + private Set selectedVias; + + private List nogoList; + + public boolean isOnline() + { + ConnectivityManager cm = (ConnectivityManager) getSystemService( Context.CONNECTIVITY_SERVICE ); + + return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnectedOrConnecting(); + } + + @SuppressWarnings("deprecation") + public void selectProfile( String[] items ) + { + availableProfiles = items; + + // if we have internet access, first show the main action dialog + if ( isOnline() ) { - boolean[] checked = new boolean[size]; - for( int i=0; i availableBasedirs; - private String[] basedirOptions; - private int selectedBasedir; - - private String[] availableWaypoints; - - private String[] routingModes; - private boolean[] routingModesChecked; - - private String defaultbasedir = null; - private String message = null; - - private String[] availableVias; - private Set selectedVias; - - private List nogoList; - - public boolean isOnline() { - ConnectivityManager cm = - (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); - - return cm.getActiveNetworkInfo() != null && - cm.getActiveNetworkInfo().isConnectedOrConnecting(); - } - - @SuppressWarnings("deprecation") - public void selectProfile( String[] items ) + else { - availableProfiles = items; - - // if we have internet access, first show the main action dialog - if ( isOnline() ) - { - showDialog( DIALOG_MAINACTION_ID ); - } - else - { - showDialog( DIALOG_SELECTPROFILE_ID ); - } + showDialog( DIALOG_SELECTPROFILE_ID ); } + } - @SuppressWarnings("deprecation") - public void startDownloadManager() + @SuppressWarnings("deprecation") + public void startDownloadManager() + { + if ( !mBRouterView.hasUpToDateLookups() ) { - if ( !mBRouterView.hasUpToDateLookups() ) - { - showDialog( DIALOG_OLDDATAHINT_ID ); - } - else - { - showDialog( DIALOG_SHOW_DM_INFO_ID ); - } + showDialog( DIALOG_OLDDATAHINT_ID ); } - - @SuppressWarnings("deprecation") - public void selectBasedir( List items, String defaultBasedir, String message ) + else { - this.defaultbasedir = defaultBasedir; - this.message = message; - availableBasedirs = new ArrayList(); - ArrayList dirFreeSizes = new ArrayList(); - for( String d : items ) + showDialog( DIALOG_SHOW_DM_INFO_ID ); + } + } + + @SuppressWarnings("deprecation") + public void selectBasedir( List items, String defaultBasedir, String message ) + { + this.defaultbasedir = defaultBasedir; + this.message = message; + availableBasedirs = new ArrayList(); + ArrayList dirFreeSizes = new ArrayList(); + for ( String d : items ) + { + try { - try - { - StatFs stat = new StatFs(d); - long size = (long)stat.getAvailableBlocks()*stat.getBlockSize(); + StatFs stat = new StatFs( d ); + long size = (long) stat.getAvailableBlocks() * stat.getBlockSize(); int idx = 0; - while ( idx < availableBasedirs.size() && dirFreeSizes.get(idx).longValue() > size ) idx++; + while (idx < availableBasedirs.size() && dirFreeSizes.get( idx ).longValue() > size) + idx++; availableBasedirs.add( idx, d ); dirFreeSizes.add( idx, Long.valueOf( size ) ); - } - catch( Exception e ) { /* ignore */ } } - - basedirOptions= new String[items.size() + 1]; - int bdidx = 0; - DecimalFormat df = new DecimalFormat( "###0.00" ); - for( int idx=0; idx( availableVias.length ); + for ( String via : items ) + selectedVias.add( via ); + showDialog( DIALOG_VIASELECT_ID ); + } + + @SuppressWarnings("deprecation") + public void selectWaypoint( String[] items ) + { + availableWaypoints = items; + showNewDialog( DIALOG_PICKWAYPOINT_ID ); + } + + @SuppressWarnings("deprecation") + public void selectNogos( List nogoList ) + { + this.nogoList = nogoList; + showDialog( DIALOG_NOGOSELECT_ID ); + } + + private Set dialogIds = new HashSet(); + + private void showNewDialog( int id ) + { + if ( dialogIds.contains( Integer.valueOf( id ) ) ) { - this.message = message; - showDialog( DIALOG_MODECONFIGOVERVIEW_ID ); - } - - - @SuppressWarnings("deprecation") - public void selectVias( String[] items ) - { - availableVias = items; - selectedVias = new HashSet(availableVias.length); - for( String via : items ) selectedVias.add( via ); - showDialog( DIALOG_VIASELECT_ID ); + removeDialog( id ); } + dialogIds.add( Integer.valueOf( id ) ); + showDialog( id ); + } - @SuppressWarnings("deprecation") - public void selectWaypoint( String[] items ) - { - availableWaypoints = items; - showNewDialog( DIALOG_PICKWAYPOINT_ID ); - } + private String errorMessage; + private String title; + private int wpCount; - @SuppressWarnings("deprecation") - public void selectNogos( List nogoList ) - { - this.nogoList = nogoList; - showDialog( DIALOG_NOGOSELECT_ID ); - } + @SuppressWarnings("deprecation") + public void showErrorMessage( String msg ) + { + errorMessage = msg; + showNewDialog( DIALOG_EXCEPTION_ID ); + } - private Set dialogIds = new HashSet(); - - private void showNewDialog( int id ) - { - if ( dialogIds.contains( Integer.valueOf( id ) ) ) - { - removeDialog( id ); - } - dialogIds.add( Integer.valueOf( id ) ); - showDialog( id ); - } - - private String errorMessage; - private String title; - private int wpCount; + @SuppressWarnings("deprecation") + public void showResultMessage( String title, String msg, int wpCount ) + { + errorMessage = msg; + this.title = title; + this.wpCount = wpCount; + showNewDialog( DIALOG_SHOWRESULT_ID ); + } - @SuppressWarnings("deprecation") - public void showErrorMessage( String msg ) - { - errorMessage = msg; - showNewDialog( DIALOG_EXCEPTION_ID ); - } + @Override + protected void onResume() + { + super.onResume(); + /* + * when the activity is resumed, we acquire a wake-lock so that the screen + * stays on, since the user will likely not be fiddling with the screen or + * buttons. + */ + mWakeLock.acquire(); + } - @SuppressWarnings("deprecation") - public void showResultMessage( String title, String msg, int wpCount ) - { - errorMessage = msg; - this.title = title; - this.wpCount = wpCount; - showNewDialog( DIALOG_SHOWRESULT_ID ); - } + @Override + protected void onPause() + { + super.onPause(); + /* + * When the activity is paused, we make sure to stop the router + */ - @Override - protected void onResume() { - super.onResume(); - /* - * when the activity is resumed, we acquire a wake-lock so that the - * screen stays on, since the user will likely not be fiddling with the - * screen or buttons. - */ - mWakeLock.acquire(); + // Stop the simulation + mBRouterView.stopRouting(); - // Start the simulation - mBRouterView.startSimulation(); - - - } - - @Override - protected void onPause() { - super.onPause(); - /* - * When the activity is paused, we make sure to stop the simulation, - * release our sensor resources and wake locks - */ - - // Stop the simulation - mBRouterView.stopSimulation(); - - // and release our wake-lock - mWakeLock.release(); - - - } - - @Override - public void onInit(int i) - { - } + // and release our wake-lock + mWakeLock.release(); + } + @Override + public void onInit( int i ) + { + } } diff --git a/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java b/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java index c190dbf..fa8341d 100644 --- a/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java +++ b/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java @@ -40,796 +40,910 @@ import btools.router.RoutingHelper; public class BRouterView extends View { - RoutingEngine cr; - private int imgw; - private int imgh; + RoutingEngine cr; + private int imgw; + private int imgh; - private int centerLon; - private int centerLat; - private double scaleLon; - private double scaleLat; - private List wpList; - private List nogoList; - private List nogoVetoList; - private OsmTrack rawTrack; - - private String modesDir; - private String tracksDir; - private String segmentDir; - private String profileDir; - private String profilePath; - private String profileName; - private String sourceHint; - private boolean waitingForSelection = false; + private int centerLon; + private int centerLat; + private double scaleLon; + private double scaleLat; + private List wpList; + private List nogoList; + private List nogoVetoList; + private OsmTrack rawTrack; - private boolean needsViaSelection; - private boolean needsNogoSelection; - private boolean needsWaypointSelection; + private String modesDir; + private String tracksDir; + private String segmentDir; + private String profileDir; + private String profilePath; + private String profileName; + private String sourceHint; + private boolean waitingForSelection = false; - private long lastDataTime = System.currentTimeMillis(); + private boolean needsViaSelection; + private boolean needsNogoSelection; + private boolean needsWaypointSelection; - private CoordinateReader cor; + private long lastDataTime = System.currentTimeMillis(); - private int[] imgPixels; + private CoordinateReader cor; - - public void startSimulation() { - } + private int[] imgPixels; - public void stopSimulation() { - if ( cr != null ) cr.terminate(); - } + public void stopRouting() + { + if ( cr != null ) cr.terminate(); + } - public BRouterView(Context context) { - super(context); - } - - public void init() + public BRouterView( Context context ) + { + super( context ); + } + + 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 + String baseDir = ConfigHelper.getBaseDir( getContext() ); + // check if valid + boolean bdValid = false; + if ( baseDir != null ) + { + File bd = new File( baseDir ); + bdValid = bd.isDirectory(); + File brd = new File( bd, "brouter" ); + if ( brd.isDirectory() ) { - DisplayMetrics metrics = new DisplayMetrics(); - ((Activity)getContext()).getWindowManager().getDefaultDisplay().getMetrics(metrics); - imgw = metrics.widthPixels; - imgh = metrics.heightPixels; - - // get base dir from private file - String baseDir = ConfigHelper.getBaseDir( getContext() ); - // check if valid - boolean bdValid = false; - if ( baseDir != null ) - { - File bd = new File( baseDir ); - bdValid = bd.isDirectory(); - File brd = new File( bd, "brouter" ); - if ( brd.isDirectory() ) - { - 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( getStorageDirectories(), guessBaseDir(), message ); - waitingForSelection = true; + startSetup( baseDir, false ); + return; } + } + String message = baseDir == null ? "(no basedir configured previously)" : "(previous basedir " + baseDir + + ( bdValid ? " does not contain 'brouter' subfolder)" : " is not valid)" ); - public void startSetup( String baseDir, boolean storeBasedir ) + ( (BRouterActivity) getContext() ).selectBasedir( 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( String baseDir, boolean storeBasedir ) + { + cor = null; + try + { + File fbd = new File( baseDir ); + if ( !fbd.isDirectory() ) + { + throw new IllegalArgumentException( "Base-directory " + baseDir + " is not a directory " ); + } + if ( storeBasedir ) + { + // Android 4.4 patch: try extend the basedir if not valid + File td = new File( fbd, "brouter" ); + try { - cor = null; - try - { - File fbd = new File( baseDir ); - if ( !fbd.isDirectory() ) - { - throw new IllegalArgumentException( "Base-directory " + baseDir + " is not a directory " ); - } - if ( storeBasedir ) - { - // Android 4.4 patch: try extend the basedir if not valid - File td = new File( fbd, "brouter" ); - try { td.mkdir(); } catch ( Exception e ) {}; - if ( !td.isDirectory() ) - { - File td1 = new File( fbd, "Android/data/btools/routingapp" ); - try { td1.mkdirs(); } catch ( Exception e ) {}; - td = new File( td1, "brouter" ); - try { td.mkdir(); } catch ( Exception e ) {}; - if ( td.isDirectory() ) fbd = td1; - } - - ConfigHelper.writeBaseDir( getContext(), baseDir ); - } - String basedir = fbd.getAbsolutePath(); - AppLogger.log( "using basedir: " + basedir ); - - // create missing directories - assertDirectoryExists( "project directory", basedir + "/brouter", null ); - segmentDir = basedir + "/brouter/segments4"; - assertDirectoryExists( "data directory", segmentDir, "segments4.zip" ); - profileDir = basedir + "/brouter/profiles2"; - assertDirectoryExists( "profile directory", profileDir, "profiles2.zip" ); - modesDir = basedir + "/brouter/modes"; - assertDirectoryExists( "modes directory", modesDir, "modes.zip" ); - assertDirectoryExists( "readmes directory", basedir + "/brouter/readmes", "readmes.zip" ); - - cor = CoordinateReader.obtainValidReader( basedir, segmentDir ); - wpList = cor.waypoints; - nogoList = cor.nogopoints; - nogoVetoList = new ArrayList(); - - sourceHint = "(coordinate-source: " + cor.basedir + cor.rootdir + ")"; - - needsViaSelection = wpList.size() > 2; - needsNogoSelection = nogoList.size() > 0; - needsWaypointSelection = wpList.size() == 0; - - if ( cor.tracksdir != null ) - { - tracksDir = cor.basedir + cor.tracksdir; - assertDirectoryExists( "track directory", tracksDir, null ); - - // output redirect: look for a pointerfile in tracksdir - File tracksDirPointer = new File( tracksDir + "/brouter.redirect" ); - if ( tracksDirPointer.isFile() ) - { - tracksDir = readSingleLineFile( tracksDirPointer ); - if ( tracksDir == null ) throw new IllegalArgumentException( "redirect pointer file is empty: " + tracksDirPointer ); - if ( !(new File( tracksDir ).isDirectory()) ) throw new IllegalArgumentException( - "redirect pointer file " + tracksDirPointer + " does not point to a directory: " + tracksDir ); - } - } - - String[] fileNames = new File( profileDir ).list(); - ArrayList profiles = new ArrayList(); - - 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; - } - if ( !lookupsFound ) - { - throw new IllegalArgumentException( "The profile-directory " + profileDir - + " does not contain the lookups.dat file." - + " see www.dr-brenschede.de/brouter for setup instructions." ); - } - if ( profiles.size() == 0 ) - { - throw new IllegalArgumentException( "The profile-directory " + profileDir - + " contains no routing profiles (*.brf)." - + " see www.dr-brenschede.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 ); - } - waitingForSelection = true; + td.mkdir(); } - - public boolean hasUpToDateLookups() + catch (Exception e) {} + if ( !td.isDirectory() ) { - 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 selectedVias ) - { - ArrayList 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; - - Map allpoints = cor.allpoints; - if ( allpoints == null ) - { - allpoints = new TreeMap(); - cor.allpoints = allpoints; - try { cor.readFromTo(); } catch ( Exception e ) { msg = "Error reading waypoints: " + e.toString(); } - if ( allpoints.size() < 2 ) msg = "coordinate source does not contain enough waypoints: " + allpoints.size(); - if ( allpoints.size() > 100 ) msg = "coordinate source contains too much waypoints: " + allpoints.size() + "(please use from/to/via names)"; - } - if ( allpoints.size() < 1 ) msg = "no more wayoints available!"; - - if ( msg != null ) - { - ((BRouterActivity)getContext()).showErrorMessage( msg ); - } - else - { - String[] wpts = new String[allpoints.size()]; - int i = 0; - for( OsmNodeNamed wp : allpoints.values() ) wpts[i++] = wp.name; - ((BRouterActivity)getContext()).selectWaypoint( wpts ); - } - } - - public void updateWaypointList( String waypoint ) - { - wpList.add( cor.allpoints.get( waypoint ) ); - cor.allpoints.remove( waypoint ); - } - - public void finishWaypointSelection() - { - needsWaypointSelection = false; - } - - public void startProcessing( String profile ) - { - profilePath = profileDir + "/" + profile + ".brf"; - profileName = profile; - - if ( needsViaSelection ) - { - needsViaSelection = false; - String[] availableVias = new String[wpList.size()-2]; - for( int viaidx=0; viaidx0?"->" : "") + wpList.get(i).name; - } - ((BRouterActivity)getContext()).showResultMessage( "Select Action", msg, wpList.size() ); - return; - } - + File td1 = new File( fbd, "Android/data/btools/routingapp" ); try { - waitingForSelection = false; - - RoutingContext rc = new RoutingContext(); - - // TODO: TEST! - // rc.rawTrackPath = "/mnt/sdcard/brouter/modes/bicycle_fast_rawtrack.dat"; - - rc.localFunction = profilePath; - - 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 = n.ilon > maxlon ? n.ilon : maxlon; - minlon = n.ilon < minlon ? n.ilon : minlon; - maxlat = n.ilat > maxlat ? n.ilat : maxlat; - minlat = n.ilat < minlat ? 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 coslat = Math.cos( ((centerLat / 1000000.) - 90.) / 57.3 ) ; - double difflon = maxlon - minlon; - double difflat = maxlat - minlat; - - scaleLon = imgw / (difflon*1.5); - scaleLat = imgh / (difflat*1.5); - if ( scaleLon < scaleLat*coslat ) scaleLat = scaleLon/coslat; - else scaleLon = scaleLat*coslat; - - startTime = System.currentTimeMillis(); - rc.prepareNogoPoints( nogoList ); - rc.nogopoints = nogoList; - - 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 void assertDirectoryExists( String message, String path, String assetZip ) - { - File f = new File( path ); - if ( !f.exists() ) - { - f.mkdirs(); - // 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(); - FileOutputStream fos = new FileOutputStream( new File( f, name ) ); - - for(;;) - { - int len = zis.read( data, 0, 1024 ); - if ( len < 0 ) break; - fos.write( data, 0, len ); - } - fos.close(); - } - is.close(); - } - catch( IOException io ) - { - throw new RuntimeException( "error expanding " + assetZip + ": " + io ); - } - - } + td1.mkdirs(); } - if ( !f.exists() || !f.isDirectory() ) throw new IllegalArgumentException( message + ": " + path + " cannot be created" ); - } - - 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 * 1000000. * scaleLat); - 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 ); - } - } - - @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 _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 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 result = "version = BRouter-1.3.1\n" - + "distance = " + cr.getDistance()/1000. + " km\n" - + "filtered ascend = " + cr.getAscend() + " m\n" - + "plain ascend = " + cr.getPlainAscend(); - - rawTrack = cr.getFoundRawTrack(); - - String title = "Success"; - if ( cr.getAlternativeIndex() > 0 ) title += " / " + cr.getAlternativeIndex() + ". Alternative"; - - ((BRouterActivity)getContext()).showResultMessage( title, result, -1 ); - 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 basedirGuesses = new ArrayList(); - basedirGuesses.add( basedir.getAbsolutePath() ); + td.mkdir(); + } + catch (Exception e) {} + if ( td.isDirectory() ) + fbd = td1; + } - if ( bd2.exists() ) - { - basedir = bd2; - basedirGuesses.add( basedir.getAbsolutePath() ); - } + ConfigHelper.writeBaseDir( getContext(), baseDir ); + } + String basedir = fbd.getAbsolutePath(); + AppLogger.log( "using basedir: " + basedir ); - ArrayList rl = new ArrayList(); - 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; - } + // create missing directories + assertDirectoryExists( "project directory", basedir + "/brouter", null ); + segmentDir = basedir + "/brouter/segments4"; + if ( assertDirectoryExists( "data directory", segmentDir, "segments4.zip" ) ) + { + ConfigMigration.tryMigrateStorageConfig( + new File( basedir + "/brouter/segments3/storageconfig.txt" ), + new File( basedir + "/brouter/segments4/storageconfig.txt" ) ); + } + profileDir = basedir + "/brouter/profiles2"; + assertDirectoryExists( "profile directory", profileDir, "profiles2.zip" ); + modesDir = basedir + "/brouter/modes"; + assertDirectoryExists( "modes directory", modesDir, "modes.zip" ); + assertDirectoryExists( "readmes directory", basedir + "/brouter/readmes", "readmes.zip" ); + + cor = CoordinateReader.obtainValidReader( basedir, segmentDir ); + wpList = cor.waypoints; + nogoList = cor.nogopoints; + nogoVetoList = new ArrayList(); + + sourceHint = "(coordinate-source: " + cor.basedir + cor.rootdir + ")"; + + needsViaSelection = wpList.size() > 2; + needsNogoSelection = nogoList.size() > 0; + needsWaypointSelection = wpList.size() == 0; + + if ( cor.tracksdir != null ) + { + tracksDir = cor.basedir + cor.tracksdir; + assertDirectoryExists( "track directory", tracksDir, null ); + + // output redirect: look for a pointerfile in tracksdir + File tracksDirPointer = new File( tracksDir + "/brouter.redirect" ); + if ( tracksDirPointer.isFile() ) + { + tracksDir = readSingleLineFile( tracksDirPointer ); + if ( tracksDir == null ) + throw new IllegalArgumentException( "redirect pointer file is empty: " + tracksDirPointer ); + if ( !( new File( 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 ) { - System.out.println( "guessBaseDir:" + e ); + tracksDir = basedir + "/brouter"; } - return basedir.getAbsolutePath(); } + } - public void writeRawTrackToMode( String mode ) + String[] fileNames = new File( profileDir ).list(); + ArrayList profiles = new ArrayList(); + + boolean lookupsFound = false; + for ( String fileName : fileNames ) + { + if ( fileName.endsWith( ".brf" ) ) { - // plus eventually the raw track for re-use - String rawTrackPath = modesDir + "/" + mode + "_rawtrack.dat"; - if ( rawTrack != null ) - { - try - { - rawTrack.writeBinary( rawTrackPath ); - } - catch( Exception e ) {} - } - else - { - new File( rawTrackPath ).delete(); - } + profiles.add( fileName.substring( 0, fileName.length() - 4 ) ); } - - public void startConfigureService() + if ( fileName.equals( "lookups.dat" ) ) + lookupsFound = true; + } + if ( !lookupsFound ) + { + throw new IllegalArgumentException( "The profile-directory " + profileDir + " does not contain the lookups.dat file." + + " see www.dr-brenschede.de/brouter for setup instructions." ); + } + if ( profiles.size() == 0 ) + { + throw new IllegalArgumentException( "The profile-directory " + profileDir + " contains no routing profiles (*.brf)." + + " see www.dr-brenschede.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 ); + } + waitingForSelection = true; + } + + + 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 selectedVias ) + { + ArrayList 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 = "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.ilat != 0 ) { - String[] modes = new String[] { - "foot_short", "foot_fast", - "bicycle_short", "bicycle_fast", - "motorcar_short", "motorcar_fast" - }; - boolean[] modesChecked = new boolean[6]; - - // parse global section of profile for mode preselection - BExpressionMetaData meta = new BExpressionMetaData(); - BExpressionContextGlobal expctxGlobal = new BExpressionContextGlobal( meta ); - meta.readMetaData( new File( profileDir, "lookups.dat" ) ); - expctxGlobal.parseFile( new File( profilePath ), null ); - expctxGlobal.evaluate( new int[0] ); - boolean isFoot = 0.f != expctxGlobal.getVariableValue( "validForFoot", 0.f ); - boolean isBike = 0.f != expctxGlobal.getVariableValue( "validForBikes", 0.f ); - boolean isCar = 0.f != expctxGlobal.getVariableValue( "validForCars", 0.f ); - - if ( isFoot || isBike || isCar ) - { - modesChecked[ 0 ] = isFoot; - modesChecked[ 1 ] = isFoot; - modesChecked[ 2 ] = isBike; - modesChecked[ 3 ] = isBike; - modesChecked[ 4 ] = isCar; - modesChecked[ 5 ] = isCar; - } - else - { - for( int i=0; i<6; i++) - { - modesChecked[i] = true; - } - } - String msg = "Choose service-modes to configure (" + profileName + " [" + nogoVetoList.size() + "])"; - - ((BRouterActivity)getContext()).selectRoutingModes( modes, modesChecked, msg ); + wpList.add( wp ); } + return; + } + } + } - public void configureService(String[] routingModes, boolean[] checkedModes) + public void finishWaypointSelection() + { + needsWaypointSelection = false; + } + + public void startProcessing( String profile ) + { + 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 = "no from/to found\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, wpList.size() ); + return; + } + + try + { + waitingForSelection = false; + + RoutingContext rc = new RoutingContext(); + + rc.localFunction = profilePath; + + 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 = n.ilon > maxlon ? n.ilon : maxlon; + minlon = n.ilon < minlon ? n.ilon : minlon; + maxlat = n.ilat > maxlat ? n.ilat : maxlat; + minlat = n.ilat < minlat ? n.ilat : minlat; + if ( prev != null ) { - // read in current config - TreeMap 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 e ) {} - finally - { - if ( br != null ) try { br.close(); } catch( Exception ee ) {} - } + plain_distance += n.calcDistance( prev ); + } + prev = n; + } + toast( "Plain distance = " + plain_distance / 1000. + " km" ); - // 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 ); - } - } + centerLon = ( maxlon + minlon ) / 2; + centerLat = ( maxlat + minlat ) / 2; - - // no write new config - BufferedWriter bw = null; - StringBuilder msg = new StringBuilder( "Mode mapping is now:\n" ); - msg.append( "( [..] counts nogo-vetos)\n" ); - try + double coslat = Math.cos( ( ( centerLat / 1000000. ) - 90. ) / 57.3 ); + double difflon = maxlon - minlon; + double difflat = maxlat - minlat; + + scaleLon = imgw / ( difflon * 1.5 ); + scaleLat = imgh / ( difflat * 1.5 ); + if ( scaleLon < scaleLat * coslat ) + scaleLat = scaleLon / coslat; + else + scaleLon = scaleLat * coslat; + + startTime = System.currentTimeMillis(); + rc.prepareNogoPoints( nogoList ); + rc.nogopoints = nogoList; + + 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, String path, String assetZip ) + { + File f = new File( path ); + if ( !f.exists() ) + { + f.mkdirs(); + // 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 ( ;; ) { - bw = new BufferedWriter( new FileWriter ( modesFile ) ); - for( ServiceModeConfig smc : map.values() ) + ZipEntry ze = zis.getNextEntry(); + if ( ze == null ) + break; + String name = ze.getName(); + FileOutputStream fos = new FileOutputStream( new File( f, name ) ); + + for ( ;; ) { - bw.write( smc.toLine() ); - bw.write( '\n' ); - msg.append( smc.toString() ).append( '\n' ); + int len = zis.read( data, 0, 1024 ); + if ( len < 0 ) + break; + fos.write( data, 0, len ); } + fos.close(); } - catch( Exception e ) {} - finally - { - if ( bw != null ) try { bw.close(); } catch( Exception ee ) {} - } - ((BRouterActivity)getContext()).showModeConfigOverview( msg.toString() ); + is.close(); + return true; + } + catch (IOException io) + { + throw new RuntimeException( "error expanding " + assetZip + ": " + io ); } - private String readSingleLineFile( File f ) - { - BufferedReader br = null; - try - { - br = new BufferedReader( new InputStreamReader ( new FileInputStream( f ) ) ); - return br.readLine(); - } - catch( Exception e ) { return null; } - finally - { - if ( br != null ) try { br.close(); } catch( Exception ee ) {} - } - } + } + } + if ( !f.exists() || !f.isDirectory() ) + throw new IllegalArgumentException( message + ": " + path + " cannot be created" ); + return false; + } - - private static List getStorageDirectories() - { - ArrayList res = new ArrayList(); - res.add( Environment.getExternalStorageDirectory().getPath() ); - BufferedReader br = null; - try - { - br = new BufferedReader(new FileReader("/proc/mounts")); - for(;;) - { - String line = br.readLine(); - if ( line == null ) break; - if (line.indexOf("vfat") < 0 && line.indexOf("/mnt") < 0 ) continue; - StringTokenizer tokens = new StringTokenizer(line, " "); - tokens.nextToken(); - String d = tokens.nextToken(); - boolean isExternalDir = false; - if ( line.contains( "/dev/block/vold" ) ) - { - isExternalDir = true; - String[] vetos = new String[] { "/mnt/secure", "/mnt/asec", "/mnt/obb", "/dev/mapper", "tmpfs", "/mnt/media_rw" }; - for( String v: vetos ) - { - if ( d.indexOf( v ) >= 0 ) - { - isExternalDir = false; - } - } - } - if ( isExternalDir ) - { - if ( !res.contains( d ) ) - { - res.add( d ); - } - } - } - } - catch ( Exception e) { /* ignore */ } - finally - { - if (br != null) { try { br.close(); } catch (Exception e) { /* ignore */ } } - } - return res; - } + 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 * 1000000. * scaleLat ); + 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 ); + } + } + + @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 _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 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 result = "version = BRouter-1.3.2\n" + "distance = " + cr.getDistance() / 1000. + " km\n" + "filtered ascend = " + cr.getAscend() + + " m\n" + "plain ascend = " + cr.getPlainAscend(); + + rawTrack = cr.getFoundRawTrack(); + + String title = "Success"; + if ( cr.getAlternativeIndex() > 0 ) + title += " / " + cr.getAlternativeIndex() + ". Alternative"; + + ( (BRouterActivity) getContext() ).showResultMessage( title, result, -1 ); + 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 ); + 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 basedirGuesses = new ArrayList(); + basedirGuesses.add( basedir.getAbsolutePath() ); + + if ( bd2.exists() ) + { + basedir = bd2; + basedirGuesses.add( basedir.getAbsolutePath() ); + } + + ArrayList rl = new ArrayList(); + 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(); + } + + public void writeRawTrackToMode( String mode ) + { + // plus eventually the raw track for re-use + String rawTrackPath = modesDir + "/" + mode + "_rawtrack.dat"; + 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]; + + // parse global section of profile for mode preselection + BExpressionMetaData meta = new BExpressionMetaData(); + BExpressionContextGlobal expctxGlobal = new BExpressionContextGlobal( meta ); + meta.readMetaData( new File( profileDir, "lookups.dat" ) ); + expctxGlobal.parseFile( new File( profilePath ), null ); + expctxGlobal.evaluate( new int[0] ); + boolean isFoot = 0.f != expctxGlobal.getVariableValue( "validForFoot", 0.f ); + boolean isBike = 0.f != expctxGlobal.getVariableValue( "validForBikes", 0.f ); + boolean isCar = 0.f != expctxGlobal.getVariableValue( "validForCars", 0.f ); + + if ( isFoot || isBike || isCar ) + { + modesChecked[0] = isFoot; + modesChecked[1] = isFoot; + modesChecked[2] = isBike; + modesChecked[3] = isBike; + modesChecked[4] = isCar; + modesChecked[5] = isCar; + } + else + { + for ( int i = 0; i < 6; i++ ) + { + modesChecked[i] = true; + } + } + 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 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 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( "( [..] 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 ) + { + BufferedReader br = null; + try + { + br = new BufferedReader( new InputStreamReader( new FileInputStream( f ) ) ); + return br.readLine(); + } + catch (Exception e) + { + return null; + } + finally + { + if ( br != null ) + try + { + br.close(); + } + catch (Exception ee) + { + } + } + } + + private static List getStorageDirectories() + { + ArrayList res = new ArrayList(); + res.add( Environment.getExternalStorageDirectory().getPath() ); + BufferedReader br = null; + try + { + br = new BufferedReader( new FileReader( "/proc/mounts" ) ); + for ( ;; ) + { + String line = br.readLine(); + if ( line == null ) + break; + if ( line.indexOf( "vfat" ) < 0 && line.indexOf( "/mnt" ) < 0 ) + continue; + StringTokenizer tokens = new StringTokenizer( line, " " ); + tokens.nextToken(); + String d = tokens.nextToken(); + boolean isExternalDir = false; + if ( line.contains( "/dev/block/vold" ) ) + { + isExternalDir = true; + String[] vetos = new String[] + { "/mnt/secure", "/mnt/asec", "/mnt/obb", "/dev/mapper", "tmpfs", "/mnt/media_rw" }; + for ( String v : vetos ) + { + if ( d.indexOf( v ) >= 0 ) + { + isExternalDir = false; + } + } + } + if ( isExternalDir ) + { + if ( !res.contains( d ) ) + { + res.add( d ); + } + } + } + } + catch (Exception e) + { /* ignore */ + } + finally + { + if ( br != null ) + { + try + { + br.close(); + } + catch (Exception e) + { /* ignore */ + } + } + } + return res; + } + +} diff --git a/brouter-routing-app/src/main/java/btools/routingapp/ConfigHelper.java b/brouter-routing-app/src/main/java/btools/routingapp/ConfigHelper.java index 720c9ac..af04f1a 100644 --- a/brouter-routing-app/src/main/java/btools/routingapp/ConfigHelper.java +++ b/brouter-routing-app/src/main/java/btools/routingapp/ConfigHelper.java @@ -9,43 +9,56 @@ import java.io.OutputStreamWriter; import android.content.Context; - -/** - * Decsription of a service config - */ public class ConfigHelper { - public static String getBaseDir( Context ctx ) - { - // get base dir from private file - InputStream configInput = null; - try - { - configInput = ctx.openFileInput( "config.dat" ); - BufferedReader br = new BufferedReader( new InputStreamReader (configInput ) ); - return br.readLine(); - } - catch( Exception e ) { return null; } - finally - { - if ( configInput != null ) try { configInput.close(); } catch( Exception ee ) {} - } - } + public static String getBaseDir( Context ctx ) + { + // get base dir from private file + InputStream configInput = null; + try + { + configInput = ctx.openFileInput( "config.dat" ); + BufferedReader br = new BufferedReader( new InputStreamReader( configInput ) ); + return br.readLine(); + } + catch (Exception e) + { + return null; + } + finally + { + if ( configInput != null ) + { + try + { + configInput.close(); + } + catch (Exception ee) + { + } + } + } + } - public static void writeBaseDir( Context ctx, String baseDir ) - { - BufferedWriter bw = null; - try - { - OutputStream configOutput = ctx.openFileOutput( "config.dat", Context.MODE_PRIVATE ); - bw = new BufferedWriter( new OutputStreamWriter (configOutput ) ); - bw.write( baseDir ); - bw.write( '\n' ); - } - catch( Exception e ) {} - finally - { - if ( bw != null ) try { bw.close(); } catch( Exception ee ) {} - } - } + public static void writeBaseDir( Context ctx, String baseDir ) + { + BufferedWriter bw = null; + try + { + OutputStream configOutput = ctx.openFileOutput( "config.dat", Context.MODE_PRIVATE ); + bw = new BufferedWriter( new OutputStreamWriter( configOutput ) ); + bw.write( baseDir ); + bw.write( '\n' ); + } + catch (Exception e){ /* ignore */ } + finally + { + if ( bw != null ) + try + { + bw.close(); + } + catch (Exception ee) { /* ignore */ } + } + } } diff --git a/brouter-routing-app/src/main/java/btools/routingapp/ConfigMigration.java b/brouter-routing-app/src/main/java/btools/routingapp/ConfigMigration.java new file mode 100644 index 0000000..99e78a5 --- /dev/null +++ b/brouter-routing-app/src/main/java/btools/routingapp/ConfigMigration.java @@ -0,0 +1,89 @@ +package btools.routingapp; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.util.ArrayList; +import java.util.List; + +public class ConfigMigration +{ + public static void tryMigrateStorageConfig( File srcFile, File dstFile ) + { + if ( !srcFile.exists() ) return; + + String ssd = null; + String amd = null; + + BufferedReader br = null; + BufferedWriter bw = null; + try + { + br = new BufferedReader( new FileReader( srcFile ) ); + for ( ;; ) + { + String line = br.readLine(); + if ( line == null ) break; + if ( line.trim().startsWith( "secondary_segment_dir=" ) ) + { + if ( !"secondary_segment_dir=../segments2".equals( line ) ) + { + ssd = line; + } + } + if ( line.trim().startsWith( "additional_maptool_dir=" ) ) + { + amd = line; + } + } + br.close(); + + List lines = new ArrayList(); + br = new BufferedReader( new FileReader( dstFile ) ); + for ( ;; ) + { + String line = br.readLine(); + if ( line == null ) break; + if ( ssd != null && line.trim().startsWith( "secondary_segment_dir=" ) ) + { + line = ssd; + } + if ( amd != null && line.trim().startsWith( "#additional_maptool_dir=" ) ) + { + line = amd; + } + lines.add( line ); + } + br.close(); + br = null; + + bw = new BufferedWriter( new FileWriter( dstFile ) ); + for( String line: lines ) + { + bw.write( line + "\n" ); + } + } + catch (Exception e) { /* ignore */ } + finally + { + if ( br != null ) + { + try + { + br.close(); + } + catch (Exception ee) { /* ignore */ } + } + if ( bw != null ) + { + try + { + bw.close(); + } + catch (Exception ee) { /* ignore */ } + } + } + } +} diff --git a/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReader.java b/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReader.java index 0cb00dc..523b7b9 100644 --- a/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReader.java +++ b/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReader.java @@ -4,8 +4,11 @@ import java.io.File; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.TreeMap; import android.os.Environment; import btools.router.OsmNodeNamed; @@ -22,7 +25,9 @@ public abstract class CoordinateReader public String rootdir; public String tracksdir; - public Map allpoints; + private Map> allpointsMap; + public List allpoints; + private HashMap pointmap; protected static String[] posnames @@ -35,6 +40,34 @@ public abstract class CoordinateReader public abstract long getTimeStamp() throws Exception; + public void readAllPoints() throws Exception + { + allpointsMap = new TreeMap>(); + readFromTo(); + allpoints = new ArrayList(); + Set names = new HashSet(); + for( String category : allpointsMap.keySet() ) + { + Map cat = allpointsMap.get( category ); + if ( cat.size() < 101 ) + { + for ( OsmNodeNamed wp : cat.values() ) + { + if ( names.add( wp.name ) ) + { + allpoints.add( wp ); + } + } + } + else + { + OsmNodeNamed nocatHint = new OsmNodeNamed(); + nocatHint.name = ""; + allpoints.add( nocatHint); + } + } + } + /* * read the from, to and via-positions from a gpx-file */ @@ -62,13 +95,23 @@ public abstract class CoordinateReader if ( fromToMissing ) waypoints.clear(); } - protected void checkAddPoint( OsmNodeNamed n ) + protected void checkAddPoint( String category, OsmNodeNamed n ) { - if ( allpoints != null ) - { - allpoints.put( n.name, n ); - return; - } + if ( allpointsMap != null ) + { + if ( category == null ) category = ""; + Map cat = allpointsMap.get( category ); + if ( cat == null ) + { + cat = new TreeMap(); + allpointsMap.put( category, cat ); + } + if ( cat.size() < 101 ) + { + cat.put( n.name, n ); + } + return; + } boolean isKnown = false; for( int i=0; i rl = new ArrayList(); + CoordinateReader cor = null; + ArrayList rl = new ArrayList(); - AppLogger.log( "adding standard maptool-base: " + basedir ); - rl.add( new CoordinateReaderOsmAnd(basedir) ); - rl.add( new CoordinateReaderLocus(basedir) ); - rl.add( new CoordinateReaderOrux(basedir) ); + AppLogger.log( "adding standard maptool-base: " + basedir ); + rl.add( new CoordinateReaderOsmAnd( basedir ) ); + rl.add( new CoordinateReaderLocus( basedir ) ); + rl.add( new CoordinateReaderOrux( basedir ) ); - // eventually add standard-sd - File standardbase = Environment.getExternalStorageDirectory(); - if ( standardbase != null ) - { - String base2 = standardbase.getAbsolutePath(); - if ( !base2.equals( basedir ) ) - { - AppLogger.log( "adding internal sd maptool-base: " + base2 ); - rl.add( new CoordinateReaderOsmAnd(base2) ); - rl.add( new CoordinateReaderLocus(base2) ); - rl.add( new CoordinateReaderOrux(base2) ); - } - } + // eventually add standard-sd + File standardbase = Environment.getExternalStorageDirectory(); + if ( standardbase != null ) + { + String base2 = standardbase.getAbsolutePath(); + if ( !base2.equals( basedir ) ) + { + AppLogger.log( "adding internal sd maptool-base: " + base2 ); + rl.add( new CoordinateReaderOsmAnd( base2 ) ); + rl.add( new CoordinateReaderLocus( base2 ) ); + rl.add( new CoordinateReaderOrux( base2 ) ); + } + } - // eventually add explicit directory - File additional = RoutingHelper.getAdditionalMaptoolDir(segmentDir); - if ( additional != null ) - { - String base3 = additional.getAbsolutePath(); - - AppLogger.log( "adding maptool-base from storage-config: " + base3 ); - - rl.add( new CoordinateReaderOsmAnd(base3) ); - rl.add( new CoordinateReaderLocus(base3) ); - rl.add( new CoordinateReaderOrux(base3) ); - } + // eventually add explicit directory + File additional = RoutingHelper.getAdditionalMaptoolDir( segmentDir ); + if ( additional != null ) + { + String base3 = additional.getAbsolutePath(); - long tmax = 0; - for( CoordinateReader r : rl ) - { - if ( AppLogger.isLogging() ) - { - AppLogger.log( "reading timestamp at systime " + new Date() ); - } + AppLogger.log( "adding maptool-base from storage-config: " + base3 ); - long t = r.getTimeStamp(); - - if ( t != 0 ) - { - if ( AppLogger.isLogging() ) - { - AppLogger.log( "found coordinate source at " + r.basedir + r.rootdir + " with timestamp " + new Date( t ) ); - } - } - - if ( t > tmax ) - { - tmax = t; - cor = r; - } - } - if ( cor == null ) - { - cor = new CoordinateReaderNone(); - } - cor.readFromTo(); - return cor; + rl.add( new CoordinateReaderOsmAnd( base3 ) ); + rl.add( new CoordinateReaderOsmAnd( base3, true ) ); + rl.add( new CoordinateReaderLocus( base3 ) ); + rl.add( new CoordinateReaderOrux( base3 ) ); + } + + long tmax = 0; + for ( CoordinateReader r : rl ) + { + if ( AppLogger.isLogging() ) + { + AppLogger.log( "reading timestamp at systime " + new Date() ); + } + + long t = r.getTimeStamp(); + + if ( t != 0 ) + { + if ( AppLogger.isLogging() ) + { + AppLogger.log( "found coordinate source at " + r.basedir + r.rootdir + " with timestamp " + new Date( t ) ); + } + } + + if ( t > tmax ) + { + tmax = t; + cor = r; + } + } + if ( cor == null ) + { + cor = new CoordinateReaderNone(); + } + cor.readFromTo(); + return cor; } } diff --git a/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderLocus.java b/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderLocus.java index e41568c..492aa2f 100644 --- a/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderLocus.java +++ b/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderLocus.java @@ -38,14 +38,16 @@ public class CoordinateReaderLocus extends CoordinateReader private void _readPointmap( String filename ) throws Exception { SQLiteDatabase myDataBase = SQLiteDatabase.openDatabase( filename, null, SQLiteDatabase.OPEN_READONLY); - Cursor c = myDataBase.rawQuery("SELECT name, longitude, latitude FROM waypoints", null); + + Cursor c = myDataBase.rawQuery("SELECT c.name, w.name, w.longitude, w.latitude FROM waypoints w, categories c where w.parent_id = c._id", null); while (c.moveToNext()) { OsmNodeNamed n = new OsmNodeNamed(); - n.name = c.getString(0); - n.ilon = (int)( ( Double.parseDouble( c.getString(1) ) + 180. )*1000000. + 0.5); - n.ilat = (int)( ( Double.parseDouble( c.getString(2) ) + 90. )*1000000. + 0.5); - checkAddPoint( n ); + String category = c.getString(0); + n.name = c.getString(1); + n.ilon = (int)( ( Double.parseDouble( c.getString(2) ) + 180. )*1000000. + 0.5); + n.ilat = (int)( ( Double.parseDouble( c.getString(3) ) + 90. )*1000000. + 0.5); + checkAddPoint( category, n ); } myDataBase.close(); } diff --git a/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderOrux.java b/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderOrux.java index 36f1af6..b275b25 100644 --- a/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderOrux.java +++ b/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderOrux.java @@ -38,14 +38,15 @@ public class CoordinateReaderOrux extends CoordinateReader private void _readPointmap( String filename ) throws Exception { SQLiteDatabase myDataBase = SQLiteDatabase.openDatabase( filename, null, SQLiteDatabase.OPEN_READONLY); - Cursor c = myDataBase.rawQuery("SELECT poiname, poilon, poilat FROM pois", null); + Cursor c = myDataBase.rawQuery("SELECT poiname, poilon, poilat, poifolder FROM pois", null); while (c.moveToNext()) { OsmNodeNamed n = new OsmNodeNamed(); n.name = c.getString(0); n.ilon = (int)( ( Double.parseDouble( c.getString(1) ) + 180. )*1000000. + 0.5); n.ilat = (int)( ( Double.parseDouble( c.getString(2) ) + 90. )*1000000. + 0.5); - checkAddPoint( n ); + String category = c.getString(3); + checkAddPoint( category, n ); } myDataBase.close(); } diff --git a/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderOsmAnd.java b/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderOsmAnd.java index bf8a22f..8d910fa 100644 --- a/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderOsmAnd.java +++ b/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReaderOsmAnd.java @@ -12,18 +12,35 @@ import btools.router.OsmNodeNamed; */ public class CoordinateReaderOsmAnd extends CoordinateReader { + private String osmandDir; + public CoordinateReaderOsmAnd( String basedir ) + { + this( basedir, false ); + } + + public CoordinateReaderOsmAnd( String basedir, boolean shortPath ) { super( basedir ); - tracksdir = "/osmand/tracks"; - rootdir = "/osmand"; + if ( shortPath ) + { + osmandDir = basedir; + tracksdir = "/tracks"; + rootdir = ""; + } + else + { + osmandDir = basedir + "/osmand"; + tracksdir = "/osmand/tracks"; + rootdir = "/osmand"; + } } @Override public long getTimeStamp() throws Exception { - long t1 = new File( basedir + "/osmand/favourites_bak.gpx" ).lastModified(); - long t2 = new File( basedir + "/osmand/favourites.gpx" ).lastModified(); + long t1 = new File( osmandDir + "/favourites_bak.gpx" ).lastModified(); + long t2 = new File( osmandDir + "/favourites.gpx" ).lastModified(); return t1 > t2 ? t1 : t2; } @@ -36,11 +53,11 @@ public class CoordinateReaderOsmAnd extends CoordinateReader { try { - _readPointmap( basedir + "/osmand/favourites_bak.gpx" ); + _readPointmap( osmandDir + "/favourites_bak.gpx" ); } catch( Exception e ) { - _readPointmap( basedir + "/osmand/favourites.gpx" ); + _readPointmap( osmandDir + "/favourites.gpx" ); } } @@ -78,7 +95,7 @@ public class CoordinateReaderOsmAnd extends CoordinateReader if ( idx11 >= 0 ) { n.name = line.substring( idx10, idx11 ).trim(); - checkAddPoint( n ); + checkAddPoint( "(one-for-all)", n ); } } } diff --git a/brouter-server/src/main/java/btools/server/BRouter.java b/brouter-server/src/main/java/btools/server/BRouter.java index f3ed3b3..4f01beb 100644 --- a/brouter-server/src/main/java/btools/server/BRouter.java +++ b/brouter-server/src/main/java/btools/server/BRouter.java @@ -88,7 +88,7 @@ public class BRouter } System.exit(0); } - System.out.println("BRouter 1.3.1 / 18102015 / abrensch"); + System.out.println("BRouter 1.3.2 / 31102015 / abrensch"); if ( args.length < 6 ) { System.out.println("Find routes in an OSM map"); diff --git a/brouter-server/src/main/java/btools/server/RouteServer.java b/brouter-server/src/main/java/btools/server/RouteServer.java index 2e3dd12..ae6b72a 100644 --- a/brouter-server/src/main/java/btools/server/RouteServer.java +++ b/brouter-server/src/main/java/btools/server/RouteServer.java @@ -155,7 +155,7 @@ public class RouteServer extends Thread public static void main(String[] args) throws Exception { - System.out.println("BRouter 1.3.1 / 18102015"); + System.out.println("BRouter 1.3.2 / 31102015"); if ( args.length != 5 ) { System.out.println("serve BRouter protocol"); diff --git a/brouter-util/src/main/java/btools/util/Raster2Png.java b/brouter-util/src/main/java/btools/util/Raster2Png.java index 775e497..42c8b31 100644 --- a/brouter-util/src/main/java/btools/util/Raster2Png.java +++ b/brouter-util/src/main/java/btools/util/Raster2Png.java @@ -1,464 +1,170 @@ package btools.util; -import java.io.*; -import java.util.zip.*; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.zip.CRC32; +import java.util.zip.Deflater; +import java.util.zip.DeflaterOutputStream; -public class Raster2Png extends Object { +public class Raster2Png extends ByteDataWriter +{ + /** Constants for filter (NONE) */ + public static final int FILTER_NONE = 0; - /** Constant specifying that alpha channel should be encoded. */ - public static final boolean ENCODE_ALPHA = true; + /** IHDR tag. */ + protected static final byte IHDR[] = { 73, 72, 68, 82 }; - /** Constant specifying that alpha channel should not be encoded. */ - public static final boolean NO_ALPHA = false; + /** IDAT tag. */ + protected static final byte IDAT[] = { 73, 68, 65, 84 }; - /** Constants for filter (NONE) */ - public static final int FILTER_NONE = 0; + /** IEND tag. */ + protected static final byte IEND[] = { 73, 69, 78, 68 }; - /** Constants for filter (SUB) */ - public static final int FILTER_SUB = 1; + /** geometry */ + protected int width, height; - /** Constants for filter (UP) */ - public static final int FILTER_UP = 2; + protected int[] imagePixels; - /** Constants for filter (LAST) */ - public static final int FILTER_LAST = 2; - - /** IHDR tag. */ - protected static final byte IHDR[] = {73, 72, 68, 82}; - - /** IDAT tag. */ - protected static final byte IDAT[] = {73, 68, 65, 84}; - - /** IEND tag. */ - protected static final byte IEND[] = {73, 69, 78, 68}; + /** CRC. */ + protected CRC32 crc = new CRC32(); - /** The png bytes. */ - protected byte[] pngBytes; + public Raster2Png() + { + super( null ); + } - /** The prior row. */ - protected byte[] priorRow; + /** + * Converts a pixel array to it's PNG equivalent + */ + public byte[] pngEncode( int width, int height, int[] imagePixels ) throws IOException + { + this.width = width; + this.height = height; + this.imagePixels = imagePixels; - /** The left bytes. */ - protected byte[] leftBytes; + // user a buffer large enough to hold the png + ab = new byte[( ( width + 1 ) * height * 3 ) + 200]; - /** The width. */ - protected int width, height; + byte[] pngIdBytes = + { -119, 80, 78, 71, 13, 10, 26, 10 }; + write( pngIdBytes ); + writeHeader(); + writeImageData(); + return toByteArray(); + } - /** The byte position. */ - protected int bytePos, maxPos; + /** + * Write a PNG "IHDR" chunk into the pngBytes array. + */ + protected void writeHeader() + { + writeInt( 13 ); + int startPos = aboffset; + write( IHDR ); + writeInt( width ); + writeInt( height ); + writeByte( 8 ); // bit depth + writeByte( 2 ); // direct model + writeByte( 0 ); // compression method + writeByte( 0 ); // filter method + writeByte( 0 ); // no interlace + crc.reset(); + crc.update( ab, startPos, aboffset - startPos ); + writeInt( (int) crc.getValue() ); + } - protected int[] imagePixels; + /** + * Write the image data into the pngBytes array. This will write one or more + * PNG "IDAT" chunks. In order to conserve memory, this method grabs as many + * rows as will fit into 32K bytes, or the whole image; whichever is less. + */ + protected void writeImageData() throws IOException + { + int rowsLeft = height; // number of rows remaining to write + int startRow = 0; // starting row to process this time through + int nRows; // how many rows to grab at a time - /** CRC. */ - protected CRC32 crc = new CRC32(); + byte[] scanLines; // the scan lines to be compressed + int scanPos; // where we are in the scan lines - /** The CRC value. */ - protected long crcValue; + byte[] compressedLines; // the resultant compressed lines + int nCompressed; // how big is the compressed area? - /** The filter type. */ - protected int filter; + int bytesPerPixel = 3; - /** The bytes-per-pixel. */ - protected int bytesPerPixel; + Deflater scrunch = new Deflater( 6 ); + ByteArrayOutputStream outBytes = new ByteArrayOutputStream( 1024 ); - /** The compression level. */ - protected int compressionLevel; - - private boolean encodeAlpha = false; - - /** - * Class constructor specifying filter to use and compression level. - * - * @param whichFilter 0=none, 1=sub, 2=up - * @param compLevel 0..9 - */ - public Raster2Png(int whichFilter, int compLevel, int width, int height, int[] imagePixels ) { - this.width = width; - this.height = height; - this.imagePixels = imagePixels; - - setFilter(whichFilter); - - if (compLevel >= 0 && compLevel <= 9) { - this.compressionLevel = compLevel; - } - } - - /** - * Creates an array of bytes that is the PNG equivalent of the current image, specifying - * whether to encode alpha or not. - * - * @param encodeAlpha boolean false=no alpha, true=encode alpha - * @return an array of bytes, or null if there was a problem - */ - public byte[] pngEncode() { - byte[] pngIdBytes = {-119, 80, 78, 71, 13, 10, 26, 10}; - - if (imagePixels == null) { - return null; - } - - /* - * start with an array that is big enough to hold all the pixels - * (plus filter bytes), and an extra 200 bytes for header info - */ - pngBytes = new byte[((width + 1) * height * 3) + 200]; - - /* - * keep track of largest byte written to the array - */ - maxPos = 0; - - bytePos = writeBytes(pngIdBytes, 0); - //hdrPos = bytePos; - writeHeader(); - //dataPos = bytePos; - if (writeImageData()) { - writeEnd(); - pngBytes = resizeByteArray(pngBytes, maxPos); - } - else { - pngBytes = null; - } - return pngBytes; - } - - /** - * Set the filter to use - * - * @param whichFilter from constant list - */ - public void setFilter(int whichFilter) { - this.filter = FILTER_NONE; - if (whichFilter <= FILTER_LAST) { - this.filter = whichFilter; - } - } - - /** - * Set the compression level to use - * - * @param level 0 through 9 - */ - public void setCompressionLevel(int level) { - if (level >= 0 && level <= 9) { - this.compressionLevel = level; - } - } - - /** - * Increase or decrease the length of a byte array. - * - * @param array The original array. - * @param newLength The length you wish the new array to have. - * @return Array of newly desired length. If shorter than the - * original, the trailing elements are truncated. - */ - protected byte[] resizeByteArray(byte[] array, int newLength) { - byte[] newArray = new byte[newLength]; - int oldLength = array.length; - - System.arraycopy(array, 0, newArray, 0, Math.min(oldLength, newLength)); - return newArray; - } - - /** - * Write an array of bytes into the pngBytes array. - * Note: This routine has the side effect of updating - * maxPos, the largest element written in the array. - * The array is resized by 1000 bytes or the length - * of the data to be written, whichever is larger. - * - * @param data The data to be written into pngBytes. - * @param offset The starting point to write to. - * @return The next place to be written to in the pngBytes array. - */ - protected int writeBytes(byte[] data, int offset) { - maxPos = Math.max(maxPos, offset + data.length); - if (data.length + offset > pngBytes.length) { - pngBytes = resizeByteArray(pngBytes, pngBytes.length + Math.max(1000, data.length)); - } - System.arraycopy(data, 0, pngBytes, offset, data.length); - return offset + data.length; - } - - /** - * Write an array of bytes into the pngBytes array, specifying number of bytes to write. - * Note: This routine has the side effect of updating - * maxPos, the largest element written in the array. - * The array is resized by 1000 bytes or the length - * of the data to be written, whichever is larger. - * - * @param data The data to be written into pngBytes. - * @param nBytes The number of bytes to be written. - * @param offset The starting point to write to. - * @return The next place to be written to in the pngBytes array. - */ - protected int writeBytes(byte[] data, int nBytes, int offset) { - maxPos = Math.max(maxPos, offset + nBytes); - if (nBytes + offset > pngBytes.length) { - pngBytes = resizeByteArray(pngBytes, pngBytes.length + Math.max(1000, nBytes)); - } - System.arraycopy(data, 0, pngBytes, offset, nBytes); - return offset + nBytes; - } - - /** - * Write a two-byte integer into the pngBytes array at a given position. - * - * @param n The integer to be written into pngBytes. - * @param offset The starting point to write to. - * @return The next place to be written to in the pngBytes array. - */ - protected int writeInt2(int n, int offset) { - byte[] temp = {(byte) ((n >> 8) & 0xff), (byte) (n & 0xff)}; - return writeBytes(temp, offset); - } - - /** - * Write a four-byte integer into the pngBytes array at a given position. - * - * @param n The integer to be written into pngBytes. - * @param offset The starting point to write to. - * @return The next place to be written to in the pngBytes array. - */ - protected int writeInt4(int n, int offset) { - byte[] temp = {(byte) ((n >> 24) & 0xff), - (byte) ((n >> 16) & 0xff), - (byte) ((n >> 8) & 0xff), - (byte) (n & 0xff)}; - return writeBytes(temp, offset); - } - - /** - * Write a single byte into the pngBytes array at a given position. - * - * @param b The integer to be written into pngBytes. - * @param offset The starting point to write to. - * @return The next place to be written to in the pngBytes array. - */ - protected int writeByte(int b, int offset) { - byte[] temp = {(byte) b}; - return writeBytes(temp, offset); - } - - /** - * Write a PNG "IHDR" chunk into the pngBytes array. - */ - protected void writeHeader() { - int startPos; - - startPos = bytePos = writeInt4(13, bytePos); - bytePos = writeBytes(IHDR, bytePos); - bytePos = writeInt4(width, bytePos); - bytePos = writeInt4(height, bytePos); - bytePos = writeByte(8, bytePos); // bit depth - bytePos = writeByte((encodeAlpha) ? 6 : 2, bytePos); // direct model - bytePos = writeByte(0, bytePos); // compression method - bytePos = writeByte(0, bytePos); // filter method - bytePos = writeByte(0, bytePos); // no interlace - crc.reset(); - crc.update(pngBytes, startPos, bytePos - startPos); - crcValue = crc.getValue(); - bytePos = writeInt4((int) crcValue, bytePos); - } - - /** - * Perform "sub" filtering on the given row. - * Uses temporary array leftBytes to store the original values - * of the previous pixels. The array is 16 bytes long, which - * will easily hold two-byte samples plus two-byte alpha. - * - * @param pixels The array holding the scan lines being built - * @param startPos Starting position within pixels of bytes to be filtered. - * @param width Width of a scanline in pixels. - */ - protected void filterSub(byte[] pixels, int startPos, int width) { - int i; - int offset = bytesPerPixel; - int actualStart = startPos + offset; - int nBytes = width * bytesPerPixel; - int leftInsert = offset; - int leftExtract = 0; - - for (i = actualStart; i < startPos + nBytes; i++) { - leftBytes[leftInsert] = pixels[i]; - pixels[i] = (byte) ((pixels[i] - leftBytes[leftExtract]) % 256); - leftInsert = (leftInsert + 1) % 0x0f; - leftExtract = (leftExtract + 1) % 0x0f; - } - } - - /** - * Perform "up" filtering on the given row. - * Side effect: refills the prior row with current row - * - * @param pixels The array holding the scan lines being built - * @param startPos Starting position within pixels of bytes to be filtered. - * @param width Width of a scanline in pixels. - */ - protected void filterUp(byte[] pixels, int startPos, int width) { - int i, nBytes; - byte currentByte; - - nBytes = width * bytesPerPixel; - - for (i = 0; i < nBytes; i++) { - currentByte = pixels[startPos + i]; - pixels[startPos + i] = (byte) ((pixels[startPos + i] - priorRow[i]) % 256); - priorRow[i] = currentByte; - } - } - - /** - * Write the image data into the pngBytes array. - * This will write one or more PNG "IDAT" chunks. In order - * to conserve memory, this method grabs as many rows as will - * fit into 32K bytes, or the whole image; whichever is less. - * - * - * @return true if no errors; false if error grabbing pixels - */ - protected boolean writeImageData() { - int rowsLeft = height; // number of rows remaining to write - int startRow = 0; // starting row to process this time through - int nRows; // how many rows to grab at a time - - byte[] scanLines; // the scan lines to be compressed - int scanPos; // where we are in the scan lines - int startPos; // where this line's actual pixels start (used for filtering) - - byte[] compressedLines; // the resultant compressed lines - int nCompressed; // how big is the compressed area? - - //int depth; // color depth ( handle only 8 or 32 ) - -// PixelGrabber pg; - - bytesPerPixel = (encodeAlpha) ? 4 : 3; - - Deflater scrunch = new Deflater(compressionLevel); - ByteArrayOutputStream outBytes = new ByteArrayOutputStream(1024); - - DeflaterOutputStream compBytes = new DeflaterOutputStream(outBytes, scrunch); - try { - while (rowsLeft > 0) { - nRows = Math.min(32767 / (width * (bytesPerPixel + 1)), rowsLeft); - nRows = Math.max( nRows, 1 ); - - int[] pixels = new int[width * nRows]; - - getPixels(startRow, nRows, pixels); - - /* - * Create a data chunk. scanLines adds "nRows" for - * the filter bytes. - */ - scanLines = new byte[width * nRows * bytesPerPixel + nRows]; - - if (filter == FILTER_SUB) { - leftBytes = new byte[16]; - } - if (filter == FILTER_UP) { - priorRow = new byte[width * bytesPerPixel]; - } - - scanPos = 0; - startPos = 1; - for (int i = 0; i < width * nRows; i++) { - if (i % width == 0) { - scanLines[scanPos++] = (byte) filter; - startPos = scanPos; - } - scanLines[scanPos++] = (byte) ((pixels[i] >> 16) & 0xff); - scanLines[scanPos++] = (byte) ((pixels[i] >> 8) & 0xff); - scanLines[scanPos++] = (byte) ((pixels[i]) & 0xff); - if (encodeAlpha) { - scanLines[scanPos++] = (byte) ((pixels[i] >> 24) & 0xff); - } - if ((i % width == width - 1) && (filter != FILTER_NONE)) { - if (filter == FILTER_SUB) { - filterSub(scanLines, startPos, width); - } - if (filter == FILTER_UP) { - filterUp(scanLines, startPos, width); - } - } - } - - /* - * Write these lines to the output area - */ - compBytes.write(scanLines, 0, scanPos); - - startRow += nRows; - rowsLeft -= nRows; - } - compBytes.close(); - - /* - * Write the compressed bytes - */ - compressedLines = outBytes.toByteArray(); - nCompressed = compressedLines.length; - - crc.reset(); - bytePos = writeInt4(nCompressed, bytePos); - bytePos = writeBytes(IDAT, bytePos); - crc.update(IDAT); - bytePos = writeBytes(compressedLines, nCompressed, bytePos); - crc.update(compressedLines, 0, nCompressed); - - crcValue = crc.getValue(); - bytePos = writeInt4((int) crcValue, bytePos); - scrunch.finish(); - return true; - } - catch (IOException e) { - System.err.println(e.toString()); - return false; - } - } - - /** - * Write a PNG "IEND" chunk into the pngBytes array. - */ - protected void writeEnd() { - bytePos = writeInt4(0, bytePos); - bytePos = writeBytes(IEND, bytePos); - crc.reset(); - crc.update(IEND); - crcValue = crc.getValue(); - bytePos = writeInt4((int) crcValue, bytePos); - } - - private void getPixels( int startRow, int nRows, int[] pixels) + DeflaterOutputStream compBytes = new DeflaterOutputStream( outBytes, scrunch ); + while (rowsLeft > 0) { - for( int i=0; i 2000 ) return 255; - int res = 0; - int div = 1; - while ( val > 0 ) - { - int d = val > 127 ? 127 : val; - val -= d; - res += d / div; - div *= 2; - } - return res < 255 ? res : 255; - } + nRows = Math.min( 32767 / ( width * ( bytesPerPixel + 1 ) ), rowsLeft ); + nRows = Math.max( nRows, 1 ); + int[] pixels = new int[width * nRows]; + + getPixels( startRow, nRows, pixels ); + + /* + * Create a data chunk. scanLines adds "nRows" for the filter bytes. + */ + scanLines = new byte[width * nRows * bytesPerPixel + nRows]; + + scanPos = 0; + for ( int i = 0; i < width * nRows; i++ ) + { + if ( i % width == 0 ) + { + scanLines[scanPos++] = (byte) FILTER_NONE; + } + scanLines[scanPos++] = (byte) ( ( pixels[i] >> 16 ) & 0xff ); + scanLines[scanPos++] = (byte) ( ( pixels[i] >> 8 ) & 0xff ); + scanLines[scanPos++] = (byte) ( ( pixels[i] ) & 0xff ); + } + + /* + * Write these lines to the output area + */ + compBytes.write( scanLines, 0, scanPos ); + + startRow += nRows; + rowsLeft -= nRows; + } + compBytes.close(); + + /* + * Write the compressed bytes + */ + compressedLines = outBytes.toByteArray(); + nCompressed = compressedLines.length; + + crc.reset(); + writeInt( nCompressed ); + write( IDAT ); + crc.update( IDAT ); + write( compressedLines ); + crc.update( compressedLines, 0, nCompressed ); + + writeInt( (int) crc.getValue() ); + scrunch.finish(); + + // Write a PNG "IEND" chunk into the pngBytes array. + writeInt( 0 ); + write( IEND ); + crc.reset(); + crc.update( IEND ); + writeInt( (int) crc.getValue() ); + } + + private void getPixels( int startRow, int nRows, int[] pixels ) + { + for ( int i = 0; i < nRows; i++ ) + { + int ir = i + startRow; + for ( int ic = 0; ic < width; ic++ ) + { + pixels[i * width + ic] = imagePixels[ir * width + ic]; + } + } + } }