diff --git a/brouter-core/src/main/java/btools/router/OsmTrack.java b/brouter-core/src/main/java/btools/router/OsmTrack.java index df3ceef..dd12910 100644 --- a/brouter-core/src/main/java/btools/router/OsmTrack.java +++ b/brouter-core/src/main/java/btools/router/OsmTrack.java @@ -286,7 +286,6 @@ public final class OsmTrack public int ascend; public int plainAscend; public int cost; - public long arrivaltime; /** * writes the track in gpx-format to a file diff --git a/brouter-core/src/main/java/btools/router/RoutingContext.java b/brouter-core/src/main/java/btools/router/RoutingContext.java index 4d8f2bf..940fd3f 100644 --- a/brouter-core/src/main/java/btools/router/RoutingContext.java +++ b/brouter-core/src/main/java/btools/router/RoutingContext.java @@ -19,13 +19,11 @@ public final class RoutingContext implements DistanceChecker { public void setAlternativeIdx( int idx ) { - if ( idx < 0 ) idx = 0; - if ( idx > 3 ) idx = 3; alternativeIdx = idx; } - public int getAlternativeIdx() + public int getAlternativeIdx(int min, int max) { - return alternativeIdx; + return alternativeIdx < min ? min : (alternativeIdx > max ? max : alternativeIdx); } public int alternativeIdx = 0; public String localFunction; @@ -66,6 +64,7 @@ public final class RoutingContext implements DistanceChecker public double waittimeadjustment; public double inittimeadjustment; public double starttimeoffset; + public boolean transitonly; public void readGlobalConfig( BExpressionContext expctxGlobal ) { @@ -92,6 +91,7 @@ public final class RoutingContext implements DistanceChecker waittimeadjustment = expctxGlobal.getVariableValue( "waittimeadjustment", 0.9f ); inittimeadjustment = expctxGlobal.getVariableValue( "inittimeadjustment", 0.2f ); starttimeoffset = expctxGlobal.getVariableValue( "starttimeoffset", 0.f ); + transitonly = expctxGlobal.getVariableValue( "transitonly", 0.f ) != 0.f; farTrafficWeight = expctxGlobal.getVariableValue( "farTrafficWeight", 2.f ); nearTrafficWeight = expctxGlobal.getVariableValue( "nearTrafficWeight", 2.f ); diff --git a/brouter-core/src/main/java/btools/router/RoutingEngine.java b/brouter-core/src/main/java/btools/router/RoutingEngine.java index e8d21ce..f71a12f 100644 --- a/brouter-core/src/main/java/btools/router/RoutingEngine.java +++ b/brouter-core/src/main/java/btools/router/RoutingEngine.java @@ -164,7 +164,7 @@ public class RoutingEngine extends Thread } else { - if ( i == routingContext.getAlternativeIdx() ) + if ( i == routingContext.getAlternativeIdx(0,3) ) { if ( "CSV".equals( System.getProperty( "reportFormat" ) ) ) { diff --git a/brouter-expressions/src/main/java/btools/expressions/ProfileComparator.java b/brouter-expressions/src/main/java/btools/expressions/ProfileComparator.java index 639f02d..3c5ee7c 100644 --- a/brouter-expressions/src/main/java/btools/expressions/ProfileComparator.java +++ b/brouter-expressions/src/main/java/btools/expressions/ProfileComparator.java @@ -1,18 +1,6 @@ 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 diff --git a/brouter-mem-router/src/main/java/btools/memrouter/GraphLoader.java b/brouter-mem-router/src/main/java/btools/memrouter/GraphLoader.java index 8c015b6..13b0c10 100644 --- a/brouter-mem-router/src/main/java/btools/memrouter/GraphLoader.java +++ b/brouter-mem-router/src/main/java/btools/memrouter/GraphLoader.java @@ -3,8 +3,8 @@ package btools.memrouter; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.Map; -import btools.expressions.BExpressionContext; import btools.expressions.BExpressionContextWay; import btools.expressions.BExpressionMetaData; import btools.mapaccess.OsmPos; @@ -27,6 +27,8 @@ import btools.util.LazyArrayOfLists; public class GraphLoader extends MapCreatorBase { private CompactLongMap nodesMap; + + private Map stationMap; private BExpressionContextWay expctxWay; @@ -102,7 +104,7 @@ public class GraphLoader extends MapCreatorBase System.out.println( "nodesLoaded=" + nodesLoaded + " linksLoaded=" + linksLoaded ); // now load the train-schedules - ScheduleParser.parseTrainTable( fahrplanFiles, this, expctxWay ); + stationMap = ScheduleParser.parseTrainTable( fahrplanFiles, this, expctxWay ); System.gc(); long mem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); @@ -110,12 +112,15 @@ public class GraphLoader extends MapCreatorBase } - public OsmNodeP matchNodeForPosition( OsmPos pos, BExpressionContextWay wayCtx ) + public OsmNodeP matchNodeForPosition( OsmPos pos, BExpressionContextWay wayCtx, boolean transitonly ) { - // todo: this creates empty lists lazy - - int ilon = pos.getILon(); - int ilat = pos.getILat(); + if ( transitonly ) + { + return matchStationForPosition( pos ); + } + + int ilon = pos.getILon(); + int ilat = pos.getILat(); List nodes = new ArrayList(); nodes.addAll( subListForPos( ilon-6125, ilat-6125 ) ); @@ -128,6 +133,22 @@ public class GraphLoader extends MapCreatorBase for( OsmNodeP node : nodes ) { + if ( transitonly ) + { + StationNode sn = getStationNode( node ); + if ( sn != null ) + { + int dist = pos.calcDistance( sn ); + if ( dist < mindist ) + { + mindist = dist; + bestmatch = sn; + } + } + continue; + } + + int dist = pos.calcDistance( node ); if ( dist < mindist ) { @@ -141,6 +162,36 @@ public class GraphLoader extends MapCreatorBase return bestmatch; } + private StationNode getStationNode( OsmNodeP node ) + { + for( OsmLinkP link = node.getFirstLink(); link != null; link = link.getNext( node ) ) + { + OsmNodeP tn = link.getTarget( node ); + if ( tn instanceof StationNode ) + { + return (StationNode)tn; + } + } + return null; + } + + public OsmNodeP matchStationForPosition( OsmPos pos ) + { + int mindist = Integer.MAX_VALUE; + OsmNodeP bestmatch = null; + + for( OsmNodeP node : stationMap.values() ) + { + int dist = pos.calcDistance( node ); + if ( dist < mindist ) + { + mindist = dist; + bestmatch = node; + } + } + return bestmatch; + } + private boolean hasRoutableLinks( OsmNodeP node, BExpressionContextWay wayCtx ) { for( OsmLinkP link = node.getFirstLink(); link != null; link = link.getNext( node ) ) @@ -183,10 +234,11 @@ public class GraphLoader extends MapCreatorBase } @Override - public void wayFileStart( File wayfile ) throws Exception + public boolean wayFileStart( File wayfile ) throws Exception { currentTile = tileForFilename( wayfile.getName() ); System.out.println( "ways currentTile=" + currentTile ); + return true; } @Override diff --git a/brouter-mem-router/src/main/java/btools/memrouter/Iternity.java b/brouter-mem-router/src/main/java/btools/memrouter/Iternity.java new file mode 100644 index 0000000..8d6b696 --- /dev/null +++ b/brouter-mem-router/src/main/java/btools/memrouter/Iternity.java @@ -0,0 +1,77 @@ +/** + * Set off departure offsets (immutable) + * + * @author ab + */ +package btools.memrouter; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import btools.router.OsmTrack; + +public class Iternity implements Comparable +{ + OsmTrack track; + OffsetSet offsets; + List details = new ArrayList(); + List lines = new ArrayList(); + long departtime; + long arrivaltime; + + @Override + public int compareTo( Iternity it ) + { + return arrivaltime == it.arrivaltime ? 0 : ( arrivaltime < it.arrivaltime ? -1 : 1 ); + } + + void appendSummary( List sum ) + { + SimpleDateFormat df = new SimpleDateFormat( "dd.MM HH:mm", Locale.GERMAN ); + sum.add( "depart: " + df.format( new Date( departtime ) )+ " arrive: " + df.format( new Date( arrivaltime ) ) ); + + StringBuilder sb = new StringBuilder( "--- " ); + for( String line: lines ) + { + sb.append( line ).append( ' ' ); + } + sb.append( "--- " ); + long mins = ( arrivaltime-departtime ) / 60000L; + sb.append( mins ).append( "min" ); + sum.add( sb.toString() ); + + int firstOffset = -1; + boolean hasLaterTrips = false; + sb = new StringBuilder( "(+later trips: " ); + for ( int offset = 0; offset < offsets.size(); offset++ ) + { + if ( offsets.contains( offset ) ) + { + if ( firstOffset < 0 ) + { + firstOffset = offset; + } + else + { + sb.append( "+" + (offset-firstOffset) + "min " ); + hasLaterTrips = true; + } + } + if ( sb.length() > 47 ) + { + sb.setLength( 47 ); + sb.append( "..." ); + } + } + sb.append( ")" ); + if ( hasLaterTrips ) + { + sum.add( sb.toString() ); + } + + + } +} diff --git a/brouter-mem-router/src/main/java/btools/memrouter/OffsetSet.java b/brouter-mem-router/src/main/java/btools/memrouter/OffsetSet.java index 02a9d1e..8e730ec 100644 --- a/brouter-mem-router/src/main/java/btools/memrouter/OffsetSet.java +++ b/brouter-mem-router/src/main/java/btools/memrouter/OffsetSet.java @@ -5,141 +5,185 @@ */ package btools.memrouter; +import java.util.BitSet; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.SortedSet; public class OffsetSet { - private static Map existingSets = new HashMap(); - private static OffsetSet empty = new OffsetSet( 0L ); - private static OffsetSet full = new OffsetSet( -1L ); + private Map existingSets = new HashMap(); - protected long mask; - - private static int instancecount = 0; + private static final int size = 185; - public static OffsetSet emptySet() + protected BitSet mask; + + public OffsetSet emptySet() { - return empty; + return new OffsetSet( new BitSet( size ), existingSets ); } public static OffsetSet fullSet() { - return full; + BitSet allbits = new BitSet( size ); + allbits.set( 0, size ); + return new OffsetSet( allbits, new HashMap() ); } - private OffsetSet( long m ) + private OffsetSet( BitSet m, Map knownSets ) { + existingSets = knownSets; + existingSets.put( m , this ); mask = m; } - private static OffsetSet create( long m, OffsetSet template ) + private OffsetSet create( BitSet m ) { - if ( m == 0L ) - { - return null; - } - if ( m == template.mask ) - { - return template; - } - - Long mm = Long.valueOf( m ); - OffsetSet set = existingSets.get( mm ); - if ( set == null ) - { - set = new OffsetSet( m ); - existingSets.put( mm, set ); - instancecount++; - System.out.println( "created set: " + set + " instancecount=" + instancecount ); - } - return set; + if ( m.isEmpty() ) + { + return null; + } + if ( m.equals( mask ) ) + { + return this; + } + + OffsetSet set = existingSets.get( m ); + if ( set == null ) + { + set = new OffsetSet( m, existingSets ); +// System.out.println( "created set: " + set + " instancecount=" + existingSets.size() ); + } + return set; } - public static OffsetSet create( List offsets, OffsetSet template ) + + public OffsetSet create( List offsets ) { - long m = 0L; - for( Integer offset : offsets ) - { - int i = offset.intValue(); - if ( i >= 0 && i < 64 ) - { - m |= ( 1L << i ); - } - } - return create( m, template ); + BitSet m = new BitSet( size ); + for ( Integer offset : offsets ) + { + int i = offset.intValue(); + if ( i >= 0 && i < size ) + { + m.set( i ); + } + } + return create( m ); } - + + public OffsetSet filterWithSet( SortedSet usedTimes, int minuteArrival ) + { + BitSet fmask = (BitSet)mask.clone(); + int idx = 0; + int maxtime = usedTimes.isEmpty() ? Integer.MAX_VALUE: usedTimes.first().intValue() + size(); + + for(;;) + { + idx = fmask.nextSetBit( idx ); + if ( idx < 0 ) break; + int i = minuteArrival + idx; + if ( i > maxtime || !usedTimes.add( Integer.valueOf(i) ) ) + { + fmask.set( idx, false ); + } + idx++; + } + return create( fmask ); + } + public int size() { - return 64; + return size; } - + public boolean contains( int offset ) { - return ( ( 1L << offset ) & mask ) != 0L; + return mask.get( offset ); } - + public OffsetSet add( int offset ) { - return create( mask | ( 1L << offset ), this ); + if ( mask.get( offset ) ) + { + return this; + } + BitSet m = (BitSet)mask.clone(); + m.set( offset ); + return create( m ); } public OffsetSet add( OffsetSet offsets ) { - return create(mask | offsets.mask, this ); + BitSet m = (BitSet)mask.clone(); + m.or( offsets.mask ); + return create( m ); } + // clear all bits from this set in the argument set public OffsetSet filter( OffsetSet in ) { - long fmask = in.mask; - fmask = fmask ^ ( fmask & mask ); - return create( fmask, in ); + BitSet fmask = (BitSet)in.mask.clone(); + fmask.andNot( mask ); + return create( fmask ); } - public static OffsetSet filterAndClose( OffsetSet in, OffsetSetHolder gateHolder, int timeDiff ) + public OffsetSet ensureMaxOffset( int max ) { - OffsetSet gate = gateHolder.getOffsetSet(); - long gmask = gate.mask; - - long fmask = in.mask; - - // delete the high offsets with offset + timeDiff >= maxoffset - fmask = timeDiff > 31 ? 0L : ( fmask << timeDiff ) >> timeDiff; - - fmask = fmask ^ ( fmask & gmask ); - - gmask |= fmask; - - gateHolder.setOffsetSet( create( gmask, gate ) ); // modify the gate - - if ( timeDiff > 0 ) - { - fmask = fmask ^ ( fmask & (gmask >> timeDiff) ); - } - return create( fmask, in ); + if ( max < size ) + { + BitSet fmask = (BitSet)mask.clone(); + fmask.set( max > 0 ? max : 0, size, false ); + return create( fmask ); + } + return this; } - - + + public OffsetSet filterAndClose( OffsetSetHolder gateHolder, boolean closeGate ) + { + OffsetSet gate = gateHolder.getOffsetSet(); + BitSet gmask = (BitSet)gate.mask.clone(); + + BitSet fmask = (BitSet)mask.clone(); + + fmask.andNot( gmask ); + + gmask.or( fmask ); + + if ( closeGate ) + { + gateHolder.setOffsetSet( create( gmask ) ); // modify the gate + } + return create( fmask ); + } + + public OffsetSet sweepWith( OffsetSet sweeper, int timeDiff ) + { + BitSet sweepmask = sweeper.mask; + BitSet fmask = (BitSet)mask.clone(); + + if ( timeDiff >= 0 ) + { + int idx = 0; + for(;;) + { + idx = sweepmask.nextSetBit( idx ) + 1; + if ( idx < 1 ) break; + + int sweepStart = Math.max( 0, idx-timeDiff ); + fmask.set( sweepStart, idx, false ); + } + int sweepStart = Math.max( 0, size-timeDiff ); + fmask.set( sweepStart, size, false ); + } +// System.out.println( "sweep: " + mask + " with: " + sweepmask + "=" + fmask ); + + return create( fmask ); + } + @Override public String toString() { - if ( mask == -1L ) return "*"; - - StringBuilder sb = new StringBuilder(); - int nbits = 0; - for( int i=0; i<65; i++ ) - { - boolean bit = i < 64 ? ((1L << i) & mask) != 0L : false; - if ( bit ) nbits++; - else if ( nbits > 0) - { - if ( sb.length() > 0 ) sb.append( ',' ); - if ( nbits == 1) sb.append( i-1 ); - else sb.append( (i-nbits) + "-" + (i-1) ); - nbits = 0; - } - } - return sb.toString(); + return mask.toString(); } } diff --git a/brouter-mem-router/src/main/java/btools/memrouter/OsmLinkP.java b/brouter-mem-router/src/main/java/btools/memrouter/OsmLinkP.java index 38933c0..7ccdc8c 100644 --- a/brouter-mem-router/src/main/java/btools/memrouter/OsmLinkP.java +++ b/brouter-mem-router/src/main/java/btools/memrouter/OsmLinkP.java @@ -5,16 +5,15 @@ */ package btools.memrouter; - public class OsmLinkP implements OffsetSetHolder { - /** - * The description bitmap is mainly the way description - * used to calculate the costfactor + /** + * The description bitmap is mainly the way description used to calculate the + * costfactor */ public byte[] descriptionBitmap; - /** + /** * The target is either the next link or the target node */ protected OsmNodeP sourceNode; @@ -23,12 +22,12 @@ public class OsmLinkP implements OffsetSetHolder protected OsmLinkP previous; protected OsmLinkP next; - public static int currentserial = 0; // serial version to invalidate link occupation + public static int currentserial = 0; // serial version to invalidate link + // occupation private int instanceserial = 0; private OffsetSet offsets; - private int time; - + public boolean isConnection() { return descriptionBitmap == null; @@ -44,59 +43,61 @@ public class OsmLinkP implements OffsetSetHolder sourceNode = source; targetNode = target; } - + protected OsmLinkP() { } public OffsetSet getOffsetSet() { - return offsets; + return offsets; } public void setOffsetSet( OffsetSet offsets ) { - this.offsets = offsets; + this.offsets = offsets; } - + public boolean isVirgin() { - return instanceserial != currentserial; + return instanceserial != currentserial; } - - public OffsetSet filterAndClose( OffsetSet in, long arrival, boolean scheduled ) + + public OffsetSet filterAndClose( OffsetSet in, long arrival ) { - int minutesArrival = (int)(arrival/60000L); if ( offsets == null || isVirgin() ) { - time = minutesArrival; - instanceserial = currentserial; - offsets = in; - return in; + initLink(); + offsets = in; + return in; } - return OffsetSet.filterAndClose( in, this, scheduled ? minutesArrival - time : 0 ); + return in.filterAndClose( this, true ); } - + protected void initLink() + { + instanceserial = currentserial; + } + /** * Set the relevant next-pointer for the given source */ public void setNext( OsmLinkP link, OsmNodeP source ) { - if ( sourceNode == source ) - { - next = link; - } - else if ( targetNode == source ) - { - previous = link; - } - else - { - throw new IllegalArgumentException( "internal error: setNext: unknown source" ); - } - } - + if ( sourceNode == source ) + { + next = link; + } + else if ( targetNode == source ) + { + previous = link; + } + else + { + throw new IllegalArgumentException( "internal error: setNext: unknown source" ); + } + } + /** * Get the relevant next-pointer for the given source */ @@ -107,7 +108,7 @@ public class OsmLinkP implements OffsetSetHolder return next; } else if ( targetNode == source ) - { + { return previous; } else @@ -126,7 +127,7 @@ public class OsmLinkP implements OffsetSetHolder return targetNode; } else if ( targetNode == source ) - { + { return sourceNode; } else @@ -145,7 +146,7 @@ public class OsmLinkP implements OffsetSetHolder return false; } else if ( targetNode == source ) - { + { return true; } else diff --git a/brouter-mem-router/src/main/java/btools/memrouter/OsmNodeP.java b/brouter-mem-router/src/main/java/btools/memrouter/OsmNodeP.java index a5e8dbb..18ed30e 100644 --- a/brouter-mem-router/src/main/java/btools/memrouter/OsmNodeP.java +++ b/brouter-mem-router/src/main/java/btools/memrouter/OsmNodeP.java @@ -146,5 +146,13 @@ public class OsmNodeP extends OsmLinkP implements Comparable, OsmPos return 0; } - + public OffsetSet filterAndCloseNode( OffsetSet in, boolean modifyGate ) + { + return in; // do nothing (StationNode overrides) + } + + public String getName() + { + return ""; + } } diff --git a/brouter-mem-router/src/main/java/btools/memrouter/ScheduleParser.java b/brouter-mem-router/src/main/java/btools/memrouter/ScheduleParser.java index 681420b..a211180 100644 --- a/brouter-mem-router/src/main/java/btools/memrouter/ScheduleParser.java +++ b/brouter-mem-router/src/main/java/btools/memrouter/ScheduleParser.java @@ -7,150 +7,169 @@ package btools.memrouter; import java.io.BufferedReader; import java.io.File; -import java.io.FileReader; +import java.io.FileInputStream; +import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; import btools.expressions.BExpressionContextWay; - final class ScheduleParser { - public static void parseTrainTable( File[] files, GraphLoader graph, BExpressionContextWay expctxWay ) - { - try - { - ScheduledLine currentLine = null; - StationNode lastStationInLine = null; + public static Map parseTrainTable( File[] files, GraphLoader graph, BExpressionContextWay expctxWay ) + { + ScheduledLine currentLine = null; + StationNode lastStationInLine = null; - boolean readingLocations = false; - - Map stationMap = new HashMap(); - - - for( File file : files ) - { - BufferedReader br = new BufferedReader( new FileReader( file ) ); - for(;;) - { - String line = br.readLine(); - if ( line == null ) break; - line = line.trim(); - if ( line.length() == 0 ) continue; - - if ( line.startsWith( "#" ) ) continue; - - if ( line.startsWith( "-- locations" ) ) - { - readingLocations = true; - continue; - } - if ( line.startsWith( "-- trainline" ) ) - { - readingLocations = false; - currentLine = new ScheduledLine(); - currentLine.name = line.substring("-- trainline".length() ).trim(); - lastStationInLine = null; - continue; - } - if ( readingLocations ) - { - StationNode station = new StationNode(); - - // Eschborn 50.14323,8.56112 - StringTokenizer tk = new StringTokenizer( line, " " ); - station.name = tk.nextToken(); - - if ( stationMap.containsKey( station.name ) ) - { - System.out.println( "skipping station name already known: " + station.name ); - continue; - } - - int locIdx = 0; - String loc = null; - int elev = 0; - int nconnections = 0; - while( tk.hasMoreTokens() || locIdx == 1 ) - { - if ( tk.hasMoreTokens() ) - { - loc = tk.nextToken(); - } - StringTokenizer tloc = new StringTokenizer( loc, "," ); - int ilat = (int)( ( Double.parseDouble( tloc.nextToken() ) + 90. ) *1000000. + 0.5); - int ilon = (int)( ( Double.parseDouble( tloc.nextToken() ) + 180. ) *1000000. + 0.5); - if ( locIdx == 0 ) - { - station.ilat = ilat; - station.ilon = ilon; - } - else - { - OsmNodeP pos = new OsmNodeP(); - pos.ilat = ilat; - pos.ilon = ilon; - - OsmNodeP node = graph.matchNodeForPosition( pos,expctxWay ); - if ( node != null ) - { - elev += node.selev; - nconnections++; + boolean readingLocations = false; - // link station to connecting node - OsmLinkP link = new OsmLinkP( station, node ); - link.descriptionBitmap = null; - station.addLink( link ); - node.addLink( link ); - - int distance = station.calcDistance( node ); - System.out.println( "matched connection for station " + station.name + " at " + distance + " meter" ); - } - } - locIdx++; - } - if ( nconnections > 0 ) - { - station.selev = (short)(elev / nconnections); - } - stationMap.put( station.name, station ); - } - else if ( currentLine != null ) - { - int idx = line.indexOf( ' ' ); - String name = line.substring( 0, idx ); - StationNode nextStationInLine = stationMap.get( name ); - String value = line.substring( idx ).trim(); - int offsetMinute = 0; - if ( lastStationInLine == null ) - { - currentLine.schedule = new TrainSchedule( value ); - } - else - { - if ( value.startsWith( "+") ) value = value.substring( 1 ); - offsetMinute = Integer.parseInt( value ); - - ScheduledLink link = new ScheduledLink( lastStationInLine, nextStationInLine ); - link.line = currentLine; - link.indexInLine = currentLine.offsetMinutes.size()-1; - -System.out.println( "adding: " + link ); - lastStationInLine.addLink( link ); - } - currentLine.offsetMinutes.add( Integer.valueOf( offsetMinute ) ); - - lastStationInLine = nextStationInLine; - } - } - br.close(); - System.out.println( "read " + stationMap.size() + " stations" ); - } - } - catch( Exception e ) - { - throw new RuntimeException( e ); - } - } + Map stationMap = new HashMap(); + + for ( File file : files ) + { + BufferedReader br = null; + try + { + br = new BufferedReader( new InputStreamReader( new FileInputStream( file ) , "ISO-8859-1" ) ); + for ( ;; ) + { + String line = br.readLine(); + if ( line == null ) + break; + line = line.trim(); + if ( line.length() == 0 ) + continue; + + if ( line.startsWith( "#" ) ) + continue; + + if ( line.startsWith( "-- locations" ) ) + { + readingLocations = true; + continue; + } + if ( line.startsWith( "-- trainline" ) ) + { + readingLocations = false; + currentLine = new ScheduledLine(); + currentLine.name = line.substring( "-- trainline".length() ).trim(); + lastStationInLine = null; + continue; + } + if ( readingLocations ) + { + StationNode station = new StationNode(); + + // Eschborn 50.14323,8.56112 + StringTokenizer tk = new StringTokenizer( line, " \t" ); + station.name = tk.nextToken(); + + if ( stationMap.containsKey( station.name ) ) + { + System.out.println( "skipping station name already known: " + station.name ); + continue; + } + + int locIdx = 0; + String loc = null; + int elev = 0; + int nconnections = 0; + while (tk.hasMoreTokens() || locIdx == 1) + { + if ( tk.hasMoreTokens() ) + { + loc = tk.nextToken(); + } + StringTokenizer tloc = new StringTokenizer( loc, "," ); + int ilat = (int) ( ( Double.parseDouble( tloc.nextToken() ) + 90. ) * 1000000. + 0.5 ); + int ilon = (int) ( ( Double.parseDouble( tloc.nextToken() ) + 180. ) * 1000000. + 0.5 ); + if ( locIdx == 0 ) + { + station.ilat = ilat; + station.ilon = ilon; + } + else + { + OsmNodeP pos = new OsmNodeP(); + pos.ilat = ilat; + pos.ilon = ilon; + + OsmNodeP node = graph.matchNodeForPosition( pos, expctxWay, false ); + if ( node != null ) + { + elev += node.selev; + nconnections++; + + // link station to connecting node + OsmLinkP link = new OsmLinkP( station, node ); + link.descriptionBitmap = null; + station.addLink( link ); + node.addLink( link ); + + int distance = station.calcDistance( node ); + System.out.println( "matched connection for station " + station.name + " at " + distance + " meter" ); + } + } + locIdx++; + } + if ( nconnections > 0 ) + { + station.selev = (short) ( elev / nconnections ); + } + stationMap.put( station.name, station ); + } + else if ( currentLine != null ) + { + int idx = line.indexOf( ' ' ); + String name = line.substring( 0, idx ); + StationNode nextStationInLine = stationMap.get( name ); + if ( nextStationInLine == null ) + { + throw new IllegalArgumentException( "unknown station: " + name ); + } + String value = line.substring( idx ).trim(); + int offsetMinute = 0; + if ( lastStationInLine == null ) + { + currentLine.schedule = new TrainSchedule( value ); + } + else + { + if ( value.startsWith( "+" ) ) + value = value.substring( 1 ); + offsetMinute = Integer.parseInt( value ); + + ScheduledLink link = new ScheduledLink( lastStationInLine, nextStationInLine ); + link.line = currentLine; + link.indexInLine = currentLine.offsetMinutes.size() - 1; + + // System.out.println( "adding: " + link ); + lastStationInLine.addLink( link ); + } + currentLine.offsetMinutes.add( Integer.valueOf( offsetMinute ) ); + + lastStationInLine = nextStationInLine; + } + } + System.out.println( "read " + stationMap.size() + " stations" ); + } + catch (Exception e) + { + throw new RuntimeException( e ); + } + finally + { + if ( br != null ) + { + try + { + br.close(); + } + catch (Exception e) { /* ignore */ } + } + } + } + return stationMap; + } } diff --git a/brouter-mem-router/src/main/java/btools/memrouter/ScheduledLine.java b/brouter-mem-router/src/main/java/btools/memrouter/ScheduledLine.java index 78054ca..8bf37d9 100644 --- a/brouter-mem-router/src/main/java/btools/memrouter/ScheduledLine.java +++ b/brouter-mem-router/src/main/java/btools/memrouter/ScheduledLine.java @@ -11,93 +11,96 @@ import java.util.HashMap; import java.util.List; import java.util.Map; - final class ScheduledLine { - String name; - List offsetMinutes = new ArrayList(); - TrainSchedule schedule; + String name; + List offsetMinutes = new ArrayList(); + TrainSchedule schedule; - - /** - * get a list of departures relative to the start-time plus - * the individual offsets according to the offset mask - * - * departures with the same wait-time are aggregated in one - * result element with multiple 1-bits in the offset mask - * - * departures with different wait-times are returned as separate items - * - * @param id the value to add to this set. - * @return true if "id" already contained in this set. - */ - public List getScheduledDepartures( int idx, long timeFrom, OffsetSet offsets ) - { - List result = new ArrayList(); + /** + * get a list of departures relative to the start-time plus the individual + * offsets according to the offset mask + * + * departures with the same wait-time are aggregated in one result element + * with multiple 1-bits in the offset mask + * + * departures with different wait-times are returned as separate items + * + * @param id + * the value to add to this set. + * @return true if "id" already contained in this set. + */ + public List getScheduledDepartures( int idx, long timeFrom, OffsetSet offsets ) + { + List result = new ArrayList(); - long minutesFrom = (timeFrom + 59999L) / 60000L; - long timeFromCorrection = minutesFrom * 60000L - timeFrom; + long minutesFrom = ( timeFrom + 59999L ) / 60000L; + long timeFromCorrection = minutesFrom * 60000L - timeFrom; - if ( idx < 0 || idx >= offsetMinutes.size() -1 ) return result; - - int offsetStart = offsetMinutes.get(idx).intValue(); - int offsetEnd = offsetMinutes.get(idx+1).intValue(); - - - Map> waitOffsets = getDepartures( offsetStart, timeFrom + timeFromCorrection, offsets ); - - for( Map.Entry> e : waitOffsets.entrySet() ) - { - ScheduledDeparture depart = new ScheduledDeparture( ); - depart.waitTime = e.getKey().intValue() * 60000L + timeFromCorrection; - depart.offsets = OffsetSet.create( e.getValue(), offsets ); - depart.rideTime = (offsetEnd-offsetStart)*60000L; - result.add( depart ); - } - return result; - } + if ( idx < 0 || idx >= offsetMinutes.size() - 1 ) + return result; - private Map> getDepartures( int offsetStart, long timeFrom, OffsetSet offsets ) - { - Map> waitOffsets = new HashMap>(); - int size = offsets.size(); - - for(int offset = 0;;) - { - // skip to next offset bit - while( offset < size && !offsets.contains( offset ) ) - { - offset++; - } - if ( offset >= size ) return waitOffsets; - - int toNext = schedule.getMinutesToNext( timeFrom + 60000L*(offset - offsetStart ) ); - if ( toNext < 0 ) return waitOffsets; - int departOffset = offset + toNext; - - // whats the closest offset within the next toNext minutes - int lastOffset = offset; - while( toNext-- >= 0 && offset < size ) - { - if ( offsets.contains( offset ) ) - { - lastOffset = offset; - } - offset++; - } - - if ( lastOffset == size-1 ) return waitOffsets; // todo? - - int waitTime = departOffset - lastOffset; - - // if we have that wait time in the list, just add the offset bit - List offsetList = waitOffsets.get( Integer.valueOf( waitTime ) ); - if ( offsetList == null ) - { - offsetList = new ArrayList(); - waitOffsets.put( Integer.valueOf( waitTime ), offsetList ); - } - offsetList.add( Integer.valueOf( lastOffset ) ); - } - } + int offsetStart = offsetMinutes.get( idx ).intValue(); + int offsetEnd = offsetMinutes.get( idx + 1 ).intValue(); + + Map> waitOffsets = getDepartures( offsetStart, timeFrom + timeFromCorrection, offsets ); + + for ( Map.Entry> e : waitOffsets.entrySet() ) + { + ScheduledDeparture depart = new ScheduledDeparture(); + depart.waitTime = e.getKey().intValue() * 60000L + timeFromCorrection; + depart.offsets = offsets.create( e.getValue() ); + depart.rideTime = ( offsetEnd - offsetStart ) * 60000L; + result.add( depart ); + } + return result; + } + + private Map> getDepartures( int offsetStart, long timeFrom, OffsetSet offsets ) + { + Map> waitOffsets = new HashMap>(); + int size = offsets.size(); + + for ( int offset = 0;; ) + { + // skip to next offset bit + while (offset < size && !offsets.contains( offset )) + { + offset++; + } + if ( offset >= size ) + return waitOffsets; + + int toNext = schedule.getMinutesToNext( timeFrom + 60000L * ( offset - offsetStart ) ); + + if ( toNext < 0 ) + return waitOffsets; + int departOffset = offset + toNext; + + // whats the closest offset within the next toNext minutes + int lastOffset = offset; + while (toNext-- >= 0 && offset < size) + { + if ( offsets.contains( offset ) ) + { + lastOffset = offset; + } + offset++; + } + + // if ( lastOffset == size - 1 ) + // return waitOffsets; // todo? + + int waitTime = departOffset - lastOffset; + + // if we have that wait time in the list, just add the offset bit + List offsetList = waitOffsets.get( Integer.valueOf( waitTime ) ); + if ( offsetList == null ) + { + offsetList = new ArrayList(); + waitOffsets.put( Integer.valueOf( waitTime ), offsetList ); + } + offsetList.add( Integer.valueOf( lastOffset ) ); + } + } } diff --git a/brouter-mem-router/src/main/java/btools/memrouter/ScheduledLink.java b/brouter-mem-router/src/main/java/btools/memrouter/ScheduledLink.java index 84bef12..23c75df 100644 --- a/brouter-mem-router/src/main/java/btools/memrouter/ScheduledLink.java +++ b/brouter-mem-router/src/main/java/btools/memrouter/ScheduledLink.java @@ -5,6 +5,9 @@ */ package btools.memrouter; +import java.util.SortedSet; +import java.util.TreeSet; + public class ScheduledLink extends OsmLinkP { @@ -30,4 +33,26 @@ public class ScheduledLink extends OsmLinkP { return "ScheduledLink: line=" + line.name + " indexInLine=" + indexInLine; } + + private SortedSet usedTimes; + + @Override + protected void initLink() + { + super.initLink(); + usedTimes = new TreeSet(); + } + + + public OffsetSet filterAndClose( OffsetSet in, long arrival ) + { + OffsetSet filtered = super.filterAndClose( in, arrival ); + if ( filtered != null && arrival >= 0 ) + { + int minutesArrival = (int) ( arrival / 60000L ); + filtered = filtered.filterWithSet( usedTimes, minutesArrival ); + } + return filtered; + } + } diff --git a/brouter-mem-router/src/main/java/btools/memrouter/ScheduledRouter.java b/brouter-mem-router/src/main/java/btools/memrouter/ScheduledRouter.java index 06d79f0..ae88de7 100644 --- a/brouter-mem-router/src/main/java/btools/memrouter/ScheduledRouter.java +++ b/brouter-mem-router/src/main/java/btools/memrouter/ScheduledRouter.java @@ -5,7 +5,9 @@ */ package btools.memrouter; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.List; @@ -16,406 +18,578 @@ import btools.router.RoutingContext; import btools.router.RoutingEngine; import btools.util.SortedHeap; - final class ScheduledRouter { - private GraphLoader graph; - - private int solutionCount = 0; - - public long linksProcessed = 0L; - public long linksReProcessed = 0L; - public long closedSkippedChained = 0L; - public long skippedChained = 0L; - - private RoutingContext rc; - private RoutingEngine re; - - private long time0; - private OsmNodeP start; - private OsmNodeP end; + private GraphLoader graph; - SortedHeap openSet = new SortedHeap(); + public long linksProcessed = 0L; + public long linksReProcessed = 0L; + public long closedSkippedChained = 0L; + public long skippedChained = 0L; - ScheduledRouter( GraphLoader graph, RoutingContext rc, RoutingEngine re ) - { - this.graph = graph; - this.rc = rc; - this.re = re; - } - - - public OsmTrack findRoute( OsmPos startPos, OsmPos endPos, String startTime, int alternativeIdx ) throws Exception - { - OsmTrack track = null; - - start = graph.matchNodeForPosition( startPos, rc.expctxWay ); - if ( start == null ) throw new IllegalArgumentException( "unmatched start: " + startPos ); - end = graph.matchNodeForPosition( endPos, rc.expctxWay ); - if ( end == null ) throw new IllegalArgumentException( "unmatched end: " + endPos ); + private RoutingContext rc; + private RoutingEngine re; -// SimpleDateFormat df = new SimpleDateFormat( "dd.MM.yyyy-HH:mm" ); -// time0 = df.parse(startTime).getTime(); -time0 = System.currentTimeMillis() + (long)(rc.starttimeoffset * 60000L ); -long minutes0 = (time0 + 59999L) / 60000L; -time0 = minutes0 * 60000L; + private long time0; + private OsmNodeP start; + private OsmNodeP end; - OffsetSet finishedOffsets = OffsetSet.emptySet(); - - OsmLinkP startLink = new OsmLinkP( null, start ); - - ScheduledTrip startTrip = new ScheduledTrip( OffsetSet.fullSet(), startLink, null, null ); - openSet.add( 0, startTrip ); - for(;;) - { - if ( re.isTerminated() ) - { - throw new RuntimeException( "operation terminated" ); - } - if ( linksProcessed + linksReProcessed > 5000000 ) - { - throw new RuntimeException( "5 Million links limit reached" ); - } - - // get cheapest trip from heap - ScheduledTrip trip = openSet.popLowestKeyValue(); - if ( trip == null ) - { - break; - } - OsmLinkP currentLink = trip.link; - OsmNodeP currentNode = trip.getTargetNode(); - if ( currentNode == null ) - { - System.out.println( "ups: " + trip ); - continue; - } - - if ( currentLink.isVirgin() ) - { - linksProcessed++; - } - else - { - linksReProcessed++; - } - - // check global closure - OffsetSet offsets = finishedOffsets.filter( trip.offsets ); - if ( offsets == null ) continue; + SortedHeap openSet = new SortedHeap(); - // check local closure for links: - offsets = currentLink.filterAndClose( offsets, trip.arrival, currentLink instanceof ScheduledLink ); - if ( offsets == null ) continue; - - - // check for arrival - if ( currentNode == end ) - { - for( int offset = 0; offset= alternativeIdx ) return track; - } - for( OsmLinkP link = currentNode.getFirstLink(); link != null; link = link.getNext( currentNode ) ) - { - addNextTripsForLink(trip, currentNode, currentLink, link, offsets, 0 ); - } - } - return track; - } - - private void addToOpenSet( ScheduledTrip nextTrip ) + ScheduledRouter( GraphLoader graph, RoutingContext rc, RoutingEngine re ) + { + this.graph = graph; + this.rc = rc; + this.re = re; + } + + private static List trips = new ArrayList(); + private static long oldChecksum = 0; + + private String startEndText() + { + return (start == null ? "unmatched" : start.getName() ) + "->" + (end == null ? "unmatched" : end.getName() ); + } + + public OsmTrack findRoute( OsmPos startPos, OsmPos endPos, int alternativeIdx ) throws Exception + { + if ( alternativeIdx == -1 ) // lowest cost result { - int distance = nextTrip.getTargetNode().calcDistance( end ); - nextTrip.adjustedCost = nextTrip.cost + (int)(distance * rc.pass1coefficient + 0.5); - openSet.add( nextTrip.adjustedCost, nextTrip ); + List singleTrip = _findRoute( startPos, endPos, true ); + if ( singleTrip.isEmpty() ) + { + if ( linksProcessed + linksReProcessed > 5000000 ) throw new RuntimeException( "5 million links limit reached" ); + else throw new RuntimeException( "no track found! (" + startEndText() + ")" ); + } + Iternity iternity = singleTrip.get( 0 ); + OsmTrack t = iternity.track; + t.iternity = iternity.details; + return t; } - - - private void addNextTripsForLink( ScheduledTrip trip, OsmNodeP currentNode, OsmLinkP currentLink, OsmLinkP link, OffsetSet offsets, int level ) - { - if ( link == currentLink ) - { - return; // just reverse, ignore - } - OsmNodeP node = link.getTarget(currentNode); - if ( node == null ) - { - System.out.println( "ups2: " + link ); - return; - } - // calc distance and check nogos - rc.nogomatch = false; - int distance = rc.calcDistance( currentNode.ilon, currentNode.ilat, node.ilon, node.ilat ); - if ( rc.nogomatch ) + // check for identical params + long[] nogocheck = rc.getNogoChecksums(); + + long checksum = nogocheck[0] + nogocheck[1] + nogocheck[2]; + checksum += startPos.getILat() + startPos.getILon() + endPos.getILat() + endPos.getILon(); + checksum += rc.localFunction.hashCode(); + + if ( checksum != oldChecksum ) + { + trips = _findRoute( startPos, endPos, false ); + Collections.sort( trips ); // sort by arrival time + oldChecksum = checksum; + } + + if ( trips.isEmpty() ) + { + if ( linksProcessed + linksReProcessed > 5000000 ) throw new RuntimeException( "5 million links limit reached" ); + else throw new RuntimeException( "no track found! (" + startEndText() + ")" ); + } + + if ( alternativeIdx == 0 ) // = result overview + { + List details = new ArrayList(); + for ( int idx = 0; idx < trips.size(); idx++ ) + { + if ( idx > 0 ) details.add( "" ); + Iternity iternity = trips.get( idx ); + iternity.appendSummary( details ); + } + Iternity iternity = trips.get( 0 ); + OsmTrack t = iternity.track; + t.iternity = details; + return t; + } + + int idx = alternativeIdx > trips.size() ? trips.size()-1 : alternativeIdx-1; + Iternity iternity = trips.get( idx ); + OsmTrack t = iternity.track; + t.iternity = iternity.details; + return t; + } + + + private List _findRoute( OsmPos startPos, OsmPos endPos, boolean fastStop ) throws Exception + { + List iternities = new ArrayList(); + + start = graph.matchNodeForPosition( startPos, rc.expctxWay, rc.transitonly ); + if ( start == null ) + throw new IllegalArgumentException( "unmatched start: " + startPos ); + end = graph.matchNodeForPosition( endPos, rc.expctxWay, rc.transitonly ); + if ( end == null ) + throw new IllegalArgumentException( "unmatched end: " + endPos ); + + time0 = System.currentTimeMillis() + (long) ( rc.starttimeoffset * 60000L ); + long minutes0 = ( time0 + 59999L ) / 60000L; + time0 = minutes0 * 60000L; + + OffsetSet fullSet = OffsetSet.fullSet(); + OffsetSet finishedOffsets = fullSet.emptySet(); + + OsmLinkP startLink = new OsmLinkP( null, start ); + + ScheduledTrip startTrip = new ScheduledTrip( OffsetSet.fullSet(), startLink, null, null ); + openSet.add( 0, startTrip ); + for ( ;; ) + { + if ( re.isTerminated() ) + { + throw new RuntimeException( "operation terminated" ); + } + if ( linksProcessed + linksReProcessed > 5000000 ) + { + break; + } + + // get cheapest trip from heap + ScheduledTrip trip = openSet.popLowestKeyValue(); + if ( trip == null ) + { + break; + } + OsmLinkP currentLink = trip.link; + OsmNodeP currentNode = trip.getTargetNode(); + if ( currentNode == null ) + { + System.out.println( "ups: " + trip ); + continue; + } + + if ( currentLink.isVirgin() ) + { + linksProcessed++; + } + else + { + linksReProcessed++; + } + + /* int maxOffset = (int)((maxarrival - trip.arrival)/60000L); + OffsetSet offsets = trip.offsets.ensureMaxOffset( maxOffset ); + if ( offsets == null ) + continue; + */ + + OffsetSet offsets = trip.offsets; + + // check global closure + offsets = finishedOffsets.filter( offsets ); + if ( offsets == null ) + continue; + +/* offsets = efficientSubset( offsets, trip.adjustedCost ); + if ( offsets == null ) + continue; +*/ + + boolean continueOnLineOnly = false; + // check local closure for the target node: + if ( currentNode.filterAndCloseNode( offsets, true ) == null ) + { + continueOnLineOnly = true; + } + + // check local closure for links: + offsets = currentLink.filterAndClose( offsets, trip.arrival ); + if ( offsets == null ) + continue; + + // check for arrival + if ( currentNode == end ) + { + Iternity iternity = null; + OffsetSet toffsets = trip.offsets; + + int lastIdx = iternities.size()-1; + // hack: for equal cost tracks, merge offsets (assuming identical iternity) + if ( lastIdx >= 0 && iternities.get( lastIdx ).track.cost == trip.cost ) + { + toffsets = toffsets.add( iternities.get( lastIdx ).offsets ); + iternities.remove( lastIdx ); + } + + for ( int offset = 0; offset < trip.offsets.size(); offset++ ) + { + if ( trip.offsets.contains( offset ) ) + { + iternity = compileTrip( trip, offset ); + iternity.offsets = toffsets; + System.out.println( "---- begin route ------ (cost " + iternity.track.cost + ")" ); + for ( String s : iternity.details ) + System.out.println( s ); + System.out.println( "---- end route ------ (arrival " + new Date( iternity.arrivaltime ) + ")" ); + break; // + plus more offsets.. + } + } + finishedOffsets = finishedOffsets.add( offsets ); + if ( iternity != null ) + { + // tracks come in cost-ascending order, so the arrival time + // must decrease for the new track to be efficient +// if ( iternities.isEmpty() || iternities.get( iternities.size() - 1 ).arrivaltime > iternity.arrivaltime ) + if ( efficientSubset( iternities, iternity.offsets, iternity.track.cost ) != null ) + { + iternities.add( iternity ); + if ( fastStop ) + { + break; + } +System.out.println( "*** added track to result list !**** "); + } + } +System.out.println( "*** finishedOffsets = " + finishedOffsets ); + + } + for ( OsmLinkP link = currentNode.getFirstLink(); link != null; link = link.getNext( currentNode ) ) + { + if ( continueOnLineOnly ) + { + if ( ! ( currentLink instanceof ScheduledLink && link instanceof ScheduledLink ) ) continue; + if ( ((ScheduledLink) currentLink).line != ((ScheduledLink) link ).line ) continue; + } + +/* // pre-check target closure + if ( link.getTarget( currentNode ).filterAndCloseNode( offsets, false ) == null ) + { + continue; + } +*/ + if ( !rc.transitonly || link instanceof ScheduledLink ) + { + addNextTripsForLink( trip, currentNode, currentLink, link, offsets, 0 ); + } + } + } + return iternities; + } + + private OffsetSet efficientSubset( List iternities, OffsetSet offsets, int cost ) + { + for( Iternity it : iternities ) + { + // determine a time-diff from a cost-diff + int dcost = cost - it.track.cost; + int dtime = (int) ( dcost * .06 / rc.cost1speed + 1. ); // 22km/h + offsets = offsets.sweepWith( it.offsets, dtime ); + if ( offsets == null ) + { + return null; + } + } + return offsets; + } + + + private void addToOpenSet( ScheduledTrip nextTrip ) + { + int distance = nextTrip.getTargetNode().calcDistance( end ); + nextTrip.adjustedCost = nextTrip.cost + (int) ( distance * rc.pass1coefficient + 0.5 ); + openSet.add( nextTrip.adjustedCost, nextTrip ); + } + + private void addNextTripsForLink( ScheduledTrip trip, OsmNodeP currentNode, OsmLinkP currentLink, OsmLinkP link, OffsetSet offsets, int level ) + { + OsmNodeP node = link.getTarget( currentNode ); + if ( node == null ) + { + System.out.println( "ups2: " + link ); + return; + } + + if ( node == trip.originNode ) + { + link.filterAndClose( offsets, -1 ); // invalidate reverse link + return; + } + + // calc distance and check nogos + rc.nogomatch = false; + int distance = rc.calcDistance( currentNode.ilon, currentNode.ilat, node.ilon, node.ilat ); + if ( rc.nogomatch ) + { + return; + } + + if ( link instanceof ScheduledLink ) + { + // System.out.println( "next trip for link: " + link + " at offset " + + // offsets ); + + ScheduledLink slink = (ScheduledLink) link; + ScheduledLine line = slink.line; + + // line change delay + long delay = 0L; + if ( currentLink instanceof ScheduledLink ) + { + delay = ( (ScheduledLink) currentLink ).line == line ? 0L : (long) ( rc.changetime * 1000. ); // 3 minutes + } + long changePenalty = delay > 0 ? 60000L : 0L; + + List nextDepartures = line.getScheduledDepartures( slink.indexInLine, time0 + trip.arrival + delay, offsets ); + for ( ScheduledDeparture nextDeparture : nextDepartures ) + { + ScheduledTrip nextTrip = new ScheduledTrip( nextDeparture.offsets, link, currentNode, trip ); + long waitTime = nextDeparture.waitTime + delay; + long rideTime = nextDeparture.rideTime; + + nextTrip.cost = trip.cost + (int) ( ( rideTime + changePenalty + waitTime * rc.waittimeadjustment ) * rc.cost1speed / 3600. ); // 22km/h + nextTrip.departure = trip.arrival + waitTime; + nextTrip.arrival = nextTrip.departure + rideTime; + + addToOpenSet( nextTrip ); + + // System.out.println( "found: " + nextTrip ); + } + } + else if ( link.isWayLink() ) + { + // get costfactor + rc.expctxWay.evaluate( link.isReverse( currentNode ), link.descriptionBitmap, null ); + + // *** penalty for distance + float costfactor = rc.expctxWay.getCostfactor(); + if ( costfactor > 9999. ) { return; } + int waycost = (int) ( distance * costfactor + 0.5f ); - if ( link instanceof ScheduledLink ) + // *** add initial cost if factor changed + float costdiff = costfactor - trip.lastcostfactor; + if ( costdiff > 0.0005 || costdiff < -0.0005 ) { -// System.out.println( "next trip for link: " + link + " at offset " + offsets ); - - ScheduledLink slink = (ScheduledLink)link; - ScheduledLine line = slink.line; - - // line change delay - long delay = 0L; - if ( currentLink instanceof ScheduledLink ) - { - delay = ((ScheduledLink)currentLink).line == line ? 0L : (long)(rc.changetime * 1000.); // 3 minutes - } - long changePenalty = delay > 0 ? 60000L : 0L; - - List nextDepartures = line.getScheduledDepartures( slink.indexInLine, time0 + trip.arrival + delay, offsets ); - for( ScheduledDeparture nextDeparture : nextDepartures ) - { - ScheduledTrip nextTrip = new ScheduledTrip( nextDeparture.offsets, link, currentNode, trip ); - long waitTime = nextDeparture.waitTime + delay; - long rideTime = nextDeparture.rideTime; - - nextTrip.cost = trip.cost + (int)( ( rideTime + changePenalty + waitTime*rc.waittimeadjustment ) * rc.cost1speed / 3600. ); // 160ms / meter = 22km/h - nextTrip.departure = trip.arrival + waitTime; - nextTrip.arrival = nextTrip.departure + rideTime; - - addToOpenSet( nextTrip ); - -// System.out.println( "found: " + nextTrip ); - } + waycost += (int) rc.expctxWay.getInitialcost(); } - else if ( link.isWayLink() ) + + if ( node.getNodeDecsription() != null ) { - // get costfactor - rc.expctxWay.evaluate( link.isReverse(currentNode), link.descriptionBitmap, null ); - - // *** penalty for distance - float costfactor = rc.expctxWay.getCostfactor(); - if ( costfactor > 9999. ) - { - return; - } - int waycost = (int)(distance * costfactor + 0.5f); - - // *** add initial cost if factor changed - float costdiff = costfactor - trip.lastcostfactor; - if ( costdiff > 0.0005 || costdiff < -0.0005 ) - { - waycost += (int)rc.expctxWay.getInitialcost(); - } - - - if ( node.getNodeDecsription() != null ) - { - rc.expctxNode.evaluate( rc.expctxWay.getNodeAccessGranted() != 0. , node.getNodeDecsription(), null ); - float initialcost = rc.expctxNode.getInitialcost(); - if ( initialcost >= 1000000. ) - { - return; - } - waycost += (int)initialcost; - } - - // *** penalty for turning angles - if ( trip.originNode != null ) - { - // penalty proportional to direction change - double cos = rc.calcCosAngle( trip.originNode.ilon, trip.originNode.ilat, currentNode.ilon, currentNode.ilat, node.ilon, node.ilat ); - int turncost = (int)(cos * rc.expctxWay.getTurncost() + 0.2 ); // e.g. turncost=90 -> 90 degree = 90m penalty - waycost += turncost; - } - - ScheduledTrip nextTrip = new ScheduledTrip( offsets, link, currentNode, trip ); - - // *** penalty for elevation - short ele2 = node.selev; - short ele1 = trip.selev; - int elefactor = 250000; - if ( ele2 == Short.MIN_VALUE ) ele2 = ele1; - nextTrip.selev = ele2; - if ( ele1 != Short.MIN_VALUE ) - { - nextTrip.ehbd = trip.ehbd + (ele1 - ele2)*elefactor - distance * rc.downhillcutoff; - nextTrip.ehbu = trip.ehbu + (ele2 - ele1)*elefactor - distance * rc.uphillcutoff; - } - - if ( nextTrip.ehbd > rc.elevationpenaltybuffer ) - { - int excess = nextTrip.ehbd - rc.elevationpenaltybuffer; - int reduce = distance * rc.elevationbufferreduce; - if ( reduce > excess ) - { - reduce = excess; - } - excess = nextTrip.ehbd - rc.elevationmaxbuffer; - if ( reduce < excess ) - { - reduce = excess; - } - nextTrip.ehbd -= reduce; - if ( rc.downhillcostdiv > 0 ) - { - int elevationCost = reduce/rc.downhillcostdiv; - waycost += elevationCost; - } - } - else if ( nextTrip.ehbd < 0 ) - { - nextTrip.ehbd = 0; - } - - if ( nextTrip.ehbu > rc.elevationpenaltybuffer ) - { - int excess = nextTrip.ehbu - rc.elevationpenaltybuffer; - int reduce = distance * rc.elevationbufferreduce; - if ( reduce > excess ) - { - reduce = excess; - } - excess = nextTrip.ehbu - rc.elevationmaxbuffer; - if ( reduce < excess ) - { - reduce = excess; - } - nextTrip.ehbu -= reduce; - if ( rc.uphillcostdiv > 0 ) - { - int elevationCost = reduce/rc.uphillcostdiv; - waycost += elevationCost; - } - } - else if ( nextTrip.ehbu < 0 ) - { - nextTrip.ehbu = 0; - } - - nextTrip.lastcostfactor = costfactor; - nextTrip.cost = trip.cost + (int)(waycost*rc.additionalcostfactor + 0.5); - nextTrip.departure = trip.arrival; - nextTrip.arrival = nextTrip.departure + (long) ( waycost * 3600. / rc.cost1speed ); // 160ms / meter = 22km/h - - addToOpenSet( nextTrip ); - } - else // connecting link - { - ScheduledTrip nextTrip = new ScheduledTrip( offsets, link, currentNode, trip ); - - long delay = (long)(rc.buffertime * 1000.); // 2 min - nextTrip.cost = trip.cost + (int)( delay*rc.waittimeadjustment * rc.cost1speed / 3600. ); - nextTrip.departure = trip.arrival; - nextTrip.arrival = nextTrip.departure + delay; - - addToOpenSet( nextTrip ); + rc.expctxNode.evaluate( rc.expctxWay.getNodeAccessGranted() != 0., node.getNodeDecsription(), null ); + float initialcost = rc.expctxNode.getInitialcost(); + if ( initialcost >= 1000000. ) + { + return; } - } - - private OsmTrack compileTrip( ScheduledTrip trip, int offset ) - { - OsmTrack track = new OsmTrack(); - track.iternity = new ArrayList(); - ScheduledTrip current = trip; - ScheduledLine lastLine = new ScheduledLine(); - ScheduledLine dummyLine = new ScheduledLine(); - List list = new ArrayList(); - - int distance = 0; - - ScheduledTrip itrip = null; - - String profile = extractProfile( rc.localFunction ); - - OsmNodeP nextNode = null; - while( current != null ) - { -System.out.println( "trip=" + current ); - OsmNodeP node = current.getTargetNode(); - OsmPathElement pe = OsmPathElement.create(node.ilon, node.ilat, node.selev, null, false ); - track.addNode(pe); - - if ( nextNode != null ) - { - distance += node.calcDistance( nextNode ); - } - - boolean isScheduled = current.link instanceof ScheduledLink; - boolean isConnection = current.link.descriptionBitmap == null && !isScheduled; - ScheduledLine line = isScheduled ? ((ScheduledLink)current.link).line : isConnection ? dummyLine : null; - - if ( line != lastLine && !isConnection ) - { - itrip = new ScheduledTrip(); - itrip.departure = current.departure; - itrip.arrival = current.arrival; - itrip.originNode = current.originNode; - itrip.link = current.link; - - if ( isScheduled && list.size() > 0 ) - { - list.get( list.size()-1 ).originNode = current.getTargetNode(); - } - list.add(itrip); - } - else if ( itrip != null && !isConnection ) - { - itrip.departure = current.departure; - itrip.originNode = current.originNode; - } - lastLine = line; - current = current.origin; - nextNode = node; - } - track.distance = distance; - track.cost = trip.cost; - - for( int i=list.size()-1; i>=0; i-- ) - { - current = list.get(i); - String lineName = profile; - - boolean isScheduled = current.link instanceof ScheduledLink; - if ( isScheduled ) - { - lineName = ((ScheduledLink)current.link).line.name; - } - String stationName = "*position*"; - if ( current.originNode instanceof StationNode ) - { - stationName = ((StationNode)current.originNode).name; - } - String nextStationName = "*position*"; - if ( i > 0 && list.get(i-1).originNode instanceof StationNode ) - { - nextStationName = ((StationNode)list.get(i-1).originNode).name; - } - { - Date d0 = new Date( time0 + 60000L * offset + current.departure ); - Date d1 = new Date( time0 + 60000L * offset + current.arrival ); - if ( track.iternity.size() > 0 ) track.iternity.add( "" ); - track.iternity.add( "depart: " + d0 + " " + stationName ); - track.iternity.add( " --- " + lineName + " ---" ); - track.iternity.add( "arrive: " + d1 + " " + nextStationName ); - } + waycost += (int) initialcost; } - return track; - } - - private String extractProfile( String s ) - { - int idx = s.lastIndexOf( '/' ); - if ( idx >= 0 ) s = s.substring( idx+1 ); - idx = s.indexOf( '.' ); - if ( idx >= 0 ) s = s.substring( 0,idx ); - return s; - } + // *** penalty for turning angles + if ( trip.originNode != null ) + { + // penalty proportional to direction change + double cos = rc.calcCosAngle( trip.originNode.ilon, trip.originNode.ilat, currentNode.ilon, currentNode.ilat, node.ilon, node.ilat ); + int turncost = (int) ( cos * rc.expctxWay.getTurncost() + 0.2 ); // e.g. turncost=90 -> 90 degree = 90m penalty + waycost += turncost; + } + + ScheduledTrip nextTrip = new ScheduledTrip( offsets, link, currentNode, trip ); + + // *** penalty for elevation + short ele2 = node.selev; + short ele1 = trip.selev; + int elefactor = 250000; + if ( ele2 == Short.MIN_VALUE ) + ele2 = ele1; + nextTrip.selev = ele2; + if ( ele1 != Short.MIN_VALUE ) + { + nextTrip.ehbd = trip.ehbd + ( ele1 - ele2 ) * elefactor - distance * rc.downhillcutoff; + nextTrip.ehbu = trip.ehbu + ( ele2 - ele1 ) * elefactor - distance * rc.uphillcutoff; + } + + if ( nextTrip.ehbd > rc.elevationpenaltybuffer ) + { + int excess = nextTrip.ehbd - rc.elevationpenaltybuffer; + int reduce = distance * rc.elevationbufferreduce; + if ( reduce > excess ) + { + reduce = excess; + } + excess = nextTrip.ehbd - rc.elevationmaxbuffer; + if ( reduce < excess ) + { + reduce = excess; + } + nextTrip.ehbd -= reduce; + if ( rc.downhillcostdiv > 0 ) + { + int elevationCost = reduce / rc.downhillcostdiv; + waycost += elevationCost; + } + } + else if ( nextTrip.ehbd < 0 ) + { + nextTrip.ehbd = 0; + } + + if ( nextTrip.ehbu > rc.elevationpenaltybuffer ) + { + int excess = nextTrip.ehbu - rc.elevationpenaltybuffer; + int reduce = distance * rc.elevationbufferreduce; + if ( reduce > excess ) + { + reduce = excess; + } + excess = nextTrip.ehbu - rc.elevationmaxbuffer; + if ( reduce < excess ) + { + reduce = excess; + } + nextTrip.ehbu -= reduce; + if ( rc.uphillcostdiv > 0 ) + { + int elevationCost = reduce / rc.uphillcostdiv; + waycost += elevationCost; + } + } + else if ( nextTrip.ehbu < 0 ) + { + nextTrip.ehbu = 0; + } + + nextTrip.lastcostfactor = costfactor; + nextTrip.cost = trip.cost + (int) ( waycost * rc.additionalcostfactor + 0.5 ); + nextTrip.departure = trip.arrival; + nextTrip.arrival = nextTrip.departure + (long) ( waycost * 3600. / rc.cost1speed ); // 22km/h + addToOpenSet( nextTrip ); + } + else + // connecting link + { + ScheduledTrip nextTrip = new ScheduledTrip( offsets, link, currentNode, trip ); + + long delay = (long) ( rc.buffertime * 1000. ); // 2 min + nextTrip.cost = trip.cost + (int) ( delay * rc.waittimeadjustment * rc.cost1speed / 3600. ); + nextTrip.departure = trip.arrival; + nextTrip.arrival = nextTrip.departure + delay; + + addToOpenSet( nextTrip ); + } + } + + private Iternity compileTrip( ScheduledTrip trip, int offset ) + { + Iternity iternity = new Iternity(); + + OsmTrack track = new OsmTrack(); + ScheduledTrip current = trip; + ScheduledLine lastLine = new ScheduledLine(); + ScheduledLine dummyLine = new ScheduledLine(); + List list = new ArrayList(); + + int distance = 0; + long departure = 0; + + ScheduledTrip itrip = null; + + String profile = extractProfile( rc.localFunction ); + + SimpleDateFormat df = new SimpleDateFormat( "dd.MM HH:mm" ); + // time0 = df.parse(startTime).getTime(); + + + OsmNodeP nextNode = null; + while (current != null) + { + departure = current.departure; + + // System.out.println( "trip=" + current ); + OsmNodeP node = current.getTargetNode(); + OsmPathElement pe = OsmPathElement.create( node.ilon, node.ilat, node.selev, null, false ); + track.addNode( pe ); + + if ( nextNode != null ) + { + distance += node.calcDistance( nextNode ); + } + + boolean isScheduled = current.link instanceof ScheduledLink; + boolean isConnection = current.link.descriptionBitmap == null && !isScheduled; + ScheduledLine line = isScheduled ? ( (ScheduledLink) current.link ).line : isConnection ? dummyLine : null; + + if ( line != lastLine && !isConnection ) + { + itrip = new ScheduledTrip(); + itrip.departure = current.departure; + itrip.arrival = current.arrival; + itrip.originNode = current.originNode; + itrip.link = current.link; + + if ( isScheduled && list.size() > 0 ) + { + list.get( list.size() - 1 ).originNode = current.getTargetNode(); + } + list.add( itrip ); + } + else if ( itrip != null && !isConnection ) + { + itrip.departure = current.departure; + itrip.originNode = current.originNode; + } + lastLine = line; + current = current.origin; + nextNode = node; + } + track.distance = distance; + track.cost = trip.cost; + + for ( int i = list.size() - 1; i >= 0; i-- ) + { + current = list.get( i ); + String lineName = profile; + + boolean isScheduled = current.link instanceof ScheduledLink; + if ( isScheduled ) + { + lineName = ( (ScheduledLink) current.link ).line.name; + } + String stationName = "*position*"; + if ( current.originNode instanceof StationNode ) + { + stationName = ( (StationNode) current.originNode ).name; + } + String nextStationName = "*position*"; + if ( i > 0 && list.get( i - 1 ).originNode instanceof StationNode ) + { + nextStationName = ( (StationNode) list.get( i - 1 ).originNode ).name; + } + if ( i == 0 && current.link.targetNode instanceof StationNode ) + { + nextStationName = ( (StationNode)current.link.targetNode ).name; + } + { + Date d0 = new Date( time0 + 60000L * offset + current.departure ); + Date d1 = new Date( time0 + 60000L * offset + current.arrival ); + if ( iternity.details.size() > 0 ) + iternity.details.add( "" ); + iternity.details.add( "depart: " + df.format( d0 ) + " " + stationName ); + iternity.details.add( " --- " + lineName + " ---" ); + iternity.details.add( "arrive: " + df.format( d1 ) + " " + nextStationName ); + + if ( !iternity.lines.contains( lineName ) ) + { + iternity.lines.add( lineName ); + } + } + } + + iternity.track = track; + iternity.arrivaltime = time0 + 60000L * offset + trip.arrival; + iternity.departtime = time0 + 60000L * offset + departure; + + return iternity; + } + + private String extractProfile( String s ) + { + int idx = s.lastIndexOf( '/' ); + if ( idx >= 0 ) + s = s.substring( idx + 1 ); + idx = s.indexOf( '.' ); + if ( idx >= 0 ) + s = s.substring( 0, idx ); + return s; + } } diff --git a/brouter-mem-router/src/main/java/btools/memrouter/StationNode.java b/brouter-mem-router/src/main/java/btools/memrouter/StationNode.java index a2054b9..a716f9e 100644 --- a/brouter-mem-router/src/main/java/btools/memrouter/StationNode.java +++ b/brouter-mem-router/src/main/java/btools/memrouter/StationNode.java @@ -5,21 +5,52 @@ */ package btools.memrouter; -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.File; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.TreeSet; final class StationNode extends OsmNodeP { + private int instanceserial = 0; + + + private static class NodeOffsets implements OffsetSetHolder + { + private OffsetSet offsets; + + public OffsetSet getOffsetSet() + { + return offsets; + } + + public void setOffsetSet( OffsetSet offsets ) + { + this.offsets = offsets; + } + } + + private NodeOffsets offsets; + + @Override + public OffsetSet filterAndCloseNode( OffsetSet in, boolean closeGate ) + { + if ( offsets == null || instanceserial != currentserial ) + { + if ( closeGate ) + { + instanceserial = currentserial; + offsets = new NodeOffsets(); + offsets.setOffsetSet( in ); + } + return in; + } + return in.filterAndClose( offsets, closeGate ); + } + + String name; + + public String getName() + { + return name; + } + } diff --git a/brouter-mem-router/src/main/java/btools/memrouter/TrainSchedule.java b/brouter-mem-router/src/main/java/btools/memrouter/TrainSchedule.java index 718e9a0..4c5ae25 100644 --- a/brouter-mem-router/src/main/java/btools/memrouter/TrainSchedule.java +++ b/brouter-mem-router/src/main/java/btools/memrouter/TrainSchedule.java @@ -5,142 +5,278 @@ */ package btools.memrouter; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Calendar; +import java.util.Collections; 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.StringTokenizer; - - final class TrainSchedule { - private static class TrainScheduleCron - { - long minutes; - long hours; - long dows; - - boolean isNegative; - - String cronSource; + private static class TrainScheduleCron + { + long minutes; + long hours; + long dows; - TrainScheduleCron( String value ) + TrainScheduleCron( String value ) + { + StringTokenizer tk = new StringTokenizer( value, "_" ); + minutes = parseElement( tk.nextToken() ); + hours = parseElement( tk.nextToken() ); + dows = parseElement( tk.nextToken() ); + } + + private long parseElement( String s ) + { + if ( "*".equals( s ) ) { - StringTokenizer tk = new StringTokenizer( value, "_" ); - minutes = parseElement( tk.nextToken() ); - hours = parseElement( tk.nextToken() ); - dows = parseElement( tk.nextToken() ); - - cronSource = value; + return Long.MAX_VALUE; } + StringTokenizer tk = new StringTokenizer( s, "," ); + long res = 0; + while (tk.hasMoreTokens()) + { + String sub = tk.nextToken(); + int start, end; + int idx = sub.indexOf( '-' ); + if ( idx < 0 ) + { + start = Integer.parseInt( sub ); + end = start; + } + else + { + start = Integer.parseInt( sub.substring( 0, idx ) ); + end = Integer.parseInt( sub.substring( idx + 1 ) ); + } + for ( int i = start; i <= end; i++ ) + { + res |= ( 1L << i ); + } + } + return res; + } + + boolean matches( int minute, int hour, int dow ) + { + return ( ( 1L << minute ) & minutes ) != 0 && ( ( 1L << hour ) & hours ) != 0 && ( ( 1L << dow ) & dows ) != 0; + } + } + + private List cronsPositive; + private List cronsNegative; + private Map> timeTable = new HashMap>(); + + public TrainSchedule( String cronstring ) + { + StringTokenizer tk = new StringTokenizer( cronstring, " " ); + + cronsPositive = new ArrayList(); + cronsNegative = new ArrayList(); + + while (tk.hasMoreTokens()) + { + String prefix = tk.nextToken(); + String value = tk.nextToken(); + if ( "+".equals( prefix ) ) + { + cronsPositive.add( new TrainScheduleCron( value ) ); + } + else if ( "-".equals( prefix ) ) + { + cronsNegative.add( new TrainScheduleCron( value ) ); + } + else + { + // prefix is a calendar id, value a slash-separated time list + List times = new ArrayList(); + StringTokenizer tk3 = new StringTokenizer( value, "/" ); + while( tk3.hasMoreTokens() ) + { + times.add( Integer.valueOf( time2Minute( tk3.nextToken() ) ) ); + } + Collections.sort( times ); + timeTable.put( prefix, times ); + } + } + } + + private static int time2Minute( String s ) + { + StringTokenizer tk = new StringTokenizer( s, ":" ); + int mins = 60 * Integer.parseInt( tk.nextToken() ); + mins += Integer.parseInt( tk.nextToken() ); + return mins; + } + + public int getMinutesToNext( long timeFrom ) + { + if ( timeTable.isEmpty() ) + { + return getMinutesToNextCron( timeFrom ); + } + Calendar cal = Calendar.getInstance(); + cal.setTime( new Date( timeFrom ) ); + int minute = cal.get( Calendar.MINUTE ); + int hour = cal.get( Calendar.HOUR_OF_DAY ); + + int year = cal.get( Calendar.YEAR ); + int month = cal.get( Calendar.MONTH ) + 1; + int day = cal.get( Calendar.DAY_OF_MONTH ); + + String sday = "" + ( year*10000 + month * 100 + day ); + + List alltimes = null; + boolean listIsCopy = false; + for( String calId : timeTable.keySet() ) + { + if ( calendarHasDate( calId, sday ) ) + { + List times = timeTable.get( calId ); + if ( alltimes == null ) + { + alltimes = times; + } + else + { + if ( !listIsCopy ) + { + alltimes = new ArrayList( alltimes ); + listIsCopy = true; + } + alltimes.addAll( times ); + } + } + } + if ( alltimes == null ) return -1; + if ( listIsCopy ) + { + Collections.sort( alltimes ); + } + + int mins = 60*hour + minute; + for( Integer t : alltimes ) + { + if ( t.intValue() >= mins ) + { + return t.intValue() - mins; + } + } + return -1; + } + + private int getMinutesToNextCron( long timeFrom ) + { + + Calendar cal = Calendar.getInstance(); + cal.setTime( new Date( timeFrom ) ); + int minute = cal.get( Calendar.MINUTE ); + int hour = cal.get( Calendar.HOUR_OF_DAY ); + int dow = cal.get( Calendar.DAY_OF_WEEK ); + dow = dow > 1 ? dow - 1 : dow + 6; + + for ( int cnt = 0; cnt < 180; cnt++ ) + { + boolean veto = false; + for ( TrainScheduleCron cron : cronsNegative ) + { + if ( cron.matches( minute, hour, dow ) ) + { + veto = true; + break; + } + } + if ( !veto ) + { + for ( TrainScheduleCron cron : cronsPositive ) + { + if ( cron.matches( minute, hour, dow ) ) + return cnt; + } + } + + if ( ++minute == 60 ) + { + minute = 0; + if ( ++hour == 24 ) + { + hour = 0; + if ( ++dow == 8 ) + { + dow = 1; + } + } + } + } + return -1; + } + + private static Map> calendarMap; + + private static boolean calendarHasDate( String calId, String date ) + { + if ( calendarMap == null ) + { + try + { + readCalendar(); + } + catch (Exception e) + { + throw new RuntimeException( "cannot readcalendar: " + e ); + } + } + Set idSet = calendarMap.get( calId ); + if ( idSet != null ) + { + return idSet.contains( date ); + } + return true; + } + + private static void readCalendar() throws Exception + { +System.out.println( "reading calendar..." ); + calendarMap = new HashMap>(); + + Map uniqueMap = new HashMap(); + + BufferedReader br = new BufferedReader( new InputStreamReader( new FileInputStream( new File( "../calendar_dates.txt" ) ), "UTF-8" ) ); + br.readLine(); // skip header + + for ( ;; ) + { + String line = br.readLine(); + if ( line == null ) break; + StringTokenizer tk = new StringTokenizer( line, "," ); + String calId = tk.nextToken(); + String calDate = tk.nextToken(); - private long parseElement( String s ) - { - if ( "*".equals( s ) ) return Long.MAX_VALUE; - StringTokenizer tk = new StringTokenizer( s, "," ); - long res = 0; - while( tk.hasMoreTokens() ) - { - String sub = tk.nextToken(); - int start, end; - int idx = sub.indexOf( '-' ); - if ( idx < 0 ) - { - start = Integer.parseInt( sub ); - end = start; - } - else - { - start = Integer.parseInt( sub.substring( 0, idx ) ); - end = Integer.parseInt( sub.substring( idx + 1) ); - } - for( int i=start; i <= end ; i++ ) - { - res |= (1L< cronsPositive; - private List cronsNegative; - - public TrainSchedule( String cronstring ) - { - StringTokenizer tk = new StringTokenizer( cronstring, " " ); - - cronsPositive = new ArrayList(); - cronsNegative = new ArrayList(); - - while ( tk.hasMoreTokens() ) - { - String sign = tk.nextToken(); - String value = tk.nextToken(); - TrainScheduleCron cron = new TrainScheduleCron( value ); - if ( "+".equals( sign ) ) - { - cronsPositive.add( cron ); - } - else if ( "-".equals( sign ) ) - { - cronsNegative.add( cron ); - } - else throw new IllegalArgumentException( "invalid cron sign: " + sign ); - } - } - - - - public int getMinutesToNext( long timeFrom ) - { - Calendar cal = Calendar.getInstance(); - cal.setTime( new Date( timeFrom ) ); - int minute = cal.get( Calendar.MINUTE ); - int hour = cal.get( Calendar.HOUR_OF_DAY ); - int dow = cal.get( Calendar.DAY_OF_WEEK ); - dow = dow > 1 ? dow -1 : dow+6; - - for( int cnt=0; cnt < 10080; cnt++ ) - { - boolean veto = false; - for( TrainScheduleCron cron : cronsNegative ) - { - if ( cron.matches( minute, hour, dow ) ) - { - veto = true; - break; - } - } - if ( !veto ) - { - for( TrainScheduleCron cron : cronsPositive ) - { - if ( cron.matches( minute, hour, dow ) ) return cnt; - } - } - - if ( ++minute == 60 ) - { - minute = 0; - if ( ++hour == 24 ) - { - hour = 0; - if ( ++dow == 8 ) - { - dow = 1; - } - } - } - } - return -1; - } + Set idSet = calendarMap.get( calId ); + if ( idSet == null ) + { + idSet = new HashSet(); + calendarMap.put( calId, idSet ); + } + String uniqueDate = uniqueMap.get( calDate ); + if ( uniqueDate == null ) + { + uniqueDate = calDate; + uniqueMap.put( uniqueDate, uniqueDate ); + } + idSet.add( uniqueDate ); + } + br.close(); +System.out.println( "read calendar with " + calendarMap.size() + " ids" ); + } } diff --git a/brouter-mem-router/src/main/java/btools/memrouter/TwinRoutingEngine.java b/brouter-mem-router/src/main/java/btools/memrouter/TwinRoutingEngine.java index bbb8ff9..c5f3139 100644 --- a/brouter-mem-router/src/main/java/btools/memrouter/TwinRoutingEngine.java +++ b/brouter-mem-router/src/main/java/btools/memrouter/TwinRoutingEngine.java @@ -65,7 +65,7 @@ public class TwinRoutingEngine extends RoutingEngine */ OsmLinkP.currentserial++; ScheduledRouter router = new ScheduledRouter( graph, routingContext, this ); - foundTrack = router.findRoute( waypoints.get(0), waypoints.get(1), "17.12.2014-19:00", routingContext.getAlternativeIdx() ); + foundTrack = router.findRoute( waypoints.get(0), waypoints.get(1), routingContext.getAlternativeIdx(-1,10) ); System.out.println( "linksProcessed=" + router.linksProcessed + " linksReProcessed=" + router.linksReProcessed); System.out.println( "skippedChained=" + router.skippedChained + " closedSkippedChained=" + router.closedSkippedChained); @@ -88,7 +88,7 @@ public class TwinRoutingEngine extends RoutingEngine File wayTilesIn = new File( parentDir, "waytiles55"); File[] fahrplanFiles = new File[2]; fahrplanFiles[0] = new File( parentDir, "fahrplan_nahverkehr.txt" ); - fahrplanFiles[1] = new File( parentDir, "fahrplan.txt" ); + fahrplanFiles[1] = new File( parentDir, "fahrplan_dbfern.txt" ); graph = new GraphLoader(); graph.process( nodeTilesIn, wayTilesIn, fahrplanFiles, routingContext.expctxWay ); diff --git a/brouter-mem-router/src/test/java/btools/memrouter/MemrouterTest.java b/brouter-mem-router/src/test/java/btools/memrouter/MemrouterTest.java index 1fc8bea..973adeb 100644 --- a/brouter-mem-router/src/test/java/btools/memrouter/MemrouterTest.java +++ b/brouter-mem-router/src/test/java/btools/memrouter/MemrouterTest.java @@ -1,12 +1,10 @@ package btools.memrouter; -import java.util.Random; -import java.util.HashMap; +import java.io.File; +import java.net.URL; import org.junit.Assert; import org.junit.Test; -import java.net.URL; -import java.io.File; import btools.expressions.BExpressionContextWay; import btools.expressions.BExpressionMetaData; diff --git a/brouter-mem-router/src/test/java/btools/memrouter/OffsetSetTest.java b/brouter-mem-router/src/test/java/btools/memrouter/OffsetSetTest.java new file mode 100644 index 0000000..8b77ff4 --- /dev/null +++ b/brouter-mem-router/src/test/java/btools/memrouter/OffsetSetTest.java @@ -0,0 +1,48 @@ +package btools.memrouter; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +public class OffsetSetTest +{ + @Test + public void offsetSetTest() throws Exception + { + OffsetSet fullset = OffsetSet.fullSet(); + OffsetSet s2 = fullset.emptySet().add( 4 ); + + Assert.assertTrue( "added bit not found", s2.contains( 4 ) ); + Assert.assertTrue( "found false bit", !s2.contains( 3 ) ); + + Assert.assertTrue( "found bit in fullset", fullset.contains( 17 ) ); + + List offsetList = new ArrayList(); + offsetList.add( Integer.valueOf( 4 )); + offsetList.add( Integer.valueOf( 5 )); + offsetList.add( Integer.valueOf( 23 )); + offsetList.add( Integer.valueOf( 50 )); + + OffsetSet s4 = fullset.create( offsetList ); + Assert.assertTrue( "added bit 23 not found", s4.contains( 23 ) ); + Assert.assertTrue( "found false bit 17", !s4.contains( 17 ) ); + + OffsetSet s5 = s2.filter( s4 ); // de-select 4 from s4 + Assert.assertTrue( "added bit 5 not found", s5.contains( 5 ) ); + Assert.assertTrue( "found false bit 4", !s5.contains( 4 ) ); + + OffsetSet s6 = s4.filter( s2 ); // de-select 4,5,23,50 from s2 -> = null + Assert.assertTrue( "expected empty set", s6 == null ); + + OsmLinkP holder = new OsmLinkP(); + holder.setOffsetSet( fullset.emptySet().add( 24 ) ); + + OffsetSet s7 = s4.filterAndClose( holder, true ); +// Assert.assertTrue( "bit 4 too much", !s7.contains( 4 ) ); +// Assert.assertTrue( "bit 5 not found", s7.contains( 5 ) ); +// Assert.assertTrue( "bit 23 not found", s7.contains( 23 ) ); +// Assert.assertTrue( "bit 50 too much", !s7.contains( 50 ) ); + } +} diff --git a/brouter-server/src/main/java/btools/server/RouteServer.java b/brouter-server/src/main/java/btools/server/RouteServer.java index 1d6f7a2..783e008 100644 --- a/brouter-server/src/main/java/btools/server/RouteServer.java +++ b/brouter-server/src/main/java/btools/server/RouteServer.java @@ -58,8 +58,8 @@ public class RouteServer extends Thread BufferedWriter bw = null; try { - br = new BufferedReader( new InputStreamReader( clientSocket.getInputStream() ) ); - bw = new BufferedWriter( new OutputStreamWriter( clientSocket.getOutputStream() ) ); + br = new BufferedReader( new InputStreamReader( clientSocket.getInputStream() , "UTF-8") ); + bw = new BufferedWriter( new OutputStreamWriter( clientSocket.getOutputStream(), "UTF-8" ) ); // we just read the first line String getline = br.readLine();