This commit is contained in:
Arndt 2015-04-03 11:09:09 +02:00
commit 53c3df66f5
9 changed files with 359 additions and 150 deletions

View file

@ -26,6 +26,9 @@ import btools.util.FrozenLongMap;
public final class OsmTrack
{
// csv-header-line
private static final String MESSAGES_HEADER = "Longitude\tLatitude\tElevation\tDistance\tCostPerKm\tElevCost\tTurnCost\tNodeCost\tInitialCost\tOsmTags";
public MatchedWaypoint endPoint;
public long[] nogoChecksums;
@ -220,7 +223,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.1\" version=\"1.1\">\n" );
sb.append( " creator=\"BRouter-1.2\" version=\"1.1\">\n" );
sb.append( " <trk>\n" );
sb.append(" <name>").append(name).append("</name>\n");
sb.append( " <trkseg>\n" );
@ -304,7 +307,19 @@ public final class OsmTrack
sb.append( " \"track-length\": \"" ).append( distance ).append( "\",\n" );
sb.append( " \"filtered ascend\": \"" ).append( ascend ).append( "\",\n" );
sb.append( " \"plain-ascend\": \"" ).append( plainAscend ).append( "\",\n" );
sb.append( " \"cost\": \"" ).append( cost ).append( "\"\n" );
sb.append( " \"cost\": \"" ).append( cost ).append( "\",\n" );
sb.append( " \"messages\": [\n" );
sb.append( " [\"").append( MESSAGES_HEADER.replaceAll("\t", "\", \"") ).append( "\"],\n" );
for( OsmPathElement n : nodes )
{
if ( n.message != null )
{
sb.append( " [\"").append( n.message.replaceAll("\t", "\", \"") ).append( "\"],\n" );
}
}
sb.deleteCharAt( sb.lastIndexOf( "," ) );
sb.append( " ]\n" );
sb.append( " },\n" );
if ( iternity != null )
@ -361,10 +376,7 @@ public final class OsmTrack
public void writeMessages( BufferedWriter bw, RoutingContext rc ) throws Exception
{
// csv-header-line
String header = "Longitude\tLatitude\tElevation\tDistance\tCostPerKm\tElevCost\tTurnCost\tNodeCost\tInitialCost\tOsmTags";
dumpLine( bw, header );
dumpLine( bw, MESSAGES_HEADER );
for( OsmPathElement n : nodes )
{
if ( n.message != null )

View file

@ -1,5 +1,6 @@
package btools.expressions;
import java.util.StringTokenizer;
final class BExpression
{
@ -26,12 +27,28 @@ final class BExpression
private float numberValue;
private int variableIdx;
private int lookupNameIdx;
private int lookupValueIdx;
private int[] lookupValueIdxArray;
// Parse the expression and all subexpression
public static BExpression parse( BExpressionContext ctx, int level ) throws Exception
{
return parse( ctx, level, null );
}
private static BExpression parse( BExpressionContext ctx, int level, String optionalToken ) throws Exception
{
boolean brackets = false;
String operator = ctx.parseToken();
if ( optionalToken != null && optionalToken.equals( operator ) )
{
operator = ctx.parseToken();
}
if ( "(".equals( operator ) )
{
brackets = true;
operator = ctx.parseToken();
}
if ( operator == null )
{
if ( level == 0 ) return null;
@ -48,11 +65,17 @@ final class BExpression
BExpression exp = new BExpression();
int nops = 3;
boolean ifThenElse = false;
if ( "switch".equals( operator ) )
{
exp.typ = SWITCH_EXP;
}
else if ( "if".equals( operator ) )
{
exp.typ = SWITCH_EXP;
ifThenElse = true;
}
else
{
nops = 2; // check binary expressions
@ -105,17 +128,25 @@ final class BExpression
{
exp.typ = LOOKUP_EXP;
String name = operator.substring( 0, idx );
String value = operator.substring( idx+1 );
String values = operator.substring( idx+1 );
exp.lookupNameIdx = ctx.getLookupNameIdx( name );
if ( exp.lookupNameIdx < 0 )
{
throw new IllegalArgumentException( "unknown lookup name: " + name );
}
exp.lookupValueIdx = ctx.getLookupValueIdx( exp.lookupNameIdx, value );
if ( exp.lookupValueIdx < 0 )
StringTokenizer tk = new StringTokenizer( values, "|" );
int nt = tk.countTokens();
int nt2 = nt == 0 ? 1 : nt;
exp.lookupValueIdxArray = new int[nt2];
for( int ti=0; ti<nt2; ti++ )
{
throw new IllegalArgumentException( "unknown lookup value: " + value );
String value = ti < nt ? tk.nextToken() : "";
exp.lookupValueIdxArray[ti] = ctx.getLookupValueIdx( exp.lookupNameIdx, value );
if ( exp.lookupValueIdxArray[ti] < 0 )
{
throw new IllegalArgumentException( "unknown lookup value: " + value );
}
}
}
else if ( (idx = ctx.getVariableIdx( operator, false )) >= 0 )
@ -123,6 +154,16 @@ final class BExpression
exp.typ = VARIABLE_EXP;
exp.variableIdx = idx;
}
else if ( "true".equals( operator ) )
{
exp.numberValue = 1.f;
exp.typ = NUMBER_EXP;
}
else if ( "false".equals( operator ) )
{
exp.numberValue = 0.f;
exp.typ = NUMBER_EXP;
}
else
{
try
@ -139,11 +180,35 @@ final class BExpression
}
}
// parse operands
if ( nops > 0 ) exp.op1 = BExpression.parse( ctx, level+1 );
if ( nops > 1 ) exp.op2 = BExpression.parse( ctx, level+1 );
if ( nops > 2 ) exp.op3 = BExpression.parse( ctx, level+1 );
if ( nops > 0 )
{
exp.op1 = BExpression.parse( ctx, level+1, exp.typ == ASSIGN_EXP ? "=" : null );
}
if ( nops > 1 )
{
if ( ifThenElse ) checkExpectedToken( ctx, "then" );
exp.op2 = BExpression.parse( ctx, level+1, null );
}
if ( nops > 2 )
{
if ( ifThenElse ) checkExpectedToken( ctx, "else" );
exp.op3 = BExpression.parse( ctx, level+1, null );
}
if ( brackets )
{
checkExpectedToken( ctx, ")" );
}
return exp;
}
private static void checkExpectedToken( BExpressionContext ctx, String expected ) throws Exception
{
String token = ctx.parseToken();
if ( ! expected.equals( token ) )
{
throw new IllegalArgumentException( "unexpected token: " + token + ", expected: " + expected );
}
}
// Evaluate the expression
public float evaluate( BExpressionContext ctx )
@ -157,7 +222,7 @@ final class BExpression
case MAX_EXP: return max( op1.evaluate(ctx), op2.evaluate(ctx) );
case SWITCH_EXP: return op1.evaluate(ctx) != 0.f ? op2.evaluate(ctx) : op3.evaluate(ctx);
case ASSIGN_EXP: return ctx.assign( variableIdx, op1.evaluate(ctx) );
case LOOKUP_EXP: return ctx.getLookupMatch( lookupNameIdx, lookupValueIdx );
case LOOKUP_EXP: return ctx.getLookupMatch( lookupNameIdx, lookupValueIdxArray );
case NUMBER_EXP: return numberValue;
case VARIABLE_EXP: return ctx.getVariableValue( variableIdx );
case NOT_EXP: return op1.evaluate(ctx) == 0.f ? 1.f : 0.f;

View file

@ -19,6 +19,7 @@ import java.util.TreeMap;
import btools.util.BitCoderContext;
import btools.util.Crc32;
import java.util.Random;
public final class BExpressionContext
@ -172,7 +173,7 @@ public final class BExpressionContext
decode( ld2, false, ab );
for( int inum = 0; inum < lookupValues.size(); inum++ ) // loop over lookup names
{
if ( ld2[inum] != ld[inum] ) throw new RuntimeException( "assertion failed encoding " + getKeyValueDescription(false, ab) );
if ( ld2[inum] != ld[inum] ) throw new RuntimeException( "assertion failed encoding inum=" + inum + " val=" + ld[inum] + " " + getKeyValueDescription(false, ab) );
}
return ab;
@ -469,6 +470,51 @@ public final class BExpressionContext
return null;
}
/**
* generate random values for regression testing
*/
public int[] generateRandomValues( Random rnd )
{
int[] data = createNewLookupData();
data[0] = 2*rnd.nextInt( 2 ); // reverse-direction = 0 or 2
for( int inum = 1; inum < data.length; inum++ )
{
int nvalues = lookupValues.get( inum ).length;
data[inum] = 0;
if ( inum > 1 && rnd.nextInt( 10 ) > 0 ) continue; // tags other than highway only 10%
data[inum] = rnd.nextInt( nvalues );
}
lookupDataValid = true;
return data;
}
public void assertAllVariablesEqual( BExpressionContext other )
{
int nv = variableData.length;
int nv2 = other.variableData.length;
if ( nv != nv2 ) throw new RuntimeException( "mismatch in variable-count: " + nv + "<->" + nv2 );
for( int i=0; i<nv; i++ )
{
if ( variableData[i] != other.variableData[i] )
{
throw new RuntimeException( "mismatch in variable " + variableName(i) + " " + variableData[i] + "<->" + other.variableData[i]
+ "\ntags = " + getKeyValueDescription( false, encode() ) );
}
}
}
private String variableName( int idx )
{
for( Map.Entry<String,Integer> e : variableNumbers.entrySet() )
{
if ( e.getValue().intValue() == idx )
{
return e.getKey();
}
}
throw new RuntimeException( "no variable for index" + idx );
}
/**
* add a new lookup-value for the given name to the given lookupData array.
* If no array is given (null value passed), the value is added to
@ -705,9 +751,16 @@ public final class BExpressionContext
return minWriteIdx;
}
float getLookupMatch( int nameIdx, int valueIdx )
float getLookupMatch( int nameIdx, int[] valueIdxArray )
{
return lookupData[nameIdx] == valueIdx ? 1.0f : 0.0f;
for( int i=0; i<valueIdxArray.length; i++ )
{
if ( lookupData[nameIdx] == valueIdxArray[i] )
{
return 1.0f;
}
}
return 0.0f;
}
public int getLookupNameIdx( String name )

View file

@ -0,0 +1,59 @@
package btools.expressions;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
import btools.util.BitCoderContext;
import btools.util.Crc32;
import java.util.Random;
public final class ProfileComparator
{
public static void main( String[] args )
{
if ( args.length != 4 )
{
System.out.println( "usage: java ProfileComparator <lookup-file> <profile1> <profile2> <nsamples>" );
return;
}
File lookupFile = new File( args[0] );
File profile1File = new File( args[1] );
File profile2File = new File( args[2] );
int nsamples = Integer.parseInt( args[3] );
testContext( lookupFile, profile1File, profile2File, nsamples, "way" );
testContext( lookupFile, profile1File, profile2File, nsamples, "node" );
}
private static void testContext( File lookupFile, File profile1File, File profile2File, int nsamples, String contextName )
{
// read lookup.dat + profiles
BExpressionMetaData meta1 = new BExpressionMetaData();
BExpressionMetaData meta2 = new BExpressionMetaData();
BExpressionContext expctx1 = new BExpressionContext(contextName, 4096, meta1 );
BExpressionContext expctx2 = new BExpressionContext(contextName, 4096, meta2 );
meta1.readMetaData( lookupFile );
meta2.readMetaData( lookupFile );
expctx1.parseFile( profile1File, "global" );
expctx2.parseFile( profile2File, "global" );
Random rnd = new Random();
for( int i=0; i<nsamples; i++ )
{
int[] data = expctx1.generateRandomValues( rnd );
expctx1.evaluate( data );
expctx2.evaluate( data );
expctx1.assertAllVariablesEqual( expctx2 );
}
}
}

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="5"
android:versionName="1.1" package="btools.routingapp">
android:versionCode="6"
android:versionName="1.2" package="btools.routingapp">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".BRouterActivity"
android:label="@string/app_name"

View file

@ -536,7 +536,7 @@ private long startTime = 0L;
}
else
{
String result = "version = BRouter-1.1\n"
String result = "version = BRouter-1.2\n"
+ "distance = " + cr.getDistance()/1000. + " km\n"
+ "filtered ascend = " + cr.getAscend() + " m\n"
+ "plain ascend = " + cr.getPlainAscend();

View file

@ -67,20 +67,32 @@ public class RouteServer extends Thread
}
else if ( url.startsWith( PROFILE_UPLOAD_URL ) )
{
writeHttpHeader(bw, "application/json");
String profileId = null;
if ( url.length() > PROFILE_UPLOAD_URL.length() + 1 )
if ( getline.startsWith("OPTIONS") )
{
// e.g. /brouter/profile/custom_1400767688382
profileId = url.substring(PROFILE_UPLOAD_URL.length() + 1);
// handle CORS preflight request (Safari)
String corsHeaders = "Access-Control-Allow-Methods: GET, POST\n"
+ "Access-Control-Allow-Headers: Content-Type\n";
writeHttpHeader( bw, "text/plain", null, corsHeaders );
bw.flush();
return;
}
else
{
writeHttpHeader(bw, "application/json");
ProfileUploadHandler uploadHandler = new ProfileUploadHandler( serviceContext );
uploadHandler.handlePostRequest( profileId, br, bw );
String profileId = null;
if ( url.length() > PROFILE_UPLOAD_URL.length() + 1 )
{
// e.g. /brouter/profile/custom_1400767688382
profileId = url.substring(PROFILE_UPLOAD_URL.length() + 1);
}
bw.flush();
return;
ProfileUploadHandler uploadHandler = new ProfileUploadHandler( serviceContext );
uploadHandler.handlePostRequest( profileId, br, bw );
bw.flush();
return;
}
}
else
{
@ -126,7 +138,7 @@ public class RouteServer extends Thread
public static void main(String[] args) throws Exception
{
System.out.println("BRouter 1.1 / 27122014");
System.out.println("BRouter 1.2 / 07022015");
if ( args.length != 5 )
{
System.out.println("serve BRouter protocol");
@ -213,6 +225,11 @@ public class RouteServer extends Thread
}
private static void writeHttpHeader( BufferedWriter bw, String mimeType, String fileName ) throws IOException
{
writeHttpHeader( bw, mimeType, fileName, null);
}
private static void writeHttpHeader( BufferedWriter bw, String mimeType, String fileName, String headers ) throws IOException
{
// http-header
bw.write( "HTTP/1.1 200 OK\n" );
@ -223,6 +240,10 @@ public class RouteServer extends Thread
bw.write( "Content-Disposition: attachment; filename=" + fileName + "\n" );
}
bw.write( "Access-Control-Allow-Origin: *\n" );
if ( headers != null )
{
bw.write( headers );
}
bw.write( "\n" );
}
}

View file

@ -8,21 +8,21 @@
# Use the following switches to change behaviour
# (1=yes, 0=no):
assign consider_elevation 1 # set to 0 to ignore elevation in routing
assign allow_steps 1 # set to 0 to disallow steps
assign allow_ferries 1 # set to 0 to disallow ferries
assign ignore_cycleroutes 0 # set to 1 for better elevation results
assign stick_to_cycleroutes 0 # set to 1 to just follow cycleroutes
assign avoid_unsafe 0 # set to 1 to avoid standard highways
assign consider_elevation = true # set to false to ignore elevation in routing
assign allow_steps = true # set to false to disallow steps
assign allow_ferries = true # set to false to disallow ferries
assign ignore_cycleroutes = false # set to true for better elevation results
assign stick_to_cycleroutes = false # set to true to just follow cycleroutes
assign avoid_unsafe = false # set to true to avoid standard highways
assign validForBikes 1
assign validForBikes = true
# the elevation parameters
assign downhillcost switch consider_elevation 60 0
assign downhillcutoff 1.5
assign uphillcost 0
assign uphillcutoff 1.5
assign downhillcost = if consider_elevation then 60 else 0
assign downhillcutoff = 1.5
assign uphillcost = 0
assign uphillcutoff = 1.5
---context:way # following code refers to way-tags
@ -30,14 +30,25 @@ assign uphillcutoff 1.5
# pre-calculate some logical expressions
#
assign any_cycleroute or route_bicycle_icn=yes or route_bicycle_ncn=yes or route_bicycle_rcn=yes route_bicycle_lcn=yes
assign nodeaccessgranted or any_cycleroute lcn=yes
assign any_cycleroute =
if route_bicycle_icn=yes then true
else if route_bicycle_ncn=yes then true
else if route_bicycle_rcn=yes then true
else if route_bicycle_lcn=yes then true
else false
assign is_ldcr and any_cycleroute not ignore_cycleroutes
assign isbike or bicycle=yes or or bicycle=permissive bicycle=designated lcn=yes
assign ispaved or surface=paved or surface=asphalt or surface=concrete surface=paving_stones
assign isunpaved not or surface= or ispaved or surface=fine_gravel surface=cobblestone
assign probablyGood or ispaved and isbike not isunpaved
assign nodeaccessgranted =
if any_cycleroute then true
else lcn=yes
assign is_ldcr =
if ignore_cycleroutes then false
else any_cycleroute
assign isbike = or bicycle=yes or or bicycle=permissive bicycle=designated lcn=yes
assign ispaved = surface=paved|asphalt|concrete|paving_stones
assign isunpaved = not or surface= or ispaved surface=fine_gravel|cobblestone
assign probablyGood = or ispaved and isbike not isunpaved
#
@ -46,59 +57,53 @@ assign probablyGood or ispaved and isbike not isunpaved
# (Suppressing turncost while following longdistance-cycleways
# makes them a little bit more magnetic)
#
assign turncost switch is_ldcr 0 90
assign turncost = if is_ldcr then 0 else 90
#
# calculate the initial cost
# this is added to the total cost each time the costfactor
# changed
#
assign initialcost switch route=ferry 10000 0
assign initialcost = if route=ferry then 10000 else 0
#
# implicit access here just from the motorroad tag
# (implicit access rules from highway tag handled elsewhere)
#
assign defaultaccess
switch access=
not motorroad=yes
switch or access=private access=no
0
1
assign defaultaccess =
if access= then not motorroad=yes
else if access=private|no then false
else true
#
# calculate logical bike access
#
assign bikeaccess
or any_cycleroute
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
not or bicycle=private or bicycle=no bicycle=dismount
assign bikeaccess =
if any_cycleroute then true
else if bicycle= then
(
if vehicle= then defaultaccess
else not vehicle=private|no
)
else not bicycle=private|no|dismount
#
# calculate logical foot access
#
assign footaccess
or bikeaccess
or bicycle=dismount
switch foot=
defaultaccess
not or foot=private foot=no
assign footaccess =
if bikeaccess then true
else if bicycle=dismount then true
else if foot= then defaultaccess
else not foot=private|no
#
# if not bike-, but foot-acess, just a moderate penalty,
# otherwise access is forbidden
#
assign accesspenalty
switch bikeaccess
0
switch footaccess
4
100000
assign accesspenalty =
if bikeaccess then 0
else if footaccess then 4
else 100000
#
# handle one-ways. On primary roads, wrong-oneways should
@ -106,19 +111,21 @@ assign accesspenalty
# 4 to the costfactor (making it at least 5 - you are allowed
# to push your bike)
#
assign oneway
switch oneway=
junction=roundabout
or oneway=yes or oneway=true oneway=1
assign oneway =
if oneway= then junction=roundabout else oneway=yes|true|1
assign onewaypenalty =
if ( if reversedirection=yes then oneway else oneway=-1 ) then
(
if ( cycleway=opposite|opposite_lane|opposite_track ) then 0
else if ( oneway:bicycle=no ) then 0
else if ( highway=primary|primary_link ) then 50
else if ( highway=secondary|secondary_link ) then 30
else if ( highway=tertiary|tertiary_link ) then 20
else 4.0
)
else 0.0
assign onewaypenalty
switch switch reversedirection=yes oneway oneway=-1
switch or cycleway=opposite or cycleway=opposite_lane or cycleway=opposite_track oneway:bicycle=no 0
switch or highway=primary highway=primary_link 50
switch or highway=secondary highway=secondary_link 30
switch or highway=tertiary highway=tertiary_link 20
4.0
0.0
#
# calculate the cost-factor, which is the factor
@ -127,106 +134,98 @@ assign onewaypenalty
# must be >=1 and it's supposed to be close to 1 for
# the type of way the routing profile is searching for
#
assign costfactor
assign costfactor =
add max onewaypenalty accesspenalty
add ( max onewaypenalty accesspenalty )
switch and highway= not route=ferry 100000
if ( and highway= not route=ferry ) then 100000
#
# steps and ferries are special. Note this is handled
# before the cycleroute-switch, to be able
# to really exlude them be setting cost to infinity
#
switch highway=steps switch allow_steps 40 100000
switch route=ferry switch allow_ferries 5.67 100000
else if ( highway=steps ) then ( if allow_steps then 40 else 100000 )
else if ( route=ferry ) then ( if allow_ferries then 5.67 else 100000 )
#
# handle long-distance cycle-routes.
#
switch is_ldcr 1 # always treated as perfect (=1)
add switch stick_to_cycleroutes 0.5 0.05 # everything else somewhat up
else if ( is_ldcr ) then 1 # always treated as perfect (=1)
else
add ( if stick_to_cycleroutes then 0.5 else 0.05 ) # everything else somewhat up
#
# some other highway types
#
switch highway=pedestrian 3
switch highway=bridleway 5
switch highway=cycleway 1
switch or highway=residential highway=living_street switch isunpaved 1.5 1.1
switch highway=service switch isunpaved 1.6 1.3
if ( highway=pedestrian ) then 3
else if ( highway=bridleway ) then 5
else if ( highway=cycleway ) then 1
else if ( highway=residential|living_street ) then ( if isunpaved then 1.5 else 1.1 )
else if ( highway=service ) then ( if isunpaved then 1.6 else 1.3 )
#
# tracks and track-like ways are rated mainly be tracktype/grade
# But note that if no tracktype is given (mainly for road/path/footway)
# it can be o.k. if there's any other hint for quality
#
switch or highway=track or highway=road or highway=path highway=footway
switch tracktype=grade1 switch probablyGood 1.0 1.3
switch tracktype=grade2 switch probablyGood 1.1 2.0
switch tracktype=grade3 switch probablyGood 1.5 3.0
switch tracktype=grade4 switch probablyGood 2.0 5.0
switch tracktype=grade5 switch probablyGood 3.0 5.0
switch probablyGood 1.0 5.0
else if ( highway=track|road|path|footway ) then
(
if ( tracktype=grade1 ) then ( if probablyGood then 1.0 else 1.3 )
else if ( tracktype=grade2 ) then ( if probablyGood then 1.1 else 2.0 )
else if ( tracktype=grade3 ) then ( if probablyGood then 1.5 else 3.0 )
else if ( tracktype=grade4 ) then ( if probablyGood then 2.0 else 5.0 )
else if ( tracktype=grade5 ) then ( if probablyGood then 3.0 else 5.0 )
else ( if probablyGood then 1.0 else 5.0 )
)
#
# When avoiding unsafe ways, avoid highways without a bike hint
#
add switch and avoid_unsafe not isbike 2 0
else add ( if ( and avoid_unsafe not isbike ) then 2 else 0 )
#
# exclude motorways and proposed roads
#
switch or highway=motorway highway=motorway_link 100000
switch or highway=proposed highway=abandoned 100000
if ( highway=motorway|motorway_link ) then 100000
else if ( highway=proposed|abandoned ) then 100000
#
# actuals roads are o.k. if we have a bike hint
#
switch or highway=trunk highway=trunk_link switch isbike 1.5 10
switch or highway=primary highway=primary_link switch isbike 1.2 3
switch or highway=secondary highway=secondary_link switch isbike 1.1 1.6
switch or highway=tertiary highway=tertiary_link switch isbike 1.0 1.4
switch highway=unclassified switch isbike 1.0 1.3
else if ( highway=trunk|trunk_link ) then ( if isbike then 1.5 else 10 )
else if ( highway=primary|primary_link ) then ( if isbike then 1.2 else 3 )
else if ( highway=secondary|secondary_link ) then ( if isbike then 1.1 else 1.6 )
else if ( highway=tertiary|tertiary_link ) then ( if isbike then 1.0 else 1.4 )
else if ( highway=unclassified ) then ( if isbike then 1.0 else 1.3 )
#
# default for any other highway type not handled above
#
2.0
else 2.0
---context:node # following code refers to node tags
assign defaultaccess
switch access=
1 # add default barrier restrictions here!
switch or access=private access=no
0
1
assign defaultaccess =
if ( access= ) then true # add default barrier restrictions here!
else if ( access=private|no ) then false
else true
assign bikeaccess
or nodeaccessgranted=yes
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
switch or bicycle=private or bicycle=no bicycle=dismount
0
1
assign bikeaccess =
if nodeaccessgranted=yes then true
else if bicycle= then
(
if vehicle= then defaultaccess
else not vehicle=private|no
)
else not bicycle=private|no|dismount
assign footaccess
or bicycle=dismount
switch foot=
defaultaccess
switch or foot=private foot=no
0
1
assign footaccess =
if bicycle=dismount then true
else if foot= then defaultaccess
else not foot=private|no
assign initialcost
switch bikeaccess
0
switch footaccess
100
1000000
assign initialcost =
if bikeaccess then 0
else ( if footaccess then 100 else 1000000 )

View file

@ -66,7 +66,7 @@ is usually the one with the most space available.
However, on Android 4.4, write access to the external card
is restricted, and usually you will not get a proposal to use
the external card. Here you should accespt to go with the
the external card. Here you should accept to go with the
internal card - later on you can setup a "secondary" data
directory on the external card where you can move the datafiles
to.