diff --git a/brouter-core/src/main/java/btools/router/OsmPath.java b/brouter-core/src/main/java/btools/router/OsmPath.java index 39adac9..e63211b 100644 --- a/brouter-core/src/main/java/btools/router/OsmPath.java +++ b/brouter-core/src/main/java/btools/router/OsmPath.java @@ -83,6 +83,8 @@ final class OsmPath implements OsmLinkHolder private void addAddionalPenalty(OsmTrack refTrack, boolean recordTransferNodes, OsmPath origin, OsmLink link, RoutingContext rc ) { + if ( link.descriptionBitmap == null ) throw new IllegalArgumentException( "null description for class: " + link.getClass() ); + rc.nogomatch = false; // extract the 3 positions of the first section @@ -101,7 +103,7 @@ final class OsmPath implements OsmLinkHolder OsmTransferNode transferNode = link.decodeFirsttransfer(); OsmNode targetNode = link.targetNode; - long lastDescription = -1L; + byte[] lastDescription = null; String lastMessage = null; for(;;) { @@ -111,7 +113,7 @@ final class OsmPath implements OsmLinkHolder int lon2; int lat2; short ele2; - long description; + byte[] description; if ( transferNode == null ) { @@ -119,6 +121,7 @@ final class OsmPath implements OsmLinkHolder lat2 = targetNode.ilat; ele2 = targetNode.selev; description = link.descriptionBitmap; + if ( description == null ) throw new IllegalArgumentException( "null description for class: " + link.getClass() ); } else { @@ -126,6 +129,7 @@ final class OsmPath implements OsmLinkHolder lat2 = transferNode.ilat; ele2 = transferNode.selev; description = transferNode.descriptionBitmap; + if ( description == null ) throw new IllegalArgumentException( "null description for class: " + transferNode.getClass() + "/" + link.getClass() + " counterlinkwritten=" + link.counterLinkWritten ); } // if way description changed, store message @@ -173,7 +177,7 @@ final class OsmPath implements OsmLinkHolder linkdisttotal += dist; rc.messageHandler.setCurrentPos( lon2, lat2 ); - rc.expctxWay.evaluate( description, rc.messageHandler ); + rc.expctxWay.evaluate( link instanceof OsmLinkReverse, description, rc.messageHandler ); // *** penalty for way-change if ( origin.originElement != null ) @@ -309,10 +313,10 @@ final class OsmPath implements OsmLinkHolder } // finally add node-costs for target node - if ( targetNode.nodeDescription != 0L ) + if ( targetNode.nodeDescription != null ) { rc.messageHandler.setCurrentPos( targetNode.ilon, targetNode.ilat ); - rc.expctxNode.evaluate( targetNode.nodeDescription, rc.messageHandler ); + rc.expctxNode.evaluate( false, targetNode.nodeDescription, rc.messageHandler ); float initialcost = rc.expctxNode.getInitialcost(); if ( initialcost >= 1000000. ) { diff --git a/brouter-core/src/main/java/btools/router/RoutingEngine.java b/brouter-core/src/main/java/btools/router/RoutingEngine.java index e374ab8..cd6574e 100644 --- a/brouter-core/src/main/java/btools/router/RoutingEngine.java +++ b/brouter-core/src/main/java/btools/router/RoutingEngine.java @@ -73,7 +73,7 @@ public class RoutingEngine extends Thread BExpressionContext expctxGlobal = new BExpressionContext( "global" ); expctxGlobal.readMetaData( new File( profileDir, "lookups.dat" ) ); expctxGlobal.parseFile( profileFile, null ); - expctxGlobal.evaluate( 1L, rc.messageHandler ); + expctxGlobal.evaluate( new int[0] ); rc.readGlobalConfig(expctxGlobal); rc.expctxWay = new BExpressionContext( "way", 4096 ); diff --git a/brouter-expressions/pom.xml b/brouter-expressions/pom.xml index 6423fe8..0071e7a 100644 --- a/brouter-expressions/pom.xml +++ b/brouter-expressions/pom.xml @@ -17,5 +17,9 @@ brouter-util ${project.version} + + junit + junit + diff --git a/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java b/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java index fed9010..ac0c88c 100644 --- a/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java +++ b/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java @@ -40,15 +40,18 @@ public final class BExpressionContext private int[] lookupData = new int[0]; + private byte[] abBuf = new byte[256]; + private Map variableNumbers = new HashMap(); private float[] variableData; // hash-cache for function results - private long[] _arrayBitmap; + private byte[][] _arrayBitmap; private int currentHashBucket = -1; - private long currentBitmap = 0; + private byte[] currentByteArray = null; + private boolean currentInversion = false; public List expressionList; @@ -85,7 +88,7 @@ public final class BExpressionContext public BExpressionContext( String context, int hashSize ) { this.context = context; - _arrayBitmap = new long[hashSize]; + _arrayBitmap = new byte[hashSize][]; _arrayCostfactor = new float[hashSize]; _arrayTurncost = new float[hashSize]; @@ -94,62 +97,79 @@ public final class BExpressionContext /** - * encode lookup data to a 64-bit word + * encode lookup data to a byte array */ - public long encode( int[] ld ) + public byte[] encode() { - long w = 0; - for( int inum = 0; inum < lookupValues.size(); inum++ ) // loop over lookup names + return encode( lookupData ); + } + + public byte[] encode( int[] ld ) + { + // start with first bit hardwired ("reversedirection") + int idx = 0; + int bm = 2; // byte mask + abBuf[0] = (byte)(ld[0] == 0 ? 0 : 1); + + // all others are generic + for( int inum = 1; inum < lookupValues.size(); inum++ ) // loop over lookup names { int n = lookupValues.get(inum).length - 1; int d = ld[inum]; + int im = 1; // integer mask + if ( n == 2 ) { n = 1; d = d == 2 ? 1 : 0; } // 1-bit encoding for booleans - - while( n != 0 ) { n >>= 1; w <<= 1; } - w |= (long)d; + while( n != 0 ) + { + if ( bm == 0x100 ) { bm = 1; abBuf[++idx] = 0; } + if ( (d & im) != 0 ) abBuf[idx] |= bm; + n >>= 1; + bm <<= 1; + im <<= 1; + } } - return w; + idx++; + byte[] ab = new byte[idx]; + System.arraycopy( abBuf, 0, ab, 0, idx ); + return ab; } /** - * decode a 64-bit word into a lookup data array + * decode a byte-array into a lookup data array */ - public void decode( int[] ld, long w ) + public void decode( int[] ld, byte[] ab ) { - for( int inum = lookupValues.size()-1; inum >= 0; inum-- ) // loop over lookup names + // start with first bit hardwired ("reversedirection") + int idx = 1; + int bm = 2; // byte mask + int b = ab[0]; + ld[0] = (b & 1) == 0 ? 0 : 2; + + // all others are generic + for( int inum = 1; inum < lookupValues.size(); inum++ ) // loop over lookup names { int nv = lookupValues.get(inum).length; int n = nv == 3 ? 1 : nv-1; // 1-bit encoding for booleans - int m = 0; - long ww = w; - while( n != 0 ) { n >>= 1; ww >>= 1; m = m<<1 | 1; } - int d = (int)(w & m); + int d = 0; + int im = 1; // integer mask + while( n != 0 ) + { + if ( bm == 0x100 ) { bm = 1; b = ab[idx++]; } + if ( (b & bm) != 0 ) d |= im; + n >>= 1; + bm <<= 1; + im <<= 1; + } if ( nv == 3 && d == 1 ) d = 2; // 1-bit encoding for booleans ld[inum] = d; - w = ww; } } - /** - * much like decode, but just for counting bits - */ - private void countBits() - { - int bits = 0; - for( int inum = lookupValues.size()-1; inum >= 0; inum-- ) // loop over lookup names - { - int nv = lookupValues.get(inum).length; - int n = nv == 3 ? 1 : nv-1; // 1-bit encoding for booleans - while( n != 0 ) { n >>= 1; bits++; } - } -// System.out.println( "context=" + context + ",bits=" + bits + " keys=" + lookupValues.size() ); - if ( bits > 64 ) throw new IllegalArgumentException( "lookup table for context " + context + " exceeds 64 bits!" ); - } - public String getCsvDescription( long bitmap ) + public String getCsvDescription( byte[] ab ) { StringBuilder sb = new StringBuilder( 200 ); - decode( lookupData, bitmap ); + decode( lookupData, ab ); for( int inum = 0; inum < lookupValues.size(); inum++ ) // loop over lookup names { BExpressionLookupValue[] va = lookupValues.get(inum); @@ -168,10 +188,10 @@ public final class BExpressionContext return sb.toString(); } - public String getKeyValueDescription( long bitmap ) + public String getKeyValueDescription( byte[] ab ) { StringBuilder sb = new StringBuilder( 200 ); - decode( lookupData, bitmap ); + decode( lookupData, ab ); for( int inum = 0; inum < lookupValues.size(); inum++ ) // loop over lookup names { BExpressionLookupValue[] va = lookupValues.get(inum); @@ -192,6 +212,7 @@ public final class BExpressionContext int parsedLines = 0; boolean ourContext = false; + addLookupValue( "reversedirection", "yes", null ); for(;;) { String line = br.readLine(); @@ -215,6 +236,7 @@ public final class BExpressionContext String value = tk.nextToken(); int idx = name.indexOf( ';' ); if ( idx >= 0 ) name = name.substring( 0, idx ); + if ( "reversedirection".equals( name ) ) continue; // this is hardcoded BExpressionLookupValue newValue = addLookupValue( name, value, null ); // add aliases @@ -229,7 +251,6 @@ public final class BExpressionContext // post-process metadata: lookupDataFrozen = true; - countBits(); } catch( Exception e ) { @@ -237,7 +258,7 @@ public final class BExpressionContext } } - private void evaluate( int[] lookupData2 ) + public void evaluate( int[] lookupData2 ) { lookupData = lookupData2; for( BExpression exp: expressionList) @@ -248,27 +269,55 @@ public final class BExpressionContext - public void evaluate( long bitmap, BExpressionReceiver receiver ) + public void evaluate( boolean inverseDirection, byte[] ab, BExpressionReceiver receiver ) { _receiver = receiver; - - if ( currentBitmap != bitmap || currentHashBucket < 0 ) + + int abLen = ab.length; + boolean equalsCurrent = currentHashBucket >= 0 && abLen == currentByteArray.length; + if ( equalsCurrent ) { - // calc hash bucket from crc - int crc = Crc32.crc( bitmap ); - int hashSize = _arrayBitmap.length; - currentHashBucket = (crc & 0xfffffff) % hashSize; - currentBitmap = bitmap; + if ( (inverseDirection ? ab[0] ^ 1 : ab[0] ) == currentByteArray[0] ) + { + for( int i=1; i= nvalues ) throw new IllegalArgumentException( "value index out of range for name " + name + ": " + valueIndex ); + lookupData[inum] = valueIndex; + } + public void parseFile( File file, String readOnlyContext ) { try @@ -423,7 +491,7 @@ public final class BExpressionContext context = readOnlyContext; expressionList = _parseFile( file ); variableData = new float[variableNumbers.size()]; - evaluate( 1L, null ); + evaluate( lookupData ); // lookupData is dummy here - evaluate just to create the variables context = realContext; } linenr = 1; @@ -592,7 +660,7 @@ public final class BExpressionContext public void expressionWarning( String message ) { - _arrayBitmap[currentHashBucket] = 0L; // no caching if warnings + _arrayBitmap[currentHashBucket] = null; // no caching if warnings if ( _receiver != null ) _receiver.expressionWarning( context, message ); } } diff --git a/brouter-expressions/src/test/java/btools/expressions/EncodeDecodeTest.java b/brouter-expressions/src/test/java/btools/expressions/EncodeDecodeTest.java new file mode 100644 index 0000000..1cb2f27 --- /dev/null +++ b/brouter-expressions/src/test/java/btools/expressions/EncodeDecodeTest.java @@ -0,0 +1,46 @@ +package btools.expressions; + +import java.util.*; +import java.io.*; +import java.net.URL; + +import org.junit.Assert; +import org.junit.Test; + +public class EncodeDecodeTest +{ + @Test + public void encodeDecodeTest() + { + URL lookupurl = this.getClass().getResource( "/lookups.dat" ); + Assert.assertTrue( "lookup file lookup.dat not found", lookupurl != null ); + File lookupFile = new File(lookupurl.getFile()); + File workingDir = lookupFile.getParentFile(); + + // read lookup.dat + trekking.brf + BExpressionContext expctxWay = new BExpressionContext("way"); + expctxWay.readMetaData( lookupFile ); + expctxWay.parseFile( new File( workingDir, "trekking.brf" ), "global" ); + + String[] tags = { "highway=residential", "oneway=yes", "reversedirection=yes" }; + + // encode the tags into 64 bit description word + int[] lookupData = expctxWay.createNewLookupData(); + for( String arg: tags ) + { + int idx = arg.indexOf( '=' ); + if ( idx < 0 ) throw new IllegalArgumentException( "bad argument (should be =): " + arg ); + String key = arg.substring( 0, idx ); + String value = arg.substring( idx+1 ); + + expctxWay.addLookupValue( key, value, lookupData ); + } + byte[] description = expctxWay.encode(lookupData); + + // calculate the cost factor from that description + expctxWay.evaluate( false, description, null ); + + float costfactor = expctxWay.getCostfactor(); + Assert.assertTrue( "costfactor mismatch", Math.abs( costfactor - 5.1 ) > 0.00001 ); + } +} diff --git a/brouter-expressions/src/test/resources/lookups.dat b/brouter-expressions/src/test/resources/lookups.dat new file mode 100644 index 0000000..af197c9 --- /dev/null +++ b/brouter-expressions/src/test/resources/lookups.dat @@ -0,0 +1,317 @@ +---lookupversion:2 + +---context:way + +highway;0001731794 track +highway;0001457935 residential +highway;0000968516 service +highway;0000756237 footway +highway;0000521566 path +highway;0000261772 unclassified +highway;0000220315 secondary +highway;0000207585 tertiary +highway;0000103445 steps +highway;0000102114 primary +highway;0000094484 cycleway +highway;0000090388 living_street +highway;0000035041 motorway +highway;0000029965 pedestrian +highway;0000026875 motorway_link +highway;0000015054 trunk +highway;0000014604 primary_link +highway;0000012211 road +highway;0000011822 trunk_link +highway;0000005882 construction +highway;0000005425 bridleway +highway;0000005180 secondary_link +highway;0000003360 platform +highway;0000002616 proposed abandoned +highway;0000001374 tertiary_link +highway;0000000760 ferry +highway;0000000541 raceway +highway;0000000346 rest_area +highway;0000000300 bus_stop +highway;0000000184 services + +tracktype;0000356503 grade2 +tracktype;0000353482 grade3 +tracktype;0000281625 grade1 +tracktype;0000245193 grade4 +tracktype;0000179135 grade5 + +surface;0000363915 asphalt +surface;0000303589 paved +surface;0000196783 gravel +surface;0000137371 ground +surface;0000128215 grass +surface;0000092748 unpaved +surface;0000086579 paving_stones +surface;0000066111 cobblestone +surface;0000042061 dirt +surface;0000026551 concrete +surface;0000025631 compacted +surface;0000019861 sand +surface;0000009400 pebblestone +surface;0000003197 fine_gravel + +maxspeed;0000402224 30 +maxspeed;0000224685 50 +maxspeed;0000045177 100 +maxspeed;0000037529 70 +maxspeed;0000014237 none +maxspeed;0000014022 60 +maxspeed;0000011530 80 +maxspeed;0000009951 10 +maxspeed;0000008056 20 +maxspeed;0000005772 120 +maxspeed;0000003165 40 +maxspeed;0000002987 7 +maxspeed;0000002826 signals +maxspeed;0000001933 130 + +service;0000221481 parking_aisle +service;0000157110 driveway + +lit;0000132495 yes + +lanes;0000098207 2 +lanes;0000042192 1 +lanes;0000018533 3 +lanes;0000004577 4 +lanes;0000000448 5 +lanes;0000000318 1.5 + +access;0000044859 yes permissive +access;0000008452 designated official +access;0000028727 destination customers +access;0000076985 agricultural forestry +access;0000116270 private +access;0000028044 no + +foot;0000339384 yes allowed Yes +foot;0000125339 designated official +foot;0000018945 no +foot;0000001562 private +foot;0000000279 destination +foot;0000008172 permissive + +bicycle;0000302789 yes allowed permissive +bicycle;0000108056 designated official +bicycle;0000000265 destination +bicycle;0000003593 dismount +bicycle;0000001426 private +bicycle;0000070179 no + +motorcar;0000010111 yes permissive +motorcar;0000001537 designated official +motorcar;0000007102 destination +motorcar;0000016706 agricultural forestry agriculture +motorcar;0000002178 private +motorcar;0000077771 no + +motor_vehicle;0000013813 yes permissive +motor_vehicle;0000002098 designated official +motor_vehicle;0000009792 destination +motor_vehicle;0000019301 agricultural forestry +motor_vehicle;0000006563 private +motor_vehicle;0000025491 no + +motorcycle;0000005750 yes permissive +motorcycle;0000001158 designated official +motorcycle;0000005805 destination +motorcycle;0000012401 agricultural forestry +motorcycle;0000001180 private +motorcycle;0000053955 no + +vehicle;0000000505 yes permissive +vehicle;0000000027 designated +vehicle;0000007582 destination +vehicle;0000004357 agricultural forestry +vehicle;0000001155 private +vehicle;0000006487 no + +cycleway;0000033575 track +cycleway;0000012829 no +cycleway;0000011604 lane +cycleway;0000008938 opposite +cycleway;0000001503 none +cycleway;0000001146 right +cycleway;0000001031 opposite_track +cycleway;0000001029 yes +cycleway;0000000856 opposite_lane +cycleway;0000000675 both +cycleway;0000000665 left +cycleway;0000000521 shared +cycleway;0000000383 street +cycleway;0000000176 segregated + +mtb:scale;0000043968 0 +mtb:scale;0000019705 1 +mtb:scale;0000006436 2 +mtb:scale;0000002702 3 +mtb:scale;0000001083 4 +mtb:scale;0000000329 5 + +sac_scale;0000049626 hiking +sac_scale;0000007933 mountain_hiking +sac_scale;0000001160 demanding_mountain_hiking +sac_scale;0000000523 yes +sac_scale;0000000364 alpine_hiking +sac_scale;0000000117 demanding_alpine_hiking + +noexit;0000058492 yes + +motorroad;0000019250 yes + +oneway;0000330245 yes +oneway;0000075148 no +oneway;0000003679 -1 +oneway;0000000001 true +oneway;0000000001 1 + +junction;0000015929 roundabout + +bridge;0000182649 yes viaduct true suspension + +tunnel;0000031626 yes + +lcn;0000018999 yes + +longdistancecycleway;0000000001 yes + +reversedirection;0000000001 yes + +---context:node + +highway;0000100947 turning_circle +highway;0000067645 traffic_signals +highway;0000047209 crossing +highway;0000037164 bus_stop +highway;0000006577 motorway_junction +highway;0000003811 stop +highway;0000002331 mini_roundabout +highway;0000001789 milestone +highway;0000001692 passing_place +highway;0000001289 give_way +highway;0000001092 emergency_access_point +highway;0000000683 speed_camera +highway;0000000672 steps +highway;0000000658 incline_steep +highway;0000000620 elevator +highway;0000000506 street_lamp +highway;0000000490 ford +highway;0000000458 incline +highway;0000000135 rest_area +highway;0000000105 path +highway;0000000098 emergency_bay +highway;0000000096 road +highway;0000000087 platform +highway;0000000074 services +highway;0000000058 track +highway;0000000055 service +highway;0000000054 footway +highway;0000000053 traffic_calming +highway;0000000046 toll_bridge +highway;0000000037 city_entry + +barrier;0000076979 gate +barrier;0000069308 bollard +barrier;0000028131 lift_gate +barrier;0000017332 cycle_barrier +barrier;0000005693 entrance +barrier;0000002885 block +barrier;0000001065 kissing_gate +barrier;0000000828 cattle_grid +barrier;0000000602 stile +barrier;0000000561 turnstile +barrier;0000000512 no +barrier;0000000463 fence +barrier;0000000417 bump_gate +barrier;0000000324 sally_port +barrier;0000000283 yes +barrier;0000000283 hampshire_gate +barrier;0000000236 swing_gate +barrier;0000000203 chain +barrier;0000000181 toll_booth +barrier;0000000180 door +barrier;0000000104 chicane +barrier;0000000096 tree +barrier;0000000087 border_control +barrier;0000000077 log +barrier;0000000076 traffic_crossing_pole +barrier;0000000063 wall +barrier;0000000060 fallen_tree +barrier;0000000052 stone +barrier;0000000048 ditch +barrier;0000000031 spikes + +access;0000001309 yes permissive +access;0000000118 designated official +access;0000000405 destination customers +access;0000000276 agricultural forestry +access;0000008574 private +access;0000002145 no + +foot;0000080681 yes permissive +foot;0000000326 designated official +foot;0000000023 destination +foot;0000000156 private +foot;0000009170 no + +bicycle;0000076717 yes permissive +bicycle;0000000406 designated official +bicycle;0000000018 destination +bicycle;0000000081 dismount +bicycle;0000000051 private +bicycle;0000016121 no + +motorcar;0000005785 yes permissive +motorcar;0000000026 designated official +motorcar;0000000080 destination +motorcar;0000000112 agricultural forestry +motorcar;0000000171 private +motorcar;0000001817 no + +motor_vehicle;0000000066 yes permissive +motor_vehicle;0000000000 designated official +motor_vehicle;0000000030 destination +motor_vehicle;0000000073 agricultural forestry +motor_vehicle;0000000136 private +motor_vehicle;0000000469 no + +motorcycle;0000004515 yes permissive +motorcycle;0000000007 designated official +motorcycle;0000000054 destination +motorcycle;0000000027 agricultural forestry +motorcycle;0000000063 private +motorcycle;0000001637 no + +vehicle;0000000058 yes permissive +vehicle;0000000000 designated +vehicle;0000000081 destination +vehicle;0000000038 agricultural forestry +vehicle;0000000041 private +vehicle;0000000271 no + +crossing;0000032485 traffic_signals +crossing;0000014300 uncontrolled +crossing;0000005086 island +crossing;0000001565 unmarked +crossing;0000001066 no +crossing;0000000333 zebra + +railway;0000034039 level_crossing +railway;0000010175 crossing + +noexit;0000043010 yes + +entrance;0000015094 yes +entrance;0000007079 main +entrance;0000000554 service +entrance;0000000169 emergency +entrance;0000000063 exit +entrance;0000000008 private + +lcn;0000018999 yes + +longdistancecycleway;0000000001 yes diff --git a/brouter-expressions/src/test/resources/trekking.brf b/brouter-expressions/src/test/resources/trekking.brf new file mode 100644 index 0000000..28a59ec --- /dev/null +++ b/brouter-expressions/src/test/resources/trekking.brf @@ -0,0 +1,225 @@ +# *** The trekking profile is for slow travel +# *** and avoiding car traffic, but still with +# *** a focus on approaching your destination +# *** efficiently. + +---context:global # following code refers to global config + +# 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 validForBikes 1 + +# the elevation parameters + +assign downhillcost switch consider_elevation 60 0 +assign downhillcutoff 1.5 +assign uphillcost 0 +assign uphillcutoff 1.5 + +---context:way # following code refers to way-tags + +# +# pre-calculate some logical expressions +# +assign is_ldcr and longdistancecycleway=yes not ignore_cycleroutes +assign isbike or bicycle=yes or 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 + + +# +# this is the cost (in Meter) for a 90-degree turn +# The actual cost is calculated as turncost*cos(angle) +# (Suppressing turncost while following longdistance-cycleways +# makes them a little bit more magnetic) +# +assign turncost switch is_ldcr 0 90 + +# +# calculate the initial cost +# this is added to the total cost each time the costfactor +# changed +# +assign initialcost switch highway=ferry 10000 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 + +# +# calculate logical bike access +# +assign bikeaccess + or longdistancecycleway=yes + switch bicycle= + switch vehicle= + defaultaccess + switch or vehicle=private vehicle=no + 0 + 1 + not or bicycle=private or bicycle=no bicycle=dismount + +# +# calculate logical foot access +# +assign footaccess + or bikeaccess + or bicycle=dismount + switch foot= + defaultaccess + not or foot=private foot=no + +# +# if not bike-, but foot-acess, just a moderate penalty, +# otherwise access is forbidden +# +assign accesspenalty + switch bikeaccess + 0 + switch footaccess + 4 + 100000 + +# +# handle one-ways. On primary roads, wrong-oneways should +# be close to forbidden, while on other ways we just add +# 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 onewaypenalty + switch switch reversedirection=yes oneway oneway=-1 + switch or cycleway=opposite or cycleway=opposite_lane cycleway=opposite_track 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 +# by which the distance of a way-segment is multiplied +# to calculate the cost of that segment. The costfactor +# 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 + + add max onewaypenalty accesspenalty + + # + # steps and ferries are special. Note this is handled + # before the longdistancecycleway-switch, to be able + # to really exlude them be setting cost to infinity + # + switch highway=steps switch allow_steps 40 100000 + switch highway=ferry switch allow_ferries 5.67 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 + + # + # 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 + + # + # 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 + + # + # When avoiding unsafe ways, avoid highways without a bike hint + # + add switch and avoid_unsafe not isbike 2 0 + + # + # exclude motorways and proposed roads + # + switch or highway=motorway highway=motorway_link 100000 + switch highway=proposed 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 + + # + # default for any other highway type not handled above + # + 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 bikeaccess + or or longdistancecycleway=yes lcn=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 footaccess + or bicycle=dismount + switch foot= + defaultaccess + switch or foot=private foot=no + 0 + 1 + +assign initialcost + switch bikeaccess + 0 + switch footaccess + 100 + 1000000 diff --git a/brouter-map-creator/src/main/java/btools/mapcreator/NodeData.java b/brouter-map-creator/src/main/java/btools/mapcreator/NodeData.java index aef65f9..b8937b6 100644 --- a/brouter-map-creator/src/main/java/btools/mapcreator/NodeData.java +++ b/brouter-map-creator/src/main/java/btools/mapcreator/NodeData.java @@ -13,7 +13,7 @@ public class NodeData extends MapCreatorBase public long nid; public int ilon; public int ilat; - public long description; + public byte[] description; public short selev = Short.MIN_VALUE; public NodeData( long id, double lon, double lat ) @@ -29,18 +29,18 @@ public class NodeData extends MapCreatorBase ilon = dis.readInt(); ilat = dis.readInt(); int mode = dis.readByte(); - if ( ( mode & 1 ) != 0 ) description = dis.readLong(); + if ( ( mode & 1 ) != 0 ) { int dlen = dis.readByte(); description = new byte[dlen]; dis.readFully( description ); } if ( ( mode & 2 ) != 0 ) selev = dis.readShort(); - } + } public void writeTo( DataOutputStream dos ) throws Exception { writeId( dos, nid ); dos.writeInt( ilon ); dos.writeInt( ilat ); - int mode = ( description == 0L ? 0 : 1 ) | ( selev == Short.MIN_VALUE ? 0 : 2 ); + int mode = ( description == null ? 0 : 1 ) | ( selev == Short.MIN_VALUE ? 0 : 2 ); dos.writeByte( (byte)mode ); - if ( ( mode & 1 ) != 0 ) dos.writeLong( description ); + if ( ( mode & 1 ) != 0 ) { dos.writeByte( description.length ); dos.write( description ); } if ( ( mode & 2 ) != 0 ) dos.writeShort( selev ); } } diff --git a/brouter-map-creator/src/main/java/btools/mapcreator/OsmLinkP.java b/brouter-map-creator/src/main/java/btools/mapcreator/OsmLinkP.java index 141f43c..192fa96 100644 --- a/brouter-map-creator/src/main/java/btools/mapcreator/OsmLinkP.java +++ b/brouter-map-creator/src/main/java/btools/mapcreator/OsmLinkP.java @@ -6,13 +6,13 @@ package btools.mapcreator; -public final class OsmLinkP +public class OsmLinkP { /** * The description bitmap is mainly the way description * used to calculate the costfactor */ - public long descriptionBitmap; + public byte[] descriptionBitmap; /** * The target is either the next link or the target node @@ -22,8 +22,8 @@ public final class OsmLinkP public OsmLinkP next; - public boolean counterLinkWritten( ) + public final boolean counterLinkWritten( ) { - return descriptionBitmap == 0L; + return descriptionBitmap == null; } } diff --git a/brouter-map-creator/src/main/java/btools/mapcreator/OsmLinkPReverse.java b/brouter-map-creator/src/main/java/btools/mapcreator/OsmLinkPReverse.java new file mode 100644 index 0000000..3a368da --- /dev/null +++ b/brouter-map-creator/src/main/java/btools/mapcreator/OsmLinkPReverse.java @@ -0,0 +1,11 @@ +/** + * Dummy child of OsmLinkP just to encode the reverse bit + * + * @author ab + */ +package btools.mapcreator; + + +public class OsmLinkPReverse extends OsmLinkP +{ +} diff --git a/brouter-map-creator/src/main/java/btools/mapcreator/OsmNodeP.java b/brouter-map-creator/src/main/java/btools/mapcreator/OsmNodeP.java index 7529e81..0b4492d 100644 --- a/brouter-map-creator/src/main/java/btools/mapcreator/OsmNodeP.java +++ b/brouter-map-creator/src/main/java/btools/mapcreator/OsmNodeP.java @@ -75,9 +75,9 @@ public class OsmNodeP implements Comparable firstlink = link; } - public long getNodeDecsription() + public byte[] getNodeDecsription() { - return 0L; + return null; } public void writeNodeData( DataOutputStream os ) throws IOException @@ -92,7 +92,7 @@ public class OsmNodeP implements Comparable os2.writeShort( getSElev() ); // hack: write node-desc as link tag (copy cycleway-bits) - long nodeDescription = getNodeDecsription(); + byte[] nodeDescription = getNodeDecsription(); for( OsmLinkP link0 = firstlink; link0 != null; link0 = link0.next ) { @@ -122,13 +122,15 @@ public class OsmNodeP implements Comparable link = link0; } origin = this; - long lastDescription = 0; + byte[] lastDescription = null; while( link != null ) { + if ( link.descriptionBitmap == null && skipDetailBit == 0 ) throw new IllegalArgumentException( "missing way description..."); + OsmNodeP target = link.targetNode; int tranferbit = target.isTransferNode() ? TRANSFERNODE_BITMASK : 0; int writedescbit = link.descriptionBitmap != lastDescription ? WRITEDESC_BITMASK : 0; - int nodedescbit = nodeDescription != 0L ? NODEDESC_BITMASK : 0; + int nodedescbit = nodeDescription != null ? NODEDESC_BITMASK : 0; if ( skipDetailBit != 0 ) { @@ -153,12 +155,17 @@ public class OsmNodeP implements Comparable } if ( writedescbit != 0 ) { - os2.writeLong( link.descriptionBitmap ); + // write the way description, code direction into the first bit + byte[] dbytes = link.descriptionBitmap; + int len = dbytes.length; + os2.writeByte( len ); + os2.writeByte( link instanceof OsmLinkPReverse ? dbytes[0] | 1 : dbytes[0] ); + if ( len > 1 ) os2.write( dbytes, 1, len-1 ); } if ( nodedescbit != 0 ) { - os2.writeLong( nodeDescription ); - nodeDescription = 0L; + os2.writeByte( nodeDescription.length ); os2.write( nodeDescription ); + nodeDescription = null; } lastDescription = link.descriptionBitmap; @@ -220,7 +227,7 @@ public class OsmNodeP implements Comparable { for( OsmLinkP link = firstlink; link != null; link = link.next ) { - if ( link.targetNode == t) link.descriptionBitmap = 0L; + if ( link.targetNode == t) link.descriptionBitmap = null; } } diff --git a/brouter-map-creator/src/main/java/btools/mapcreator/OsmNodePT.java b/brouter-map-creator/src/main/java/btools/mapcreator/OsmNodePT.java index 94e048c..989c4d4 100644 --- a/brouter-map-creator/src/main/java/btools/mapcreator/OsmNodePT.java +++ b/brouter-map-creator/src/main/java/btools/mapcreator/OsmNodePT.java @@ -8,7 +8,7 @@ package btools.mapcreator; public class OsmNodePT extends OsmNodeP { - public long descriptionBits; + public byte[] descriptionBits; public byte wayOrBits = 0; // used to propagate bike networks to nodes @@ -16,15 +16,16 @@ public class OsmNodePT extends OsmNodeP { } - public OsmNodePT( long descriptionBits ) + public OsmNodePT( byte[] descriptionBits ) { this.descriptionBits = descriptionBits; } @Override - public long getNodeDecsription() + public final byte[] getNodeDecsription() { - return descriptionBits | (long)( (wayOrBits & 6) >> 1 ); + return descriptionBits; + // return descriptionBits | (long)( (wayOrBits & 6) >> 1 ); TODO !!!!!!!!!!1 } @Override diff --git a/brouter-map-creator/src/main/java/btools/mapcreator/WayCutter.java b/brouter-map-creator/src/main/java/btools/mapcreator/WayCutter.java index 41d4a08..e1d5c0b 100644 --- a/brouter-map-creator/src/main/java/btools/mapcreator/WayCutter.java +++ b/brouter-map-creator/src/main/java/btools/mapcreator/WayCutter.java @@ -100,11 +100,11 @@ public class WayCutter extends MapCreatorBase { boolean ok = true; // check access and log a warning for conflicts - expctxReport.evaluate( data.description, null ); + expctxReport.evaluate( false, data.description, null ); boolean warn = expctxReport.getCostfactor() >= 10000.; if ( warn ) { - expctxCheck.evaluate( data.description, null ); + expctxCheck.evaluate( false, data.description, null ); ok = expctxCheck.getCostfactor() < 10000.; System.out.println( "** relation access conflict for wid = " + data.wid + " tags:" + expctxReport.getKeyValueDescription( data.description ) + " (ok=" + ok + ")" ); @@ -112,7 +112,8 @@ public class WayCutter extends MapCreatorBase if ( ok ) { - data.description |= 2; + expctxReport.addLookupValue( "longdistancecycleway", 2 ); + data.description = expctxReport.encode(); } } diff --git a/brouter-map-creator/src/main/java/btools/mapcreator/WayData.java b/brouter-map-creator/src/main/java/btools/mapcreator/WayData.java index 23109d8..d6523cb 100644 --- a/brouter-map-creator/src/main/java/btools/mapcreator/WayData.java +++ b/brouter-map-creator/src/main/java/btools/mapcreator/WayData.java @@ -13,7 +13,7 @@ import btools.util.LongList; public class WayData extends MapCreatorBase { public long wid; - public long description; + public byte[] description; public LongList nodes; public WayData( long id ) @@ -32,7 +32,7 @@ public class WayData extends MapCreatorBase { nodes = new LongList( 16 ); wid = readId( di) ; - description = di.readLong(); + int dlen = di.readByte(); description = new byte[dlen]; di.readFully( description ); for (;;) { long nid = readId( di ); @@ -44,7 +44,7 @@ public class WayData extends MapCreatorBase public void writeTo( DataOutputStream dos ) throws Exception { writeId( dos, wid ); - dos.writeLong( description ); + dos.writeByte( description.length ); dos.write( description ); int size = nodes.size(); for( int i=0; i < size; i++ ) { diff --git a/brouter-map-creator/src/main/java/btools/mapcreator/WayLinker.java b/brouter-map-creator/src/main/java/btools/mapcreator/WayLinker.java index 2c52cb1..5dce724 100644 --- a/brouter-map-creator/src/main/java/btools/mapcreator/WayLinker.java +++ b/brouter-map-creator/src/main/java/btools/mapcreator/WayLinker.java @@ -104,7 +104,7 @@ public class WayLinker extends MapCreatorBase @Override public void nextNode( NodeData data ) throws Exception { - OsmNodeP n = data.description == 0L ? new OsmNodeP() : new OsmNodePT(data.description); + OsmNodeP n = data.description == null ? new OsmNodeP() : new OsmNodePT(data.description); n.ilon = data.ilon; n.ilat = data.ilat; n.selev = data.selev; @@ -132,18 +132,17 @@ public class WayLinker extends MapCreatorBase @Override public void nextWay( WayData way ) throws Exception { - long description = way.description; - long reverseDescription = description | 1L; // (add reverse bit) + byte[] description = way.description; // filter according to profile - expctxWay.evaluate( description, null ); + expctxWay.evaluate( false, description, null ); boolean ok = expctxWay.getCostfactor() < 10000.; - expctxWay.evaluate( reverseDescription, null ); + expctxWay.evaluate( true, description, null ); ok |= expctxWay.getCostfactor() < 10000.; if ( !ok ) return; - byte lowbyte = (byte)description; +// byte lowbyte = (byte)description; OsmNodeP n1 = null; OsmNodeP n2 = null; @@ -159,16 +158,16 @@ public class WayLinker extends MapCreatorBase l1.descriptionBitmap = description; n1.addLink( l1 ); - OsmLinkP l2 = new OsmLinkP(); + OsmLinkP l2 = new OsmLinkPReverse(); l2.targetNode = n1; - l2.descriptionBitmap = reverseDescription; + l2.descriptionBitmap = description; n2.addLink( l2 ); } if ( n2 != null ) { - n2.wayAndBits &= lowbyte; - if ( n2 instanceof OsmNodePT ) ((OsmNodePT)n2).wayOrBits |= lowbyte; +// n2.wayAndBits &= lowbyte; +// if ( n2 instanceof OsmNodePT ) ((OsmNodePT)n2).wayOrBits |= lowbyte; } } } diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/ByteDataReader.java b/brouter-mapaccess/src/main/java/btools/mapaccess/ByteDataReader.java index b1776ff..7ad5e25 100644 --- a/brouter-mapaccess/src/main/java/btools/mapaccess/ByteDataReader.java +++ b/brouter-mapaccess/src/main/java/btools/mapaccess/ByteDataReader.java @@ -56,4 +56,20 @@ final class ByteDataReader int i0 = ab[aboffset++] & 0xff; return (short)( (i1 << 8) | i0); } + + public void readFully( byte[] ta ) + { + System.arraycopy( ab, aboffset, ta, 0, ta.length ); + aboffset += ta.length; + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder( "[" ); + for( int i=0; i> 8) & 0xff ); ab[aboffset++] = (byte)( (v ) & 0xff ); } -} + + public void write( byte[] sa ) + { + System.arraycopy( sa, 0, ab, aboffset, sa.length ); + aboffset += sa.length; + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder( "[" ); + for( int i=0; i> 16 ) != currentILonHigh ) { @@ -61,7 +63,7 @@ public final class OsmTransferNode byte[] ab = new byte[size]; ByteDataWriter os = new ByteDataWriter( ab ); - currentDesc = 0; + currentDesc = null; currentILonHigh = 0; currentILatHigh = 0; n = tn; @@ -84,7 +86,7 @@ public final class OsmTransferNode currentILatHigh = n.ilat >> 16; } os.writeByte( mode); - if ( (mode & BIT_DESC) != 0 ) os.writeLong( currentDesc ); + if ( (mode & BIT_DESC) != 0 ) { os.writeByte( currentDesc.length ); os.write( currentDesc ); } if ( (mode & BIT_ILONHIGH) != 0 ) os.writeShort( currentILonHigh ); if ( (mode & BIT_ILATHIGH) != 0 ) os.writeShort( currentILatHigh ); os.writeShort( n.ilon ); @@ -103,19 +105,21 @@ public final class OsmTransferNode OsmTransferNode firstNode = null; OsmTransferNode lastNode = null; - long currentDesc = 0; + byte[] currentDesc = null; int currentILonHigh = 0; int currentILatHigh = 0; + for(;;) { byte mode = is.readByte(); if ( (mode & BIT_STOP ) != 0 ) break; OsmTransferNode n = new OsmTransferNode(); - if ( (mode & BIT_DESC) != 0 ) currentDesc = is.readLong(); + if ( (mode & BIT_DESC) != 0 ) { int dlen = is.readByte(); currentDesc = new byte[dlen]; is.readFully( currentDesc ); } if ( (mode & BIT_ILONHIGH) != 0 ) currentILonHigh = is.readShort(); if ( (mode & BIT_ILATHIGH) != 0 ) currentILatHigh = is.readShort(); n.descriptionBitmap = currentDesc; + if ( n.descriptionBitmap == null ) throw new IllegalArgumentException( "transfernode-decode: description is null" ); int ilon = is.readShort() & 0xffff; ilon |= currentILonHigh << 16; int ilat = is.readShort() & 0xffff; ilat |= currentILatHigh << 16; n.ilon = ilon; 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 b7014e1..df67b13 100644 --- a/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java +++ b/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java @@ -671,7 +671,7 @@ private long startTime = 0L; BExpressionContext expctxGlobal = new BExpressionContext( "global" ); expctxGlobal.readMetaData( new File( profileDir, "lookups.dat" ) ); expctxGlobal.parseFile( new File( profilePath ), null ); - expctxGlobal.evaluate( 1L, null ); + expctxGlobal.evaluate( new int[0] ); boolean isFoot = 0.f != expctxGlobal.getVariableValue( "validForFoot" ); boolean isBike = 0.f != expctxGlobal.getVariableValue( "validForBikes" ); boolean isCar = 0.f != expctxGlobal.getVariableValue( "validForCars" );