im-router-update

This commit is contained in:
Arndt 2016-08-05 16:02:13 +02:00
parent cd8082f2b2
commit d277db0bd1
19 changed files with 1506 additions and 903 deletions

View file

@ -286,7 +286,6 @@ public final class OsmTrack
public int ascend; public int ascend;
public int plainAscend; public int plainAscend;
public int cost; public int cost;
public long arrivaltime;
/** /**
* writes the track in gpx-format to a file * writes the track in gpx-format to a file

View file

@ -19,13 +19,11 @@ public final class RoutingContext implements DistanceChecker
{ {
public void setAlternativeIdx( int idx ) public void setAlternativeIdx( int idx )
{ {
if ( idx < 0 ) idx = 0;
if ( idx > 3 ) idx = 3;
alternativeIdx = idx; 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 int alternativeIdx = 0;
public String localFunction; public String localFunction;
@ -66,6 +64,7 @@ public final class RoutingContext implements DistanceChecker
public double waittimeadjustment; public double waittimeadjustment;
public double inittimeadjustment; public double inittimeadjustment;
public double starttimeoffset; public double starttimeoffset;
public boolean transitonly;
public void readGlobalConfig( BExpressionContext expctxGlobal ) public void readGlobalConfig( BExpressionContext expctxGlobal )
{ {
@ -92,6 +91,7 @@ public final class RoutingContext implements DistanceChecker
waittimeadjustment = expctxGlobal.getVariableValue( "waittimeadjustment", 0.9f ); waittimeadjustment = expctxGlobal.getVariableValue( "waittimeadjustment", 0.9f );
inittimeadjustment = expctxGlobal.getVariableValue( "inittimeadjustment", 0.2f ); inittimeadjustment = expctxGlobal.getVariableValue( "inittimeadjustment", 0.2f );
starttimeoffset = expctxGlobal.getVariableValue( "starttimeoffset", 0.f ); starttimeoffset = expctxGlobal.getVariableValue( "starttimeoffset", 0.f );
transitonly = expctxGlobal.getVariableValue( "transitonly", 0.f ) != 0.f;
farTrafficWeight = expctxGlobal.getVariableValue( "farTrafficWeight", 2.f ); farTrafficWeight = expctxGlobal.getVariableValue( "farTrafficWeight", 2.f );
nearTrafficWeight = expctxGlobal.getVariableValue( "nearTrafficWeight", 2.f ); nearTrafficWeight = expctxGlobal.getVariableValue( "nearTrafficWeight", 2.f );

View file

@ -164,7 +164,7 @@ public class RoutingEngine extends Thread
} }
else else
{ {
if ( i == routingContext.getAlternativeIdx() ) if ( i == routingContext.getAlternativeIdx(0,3) )
{ {
if ( "CSV".equals( System.getProperty( "reportFormat" ) ) ) if ( "CSV".equals( System.getProperty( "reportFormat" ) ) )
{ {

View file

@ -1,18 +1,6 @@
package btools.expressions; package btools.expressions;
import java.io.BufferedReader;
import java.io.File; 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; import java.util.Random;
public final class ProfileComparator public final class ProfileComparator

View file

@ -3,8 +3,8 @@ package btools.memrouter;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import btools.expressions.BExpressionContext;
import btools.expressions.BExpressionContextWay; import btools.expressions.BExpressionContextWay;
import btools.expressions.BExpressionMetaData; import btools.expressions.BExpressionMetaData;
import btools.mapaccess.OsmPos; import btools.mapaccess.OsmPos;
@ -28,6 +28,8 @@ public class GraphLoader extends MapCreatorBase
{ {
private CompactLongMap<OsmNodeP> nodesMap; private CompactLongMap<OsmNodeP> nodesMap;
private Map<String, StationNode> stationMap;
private BExpressionContextWay expctxWay; private BExpressionContextWay expctxWay;
private ByteArrayUnifier abUnifier; private ByteArrayUnifier abUnifier;
@ -102,7 +104,7 @@ public class GraphLoader extends MapCreatorBase
System.out.println( "nodesLoaded=" + nodesLoaded + " linksLoaded=" + linksLoaded ); System.out.println( "nodesLoaded=" + nodesLoaded + " linksLoaded=" + linksLoaded );
// now load the train-schedules // now load the train-schedules
ScheduleParser.parseTrainTable( fahrplanFiles, this, expctxWay ); stationMap = ScheduleParser.parseTrainTable( fahrplanFiles, this, expctxWay );
System.gc(); System.gc();
long mem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); long mem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
@ -110,9 +112,12 @@ 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 if ( transitonly )
{
return matchStationForPosition( pos );
}
int ilon = pos.getILon(); int ilon = pos.getILon();
int ilat = pos.getILat(); int ilat = pos.getILat();
@ -128,6 +133,22 @@ public class GraphLoader extends MapCreatorBase
for( OsmNodeP node : nodes ) 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 ); int dist = pos.calcDistance( node );
if ( dist < mindist ) if ( dist < mindist )
{ {
@ -141,6 +162,36 @@ public class GraphLoader extends MapCreatorBase
return bestmatch; 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 ) private boolean hasRoutableLinks( OsmNodeP node, BExpressionContextWay wayCtx )
{ {
for( OsmLinkP link = node.getFirstLink(); link != null; link = link.getNext( node ) ) for( OsmLinkP link = node.getFirstLink(); link != null; link = link.getNext( node ) )
@ -183,10 +234,11 @@ public class GraphLoader extends MapCreatorBase
} }
@Override @Override
public void wayFileStart( File wayfile ) throws Exception public boolean wayFileStart( File wayfile ) throws Exception
{ {
currentTile = tileForFilename( wayfile.getName() ); currentTile = tileForFilename( wayfile.getName() );
System.out.println( "ways currentTile=" + currentTile ); System.out.println( "ways currentTile=" + currentTile );
return true;
} }
@Override @Override

View file

@ -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<Iternity>
{
OsmTrack track;
OffsetSet offsets;
List<String> details = new ArrayList<String>();
List<String> lines = new ArrayList<String>();
long departtime;
long arrivaltime;
@Override
public int compareTo( Iternity it )
{
return arrivaltime == it.arrivaltime ? 0 : ( arrivaltime < it.arrivaltime ? -1 : 1 );
}
void appendSummary( List<String> 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() );
}
}
}

View file

@ -5,141 +5,185 @@
*/ */
package btools.memrouter; package btools.memrouter;
import java.util.BitSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.SortedSet;
public class OffsetSet public class OffsetSet
{ {
private static Map<Long,OffsetSet> existingSets = new HashMap<Long,OffsetSet>(); private Map<BitSet, OffsetSet> existingSets = new HashMap<BitSet, OffsetSet>();
private static OffsetSet empty = new OffsetSet( 0L );
private static OffsetSet full = new OffsetSet( -1L );
protected long mask; private static final int size = 185;
private static int instancecount = 0; protected BitSet mask;
public static OffsetSet emptySet() public OffsetSet emptySet()
{ {
return empty; return new OffsetSet( new BitSet( size ), existingSets );
} }
public static OffsetSet fullSet() public static OffsetSet fullSet()
{ {
return full; BitSet allbits = new BitSet( size );
allbits.set( 0, size );
return new OffsetSet( allbits, new HashMap<BitSet, OffsetSet>() );
} }
private OffsetSet( long m ) private OffsetSet( BitSet m, Map<BitSet, OffsetSet> knownSets )
{ {
existingSets = knownSets;
existingSets.put( m , this );
mask = m; mask = m;
} }
private static OffsetSet create( long m, OffsetSet template ) private OffsetSet create( BitSet m )
{ {
if ( m == 0L ) if ( m.isEmpty() )
{ {
return null; return null;
} }
if ( m == template.mask ) if ( m.equals( mask ) )
{ {
return template; return this;
} }
Long mm = Long.valueOf( m ); OffsetSet set = existingSets.get( m );
OffsetSet set = existingSets.get( mm );
if ( set == null ) if ( set == null )
{ {
set = new OffsetSet( m ); set = new OffsetSet( m, existingSets );
existingSets.put( mm, set ); // System.out.println( "created set: " + set + " instancecount=" + existingSets.size() );
instancecount++;
System.out.println( "created set: " + set + " instancecount=" + instancecount );
} }
return set; return set;
} }
public static OffsetSet create( List<Integer> offsets, OffsetSet template )
public OffsetSet create( List<Integer> offsets )
{ {
long m = 0L; BitSet m = new BitSet( size );
for( Integer offset : offsets ) for ( Integer offset : offsets )
{ {
int i = offset.intValue(); int i = offset.intValue();
if ( i >= 0 && i < 64 ) if ( i >= 0 && i < size )
{ {
m |= ( 1L << i ); m.set( i );
} }
} }
return create( m, template ); return create( m );
}
public OffsetSet filterWithSet( SortedSet<Integer> 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() public int size()
{ {
return 64; return size;
} }
public boolean contains( int offset ) public boolean contains( int offset )
{ {
return ( ( 1L << offset ) & mask ) != 0L; return mask.get( offset );
} }
public OffsetSet add( int 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 ) 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 ) public OffsetSet filter( OffsetSet in )
{ {
long fmask = in.mask; BitSet fmask = (BitSet)in.mask.clone();
fmask = fmask ^ ( fmask & mask ); fmask.andNot( mask );
return create( fmask, in ); return create( fmask );
} }
public static OffsetSet filterAndClose( OffsetSet in, OffsetSetHolder gateHolder, int timeDiff ) public OffsetSet ensureMaxOffset( int max )
{
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(); OffsetSet gate = gateHolder.getOffsetSet();
long gmask = gate.mask; BitSet gmask = (BitSet)gate.mask.clone();
long fmask = in.mask; BitSet fmask = (BitSet)mask.clone();
// delete the high offsets with offset + timeDiff >= maxoffset fmask.andNot( gmask );
fmask = timeDiff > 31 ? 0L : ( fmask << timeDiff ) >> timeDiff;
fmask = fmask ^ ( fmask & gmask ); gmask.or( fmask );
gmask |= fmask; if ( closeGate )
gateHolder.setOffsetSet( create( gmask, gate ) ); // modify the gate
if ( timeDiff > 0 )
{ {
fmask = fmask ^ ( fmask & (gmask >> timeDiff) ); gateHolder.setOffsetSet( create( gmask ) ); // modify the gate
} }
return create( fmask, in ); 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 @Override
public String toString() public String toString()
{ {
if ( mask == -1L ) return "*"; return mask.toString();
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();
} }
} }

View file

@ -5,12 +5,11 @@
*/ */
package btools.memrouter; package btools.memrouter;
public class OsmLinkP implements OffsetSetHolder public class OsmLinkP implements OffsetSetHolder
{ {
/** /**
* The description bitmap is mainly the way description * The description bitmap is mainly the way description used to calculate the
* used to calculate the costfactor * costfactor
*/ */
public byte[] descriptionBitmap; public byte[] descriptionBitmap;
@ -23,11 +22,11 @@ public class OsmLinkP implements OffsetSetHolder
protected OsmLinkP previous; protected OsmLinkP previous;
protected OsmLinkP next; 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 int instanceserial = 0;
private OffsetSet offsets; private OffsetSet offsets;
private int time;
public boolean isConnection() public boolean isConnection()
{ {
@ -64,19 +63,21 @@ public class OsmLinkP implements OffsetSetHolder
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() ) if ( offsets == null || isVirgin() )
{ {
time = minutesArrival; initLink();
instanceserial = currentserial;
offsets = in; offsets = in;
return 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 * Set the relevant next-pointer for the given source

View file

@ -146,5 +146,13 @@ public class OsmNodeP extends OsmLinkP implements Comparable<OsmNodeP>, OsmPos
return 0; return 0;
} }
public OffsetSet filterAndCloseNode( OffsetSet in, boolean modifyGate )
{
return in; // do nothing (StationNode overrides)
}
public String getName()
{
return "<waynode>";
}
} }

View file

@ -7,39 +7,42 @@ package btools.memrouter;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileReader; import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import btools.expressions.BExpressionContextWay; import btools.expressions.BExpressionContextWay;
final class ScheduleParser final class ScheduleParser
{ {
public static void parseTrainTable( File[] files, GraphLoader graph, BExpressionContextWay expctxWay ) public static Map<String, StationNode> parseTrainTable( File[] files, GraphLoader graph, BExpressionContextWay expctxWay )
{
try
{ {
ScheduledLine currentLine = null; ScheduledLine currentLine = null;
StationNode lastStationInLine = null; StationNode lastStationInLine = null;
boolean readingLocations = false; boolean readingLocations = false;
Map<String,StationNode> stationMap = new HashMap<String,StationNode>(); Map<String, StationNode> stationMap = new HashMap<String, StationNode>();
for ( File file : files )
for( File file : files )
{ {
BufferedReader br = new BufferedReader( new FileReader( file ) ); BufferedReader br = null;
for(;;) try
{
br = new BufferedReader( new InputStreamReader( new FileInputStream( file ) , "ISO-8859-1" ) );
for ( ;; )
{ {
String line = br.readLine(); String line = br.readLine();
if ( line == null ) break; if ( line == null )
break;
line = line.trim(); line = line.trim();
if ( line.length() == 0 ) continue; if ( line.length() == 0 )
continue;
if ( line.startsWith( "#" ) ) continue; if ( line.startsWith( "#" ) )
continue;
if ( line.startsWith( "-- locations" ) ) if ( line.startsWith( "-- locations" ) )
{ {
@ -50,7 +53,7 @@ final class ScheduleParser
{ {
readingLocations = false; readingLocations = false;
currentLine = new ScheduledLine(); currentLine = new ScheduledLine();
currentLine.name = line.substring("-- trainline".length() ).trim(); currentLine.name = line.substring( "-- trainline".length() ).trim();
lastStationInLine = null; lastStationInLine = null;
continue; continue;
} }
@ -59,7 +62,7 @@ final class ScheduleParser
StationNode station = new StationNode(); StationNode station = new StationNode();
// Eschborn 50.14323,8.56112 // Eschborn 50.14323,8.56112
StringTokenizer tk = new StringTokenizer( line, " " ); StringTokenizer tk = new StringTokenizer( line, " \t" );
station.name = tk.nextToken(); station.name = tk.nextToken();
if ( stationMap.containsKey( station.name ) ) if ( stationMap.containsKey( station.name ) )
@ -72,15 +75,15 @@ final class ScheduleParser
String loc = null; String loc = null;
int elev = 0; int elev = 0;
int nconnections = 0; int nconnections = 0;
while( tk.hasMoreTokens() || locIdx == 1 ) while (tk.hasMoreTokens() || locIdx == 1)
{ {
if ( tk.hasMoreTokens() ) if ( tk.hasMoreTokens() )
{ {
loc = tk.nextToken(); loc = tk.nextToken();
} }
StringTokenizer tloc = new StringTokenizer( loc, "," ); StringTokenizer tloc = new StringTokenizer( loc, "," );
int ilat = (int)( ( Double.parseDouble( tloc.nextToken() ) + 90. ) *1000000. + 0.5); int ilat = (int) ( ( Double.parseDouble( tloc.nextToken() ) + 90. ) * 1000000. + 0.5 );
int ilon = (int)( ( Double.parseDouble( tloc.nextToken() ) + 180. ) *1000000. + 0.5); int ilon = (int) ( ( Double.parseDouble( tloc.nextToken() ) + 180. ) * 1000000. + 0.5 );
if ( locIdx == 0 ) if ( locIdx == 0 )
{ {
station.ilat = ilat; station.ilat = ilat;
@ -92,7 +95,7 @@ final class ScheduleParser
pos.ilat = ilat; pos.ilat = ilat;
pos.ilon = ilon; pos.ilon = ilon;
OsmNodeP node = graph.matchNodeForPosition( pos,expctxWay ); OsmNodeP node = graph.matchNodeForPosition( pos, expctxWay, false );
if ( node != null ) if ( node != null )
{ {
elev += node.selev; elev += node.selev;
@ -112,7 +115,7 @@ final class ScheduleParser
} }
if ( nconnections > 0 ) if ( nconnections > 0 )
{ {
station.selev = (short)(elev / nconnections); station.selev = (short) ( elev / nconnections );
} }
stationMap.put( station.name, station ); stationMap.put( station.name, station );
} }
@ -121,6 +124,10 @@ final class ScheduleParser
int idx = line.indexOf( ' ' ); int idx = line.indexOf( ' ' );
String name = line.substring( 0, idx ); String name = line.substring( 0, idx );
StationNode nextStationInLine = stationMap.get( name ); StationNode nextStationInLine = stationMap.get( name );
if ( nextStationInLine == null )
{
throw new IllegalArgumentException( "unknown station: " + name );
}
String value = line.substring( idx ).trim(); String value = line.substring( idx ).trim();
int offsetMinute = 0; int offsetMinute = 0;
if ( lastStationInLine == null ) if ( lastStationInLine == null )
@ -129,14 +136,15 @@ final class ScheduleParser
} }
else else
{ {
if ( value.startsWith( "+") ) value = value.substring( 1 ); if ( value.startsWith( "+" ) )
value = value.substring( 1 );
offsetMinute = Integer.parseInt( value ); offsetMinute = Integer.parseInt( value );
ScheduledLink link = new ScheduledLink( lastStationInLine, nextStationInLine ); ScheduledLink link = new ScheduledLink( lastStationInLine, nextStationInLine );
link.line = currentLine; link.line = currentLine;
link.indexInLine = currentLine.offsetMinutes.size()-1; link.indexInLine = currentLine.offsetMinutes.size() - 1;
System.out.println( "adding: " + link ); // System.out.println( "adding: " + link );
lastStationInLine.addLink( link ); lastStationInLine.addLink( link );
} }
currentLine.offsetMinutes.add( Integer.valueOf( offsetMinute ) ); currentLine.offsetMinutes.add( Integer.valueOf( offsetMinute ) );
@ -144,13 +152,24 @@ System.out.println( "adding: " + link );
lastStationInLine = nextStationInLine; lastStationInLine = nextStationInLine;
} }
} }
br.close();
System.out.println( "read " + stationMap.size() + " stations" ); System.out.println( "read " + stationMap.size() + " stations" );
} }
} catch (Exception e)
catch( Exception e )
{ {
throw new RuntimeException( e ); throw new RuntimeException( e );
} }
finally
{
if ( br != null )
{
try
{
br.close();
}
catch (Exception e) { /* ignore */ }
}
}
}
return stationMap;
} }
} }

View file

@ -11,73 +11,75 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
final class ScheduledLine final class ScheduledLine
{ {
String name; String name;
List<Integer> offsetMinutes = new ArrayList<Integer>(); List<Integer> offsetMinutes = new ArrayList<Integer>();
TrainSchedule schedule; TrainSchedule schedule;
/** /**
* get a list of departures relative to the start-time plus * get a list of departures relative to the start-time plus the individual
* the individual offsets according to the offset mask * offsets according to the offset mask
* *
* departures with the same wait-time are aggregated in one * departures with the same wait-time are aggregated in one result element
* result element with multiple 1-bits in the offset mask * with multiple 1-bits in the offset mask
* *
* departures with different wait-times are returned as separate items * departures with different wait-times are returned as separate items
* *
* @param id the value to add to this set. * @param id
* the value to add to this set.
* @return true if "id" already contained in this set. * @return true if "id" already contained in this set.
*/ */
public List<ScheduledDeparture> getScheduledDepartures( int idx, long timeFrom, OffsetSet offsets ) public List<ScheduledDeparture> getScheduledDepartures( int idx, long timeFrom, OffsetSet offsets )
{ {
List<ScheduledDeparture> result = new ArrayList<ScheduledDeparture>(); List<ScheduledDeparture> result = new ArrayList<ScheduledDeparture>();
long minutesFrom = (timeFrom + 59999L) / 60000L; long minutesFrom = ( timeFrom + 59999L ) / 60000L;
long timeFromCorrection = minutesFrom * 60000L - timeFrom; long timeFromCorrection = minutesFrom * 60000L - timeFrom;
if ( idx < 0 || idx >= offsetMinutes.size() -1 ) return result; if ( idx < 0 || idx >= offsetMinutes.size() - 1 )
return result;
int offsetStart = offsetMinutes.get(idx).intValue(); int offsetStart = offsetMinutes.get( idx ).intValue();
int offsetEnd = offsetMinutes.get(idx+1).intValue(); int offsetEnd = offsetMinutes.get( idx + 1 ).intValue();
Map<Integer, List<Integer>> waitOffsets = getDepartures( offsetStart, timeFrom + timeFromCorrection, offsets );
Map<Integer,List<Integer>> waitOffsets = getDepartures( offsetStart, timeFrom + timeFromCorrection, offsets ); for ( Map.Entry<Integer, List<Integer>> e : waitOffsets.entrySet() )
for( Map.Entry<Integer,List<Integer>> e : waitOffsets.entrySet() )
{ {
ScheduledDeparture depart = new ScheduledDeparture( ); ScheduledDeparture depart = new ScheduledDeparture();
depart.waitTime = e.getKey().intValue() * 60000L + timeFromCorrection; depart.waitTime = e.getKey().intValue() * 60000L + timeFromCorrection;
depart.offsets = OffsetSet.create( e.getValue(), offsets ); depart.offsets = offsets.create( e.getValue() );
depart.rideTime = (offsetEnd-offsetStart)*60000L; depart.rideTime = ( offsetEnd - offsetStart ) * 60000L;
result.add( depart ); result.add( depart );
} }
return result; return result;
} }
private Map<Integer,List<Integer>> getDepartures( int offsetStart, long timeFrom, OffsetSet offsets ) private Map<Integer, List<Integer>> getDepartures( int offsetStart, long timeFrom, OffsetSet offsets )
{ {
Map<Integer,List<Integer>> waitOffsets = new HashMap<Integer,List<Integer>>(); Map<Integer, List<Integer>> waitOffsets = new HashMap<Integer, List<Integer>>();
int size = offsets.size(); int size = offsets.size();
for(int offset = 0;;) for ( int offset = 0;; )
{ {
// skip to next offset bit // skip to next offset bit
while( offset < size && !offsets.contains( offset ) ) while (offset < size && !offsets.contains( offset ))
{ {
offset++; offset++;
} }
if ( offset >= size ) return waitOffsets; if ( offset >= size )
return waitOffsets;
int toNext = schedule.getMinutesToNext( timeFrom + 60000L*(offset - offsetStart ) ); int toNext = schedule.getMinutesToNext( timeFrom + 60000L * ( offset - offsetStart ) );
if ( toNext < 0 ) return waitOffsets;
if ( toNext < 0 )
return waitOffsets;
int departOffset = offset + toNext; int departOffset = offset + toNext;
// whats the closest offset within the next toNext minutes // whats the closest offset within the next toNext minutes
int lastOffset = offset; int lastOffset = offset;
while( toNext-- >= 0 && offset < size ) while (toNext-- >= 0 && offset < size)
{ {
if ( offsets.contains( offset ) ) if ( offsets.contains( offset ) )
{ {
@ -86,7 +88,8 @@ final class ScheduledLine
offset++; offset++;
} }
if ( lastOffset == size-1 ) return waitOffsets; // todo? // if ( lastOffset == size - 1 )
// return waitOffsets; // todo?
int waitTime = departOffset - lastOffset; int waitTime = departOffset - lastOffset;

View file

@ -5,6 +5,9 @@
*/ */
package btools.memrouter; package btools.memrouter;
import java.util.SortedSet;
import java.util.TreeSet;
public class ScheduledLink extends OsmLinkP public class ScheduledLink extends OsmLinkP
{ {
@ -30,4 +33,26 @@ public class ScheduledLink extends OsmLinkP
{ {
return "ScheduledLink: line=" + line.name + " indexInLine=" + indexInLine; return "ScheduledLink: line=" + line.name + " indexInLine=" + indexInLine;
} }
private SortedSet<Integer> usedTimes;
@Override
protected void initLink()
{
super.initLink();
usedTimes = new TreeSet<Integer>();
}
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;
}
} }

View file

@ -5,7 +5,9 @@
*/ */
package btools.memrouter; package btools.memrouter;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -16,13 +18,10 @@ import btools.router.RoutingContext;
import btools.router.RoutingEngine; import btools.router.RoutingEngine;
import btools.util.SortedHeap; import btools.util.SortedHeap;
final class ScheduledRouter final class ScheduledRouter
{ {
private GraphLoader graph; private GraphLoader graph;
private int solutionCount = 0;
public long linksProcessed = 0L; public long linksProcessed = 0L;
public long linksReProcessed = 0L; public long linksReProcessed = 0L;
public long closedSkippedChained = 0L; public long closedSkippedChained = 0L;
@ -44,29 +43,96 @@ final class ScheduledRouter
this.re = re; this.re = re;
} }
private static List<Iternity> trips = new ArrayList<Iternity>();
private static long oldChecksum = 0;
public OsmTrack findRoute( OsmPos startPos, OsmPos endPos, String startTime, int alternativeIdx ) throws Exception private String startEndText()
{ {
OsmTrack track = null; return (start == null ? "unmatched" : start.getName() ) + "->" + (end == null ? "unmatched" : end.getName() );
}
start = graph.matchNodeForPosition( startPos, rc.expctxWay ); public OsmTrack findRoute( OsmPos startPos, OsmPos endPos, int alternativeIdx ) throws Exception
if ( start == null ) throw new IllegalArgumentException( "unmatched start: " + startPos ); {
end = graph.matchNodeForPosition( endPos, rc.expctxWay ); if ( alternativeIdx == -1 ) // lowest cost result
if ( end == null ) throw new IllegalArgumentException( "unmatched end: " + endPos ); {
List<Iternity> 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;
}
// SimpleDateFormat df = new SimpleDateFormat( "dd.MM.yyyy-HH:mm" ); // check for identical params
// time0 = df.parse(startTime).getTime(); long[] nogocheck = rc.getNogoChecksums();
time0 = System.currentTimeMillis() + (long)(rc.starttimeoffset * 60000L );
long minutes0 = (time0 + 59999L) / 60000L;
time0 = minutes0 * 60000L;
OffsetSet finishedOffsets = OffsetSet.emptySet(); 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<String> details = new ArrayList<String>();
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<Iternity> _findRoute( OsmPos startPos, OsmPos endPos, boolean fastStop ) throws Exception
{
List<Iternity> iternities = new ArrayList<Iternity>();
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 ); OsmLinkP startLink = new OsmLinkP( null, start );
ScheduledTrip startTrip = new ScheduledTrip( OffsetSet.fullSet(), startLink, null, null ); ScheduledTrip startTrip = new ScheduledTrip( OffsetSet.fullSet(), startLink, null, null );
openSet.add( 0, startTrip ); openSet.add( 0, startTrip );
for(;;) for ( ;; )
{ {
if ( re.isTerminated() ) if ( re.isTerminated() )
{ {
@ -74,7 +140,7 @@ time0 = minutes0 * 60000L;
} }
if ( linksProcessed + linksReProcessed > 5000000 ) if ( linksProcessed + linksReProcessed > 5000000 )
{ {
throw new RuntimeException( "5 Million links limit reached" ); break;
} }
// get cheapest trip from heap // get cheapest trip from heap
@ -100,61 +166,144 @@ time0 = minutes0 * 60000L;
linksReProcessed++; 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 // check global closure
OffsetSet offsets = finishedOffsets.filter( trip.offsets ); offsets = finishedOffsets.filter( offsets );
if ( offsets == null ) continue; 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: // check local closure for links:
offsets = currentLink.filterAndClose( offsets, trip.arrival, currentLink instanceof ScheduledLink ); offsets = currentLink.filterAndClose( offsets, trip.arrival );
if ( offsets == null ) continue; if ( offsets == null )
continue;
// check for arrival // check for arrival
if ( currentNode == end ) if ( currentNode == end )
{ {
for( int offset = 0; offset<trip.offsets.size(); offset++ ) 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 ) ) if ( trip.offsets.contains( offset ) )
{ {
track = compileTrip( trip, offset ); iternity = compileTrip( trip, offset );
System.out.println( "---- begin route ------ (cost " + track.cost + ")" ); iternity.offsets = toffsets;
for( String s : track.iternity ) System.out.println( s ); System.out.println( "---- begin route ------ (cost " + iternity.track.cost + ")" );
System.out.println( "---- end route ------" ); for ( String s : iternity.details )
System.out.println( s );
System.out.println( "---- end route ------ (arrival " + new Date( iternity.arrivaltime ) + ")" );
break; // + plus more offsets.. break; // + plus more offsets..
} }
} }
finishedOffsets = finishedOffsets.add( offsets ); finishedOffsets = finishedOffsets.add( offsets );
if ( solutionCount++ >= alternativeIdx ) return track; if ( iternity != null )
}
for( OsmLinkP link = currentNode.getFirstLink(); link != null; link = link.getNext( currentNode ) )
{ {
addNextTripsForLink(trip, currentNode, currentLink, link, offsets, 0 ); // 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 !**** ");
} }
} }
return track; 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<Iternity> 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 ) private void addToOpenSet( ScheduledTrip nextTrip )
{ {
int distance = nextTrip.getTargetNode().calcDistance( end ); int distance = nextTrip.getTargetNode().calcDistance( end );
nextTrip.adjustedCost = nextTrip.cost + (int)(distance * rc.pass1coefficient + 0.5); nextTrip.adjustedCost = nextTrip.cost + (int) ( distance * rc.pass1coefficient + 0.5 );
openSet.add( nextTrip.adjustedCost, nextTrip ); openSet.add( nextTrip.adjustedCost, nextTrip );
} }
private void addNextTripsForLink( ScheduledTrip trip, OsmNodeP currentNode, OsmLinkP currentLink, OsmLinkP link, OffsetSet offsets, int level ) private void addNextTripsForLink( ScheduledTrip trip, OsmNodeP currentNode, OsmLinkP currentLink, OsmLinkP link, OffsetSet offsets, int level )
{ {
if ( link == currentLink ) OsmNodeP node = link.getTarget( currentNode );
{
return; // just reverse, ignore
}
OsmNodeP node = link.getTarget(currentNode);
if ( node == null ) if ( node == null )
{ {
System.out.println( "ups2: " + link ); System.out.println( "ups2: " + link );
return; return;
} }
if ( node == trip.originNode )
{
link.filterAndClose( offsets, -1 ); // invalidate reverse link
return;
}
// calc distance and check nogos // calc distance and check nogos
rc.nogomatch = false; rc.nogomatch = false;
int distance = rc.calcDistance( currentNode.ilon, currentNode.ilat, node.ilon, node.ilat ); int distance = rc.calcDistance( currentNode.ilon, currentNode.ilat, node.ilon, node.ilat );
@ -165,39 +314,40 @@ time0 = minutes0 * 60000L;
if ( link instanceof ScheduledLink ) if ( link instanceof ScheduledLink )
{ {
// System.out.println( "next trip for link: " + link + " at offset " + offsets ); // System.out.println( "next trip for link: " + link + " at offset " +
// offsets );
ScheduledLink slink = (ScheduledLink)link; ScheduledLink slink = (ScheduledLink) link;
ScheduledLine line = slink.line; ScheduledLine line = slink.line;
// line change delay // line change delay
long delay = 0L; long delay = 0L;
if ( currentLink instanceof ScheduledLink ) if ( currentLink instanceof ScheduledLink )
{ {
delay = ((ScheduledLink)currentLink).line == line ? 0L : (long)(rc.changetime * 1000.); // 3 minutes delay = ( (ScheduledLink) currentLink ).line == line ? 0L : (long) ( rc.changetime * 1000. ); // 3 minutes
} }
long changePenalty = delay > 0 ? 60000L : 0L; long changePenalty = delay > 0 ? 60000L : 0L;
List<ScheduledDeparture> nextDepartures = line.getScheduledDepartures( slink.indexInLine, time0 + trip.arrival + delay, offsets ); List<ScheduledDeparture> nextDepartures = line.getScheduledDepartures( slink.indexInLine, time0 + trip.arrival + delay, offsets );
for( ScheduledDeparture nextDeparture : nextDepartures ) for ( ScheduledDeparture nextDeparture : nextDepartures )
{ {
ScheduledTrip nextTrip = new ScheduledTrip( nextDeparture.offsets, link, currentNode, trip ); ScheduledTrip nextTrip = new ScheduledTrip( nextDeparture.offsets, link, currentNode, trip );
long waitTime = nextDeparture.waitTime + delay; long waitTime = nextDeparture.waitTime + delay;
long rideTime = nextDeparture.rideTime; long rideTime = nextDeparture.rideTime;
nextTrip.cost = trip.cost + (int)( ( rideTime + changePenalty + waitTime*rc.waittimeadjustment ) * rc.cost1speed / 3600. ); // 160ms / meter = 22km/h nextTrip.cost = trip.cost + (int) ( ( rideTime + changePenalty + waitTime * rc.waittimeadjustment ) * rc.cost1speed / 3600. ); // 22km/h
nextTrip.departure = trip.arrival + waitTime; nextTrip.departure = trip.arrival + waitTime;
nextTrip.arrival = nextTrip.departure + rideTime; nextTrip.arrival = nextTrip.departure + rideTime;
addToOpenSet( nextTrip ); addToOpenSet( nextTrip );
// System.out.println( "found: " + nextTrip ); // System.out.println( "found: " + nextTrip );
} }
} }
else if ( link.isWayLink() ) else if ( link.isWayLink() )
{ {
// get costfactor // get costfactor
rc.expctxWay.evaluate( link.isReverse(currentNode), link.descriptionBitmap, null ); rc.expctxWay.evaluate( link.isReverse( currentNode ), link.descriptionBitmap, null );
// *** penalty for distance // *** penalty for distance
float costfactor = rc.expctxWay.getCostfactor(); float costfactor = rc.expctxWay.getCostfactor();
@ -205,25 +355,24 @@ time0 = minutes0 * 60000L;
{ {
return; return;
} }
int waycost = (int)(distance * costfactor + 0.5f); int waycost = (int) ( distance * costfactor + 0.5f );
// *** add initial cost if factor changed // *** add initial cost if factor changed
float costdiff = costfactor - trip.lastcostfactor; float costdiff = costfactor - trip.lastcostfactor;
if ( costdiff > 0.0005 || costdiff < -0.0005 ) if ( costdiff > 0.0005 || costdiff < -0.0005 )
{ {
waycost += (int)rc.expctxWay.getInitialcost(); waycost += (int) rc.expctxWay.getInitialcost();
} }
if ( node.getNodeDecsription() != null ) if ( node.getNodeDecsription() != null )
{ {
rc.expctxNode.evaluate( rc.expctxWay.getNodeAccessGranted() != 0. , node.getNodeDecsription(), null ); rc.expctxNode.evaluate( rc.expctxWay.getNodeAccessGranted() != 0., node.getNodeDecsription(), null );
float initialcost = rc.expctxNode.getInitialcost(); float initialcost = rc.expctxNode.getInitialcost();
if ( initialcost >= 1000000. ) if ( initialcost >= 1000000. )
{ {
return; return;
} }
waycost += (int)initialcost; waycost += (int) initialcost;
} }
// *** penalty for turning angles // *** penalty for turning angles
@ -231,7 +380,7 @@ time0 = minutes0 * 60000L;
{ {
// penalty proportional to direction change // penalty proportional to direction change
double cos = rc.calcCosAngle( trip.originNode.ilon, trip.originNode.ilat, currentNode.ilon, currentNode.ilat, node.ilon, node.ilat ); 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 int turncost = (int) ( cos * rc.expctxWay.getTurncost() + 0.2 ); // e.g. turncost=90 -> 90 degree = 90m penalty
waycost += turncost; waycost += turncost;
} }
@ -241,12 +390,13 @@ time0 = minutes0 * 60000L;
short ele2 = node.selev; short ele2 = node.selev;
short ele1 = trip.selev; short ele1 = trip.selev;
int elefactor = 250000; int elefactor = 250000;
if ( ele2 == Short.MIN_VALUE ) ele2 = ele1; if ( ele2 == Short.MIN_VALUE )
ele2 = ele1;
nextTrip.selev = ele2; nextTrip.selev = ele2;
if ( ele1 != Short.MIN_VALUE ) if ( ele1 != Short.MIN_VALUE )
{ {
nextTrip.ehbd = trip.ehbd + (ele1 - ele2)*elefactor - distance * rc.downhillcutoff; nextTrip.ehbd = trip.ehbd + ( ele1 - ele2 ) * elefactor - distance * rc.downhillcutoff;
nextTrip.ehbu = trip.ehbu + (ele2 - ele1)*elefactor - distance * rc.uphillcutoff; nextTrip.ehbu = trip.ehbu + ( ele2 - ele1 ) * elefactor - distance * rc.uphillcutoff;
} }
if ( nextTrip.ehbd > rc.elevationpenaltybuffer ) if ( nextTrip.ehbd > rc.elevationpenaltybuffer )
@ -265,7 +415,7 @@ time0 = minutes0 * 60000L;
nextTrip.ehbd -= reduce; nextTrip.ehbd -= reduce;
if ( rc.downhillcostdiv > 0 ) if ( rc.downhillcostdiv > 0 )
{ {
int elevationCost = reduce/rc.downhillcostdiv; int elevationCost = reduce / rc.downhillcostdiv;
waycost += elevationCost; waycost += elevationCost;
} }
} }
@ -290,7 +440,7 @@ time0 = minutes0 * 60000L;
nextTrip.ehbu -= reduce; nextTrip.ehbu -= reduce;
if ( rc.uphillcostdiv > 0 ) if ( rc.uphillcostdiv > 0 )
{ {
int elevationCost = reduce/rc.uphillcostdiv; int elevationCost = reduce / rc.uphillcostdiv;
waycost += elevationCost; waycost += elevationCost;
} }
} }
@ -300,18 +450,18 @@ time0 = minutes0 * 60000L;
} }
nextTrip.lastcostfactor = costfactor; nextTrip.lastcostfactor = costfactor;
nextTrip.cost = trip.cost + (int)(waycost*rc.additionalcostfactor + 0.5); nextTrip.cost = trip.cost + (int) ( waycost * rc.additionalcostfactor + 0.5 );
nextTrip.departure = trip.arrival; nextTrip.departure = trip.arrival;
nextTrip.arrival = nextTrip.departure + (long) ( waycost * 3600. / rc.cost1speed ); // 160ms / meter = 22km/h nextTrip.arrival = nextTrip.departure + (long) ( waycost * 3600. / rc.cost1speed ); // 22km/h
addToOpenSet( nextTrip ); addToOpenSet( nextTrip );
} }
else // connecting link else
// connecting link
{ {
ScheduledTrip nextTrip = new ScheduledTrip( offsets, link, currentNode, trip ); ScheduledTrip nextTrip = new ScheduledTrip( offsets, link, currentNode, trip );
long delay = (long)(rc.buffertime * 1000.); // 2 min long delay = (long) ( rc.buffertime * 1000. ); // 2 min
nextTrip.cost = trip.cost + (int)( delay*rc.waittimeadjustment * rc.cost1speed / 3600. ); nextTrip.cost = trip.cost + (int) ( delay * rc.waittimeadjustment * rc.cost1speed / 3600. );
nextTrip.departure = trip.arrival; nextTrip.departure = trip.arrival;
nextTrip.arrival = nextTrip.departure + delay; nextTrip.arrival = nextTrip.departure + delay;
@ -319,28 +469,36 @@ time0 = minutes0 * 60000L;
} }
} }
private OsmTrack compileTrip( ScheduledTrip trip, int offset ) private Iternity compileTrip( ScheduledTrip trip, int offset )
{ {
Iternity iternity = new Iternity();
OsmTrack track = new OsmTrack(); OsmTrack track = new OsmTrack();
track.iternity = new ArrayList<String>();
ScheduledTrip current = trip; ScheduledTrip current = trip;
ScheduledLine lastLine = new ScheduledLine(); ScheduledLine lastLine = new ScheduledLine();
ScheduledLine dummyLine = new ScheduledLine(); ScheduledLine dummyLine = new ScheduledLine();
List<ScheduledTrip> list = new ArrayList<ScheduledTrip>(); List<ScheduledTrip> list = new ArrayList<ScheduledTrip>();
int distance = 0; int distance = 0;
long departure = 0;
ScheduledTrip itrip = null; ScheduledTrip itrip = null;
String profile = extractProfile( rc.localFunction ); String profile = extractProfile( rc.localFunction );
SimpleDateFormat df = new SimpleDateFormat( "dd.MM HH:mm" );
// time0 = df.parse(startTime).getTime();
OsmNodeP nextNode = null; OsmNodeP nextNode = null;
while( current != null ) while (current != null)
{ {
System.out.println( "trip=" + current ); departure = current.departure;
// System.out.println( "trip=" + current );
OsmNodeP node = current.getTargetNode(); OsmNodeP node = current.getTargetNode();
OsmPathElement pe = OsmPathElement.create(node.ilon, node.ilat, node.selev, null, false ); OsmPathElement pe = OsmPathElement.create( node.ilon, node.ilat, node.selev, null, false );
track.addNode(pe); track.addNode( pe );
if ( nextNode != null ) if ( nextNode != null )
{ {
@ -349,7 +507,7 @@ System.out.println( "trip=" + current );
boolean isScheduled = current.link instanceof ScheduledLink; boolean isScheduled = current.link instanceof ScheduledLink;
boolean isConnection = current.link.descriptionBitmap == null && !isScheduled; boolean isConnection = current.link.descriptionBitmap == null && !isScheduled;
ScheduledLine line = isScheduled ? ((ScheduledLink)current.link).line : isConnection ? dummyLine : null; ScheduledLine line = isScheduled ? ( (ScheduledLink) current.link ).line : isConnection ? dummyLine : null;
if ( line != lastLine && !isConnection ) if ( line != lastLine && !isConnection )
{ {
@ -361,9 +519,9 @@ System.out.println( "trip=" + current );
if ( isScheduled && list.size() > 0 ) if ( isScheduled && list.size() > 0 )
{ {
list.get( list.size()-1 ).originNode = current.getTargetNode(); list.get( list.size() - 1 ).originNode = current.getTargetNode();
} }
list.add(itrip); list.add( itrip );
} }
else if ( itrip != null && !isConnection ) else if ( itrip != null && !isConnection )
{ {
@ -377,45 +535,61 @@ System.out.println( "trip=" + current );
track.distance = distance; track.distance = distance;
track.cost = trip.cost; track.cost = trip.cost;
for( int i=list.size()-1; i>=0; i-- ) for ( int i = list.size() - 1; i >= 0; i-- )
{ {
current = list.get(i); current = list.get( i );
String lineName = profile; String lineName = profile;
boolean isScheduled = current.link instanceof ScheduledLink; boolean isScheduled = current.link instanceof ScheduledLink;
if ( isScheduled ) if ( isScheduled )
{ {
lineName = ((ScheduledLink)current.link).line.name; lineName = ( (ScheduledLink) current.link ).line.name;
} }
String stationName = "*position*"; String stationName = "*position*";
if ( current.originNode instanceof StationNode ) if ( current.originNode instanceof StationNode )
{ {
stationName = ((StationNode)current.originNode).name; stationName = ( (StationNode) current.originNode ).name;
} }
String nextStationName = "*position*"; String nextStationName = "*position*";
if ( i > 0 && list.get(i-1).originNode instanceof StationNode ) if ( i > 0 && list.get( i - 1 ).originNode instanceof StationNode )
{ {
nextStationName = ((StationNode)list.get(i-1).originNode).name; 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 d0 = new Date( time0 + 60000L * offset + current.departure );
Date d1 = new Date( time0 + 60000L * offset + current.arrival ); Date d1 = new Date( time0 + 60000L * offset + current.arrival );
if ( track.iternity.size() > 0 ) track.iternity.add( "" ); if ( iternity.details.size() > 0 )
track.iternity.add( "depart: " + d0 + " " + stationName ); iternity.details.add( "" );
track.iternity.add( " --- " + lineName + " ---" ); iternity.details.add( "depart: " + df.format( d0 ) + " " + stationName );
track.iternity.add( "arrive: " + d1 + " " + nextStationName ); iternity.details.add( " --- " + lineName + " ---" );
iternity.details.add( "arrive: " + df.format( d1 ) + " " + nextStationName );
if ( !iternity.lines.contains( lineName ) )
{
iternity.lines.add( lineName );
}
} }
} }
return track; iternity.track = track;
iternity.arrivaltime = time0 + 60000L * offset + trip.arrival;
iternity.departtime = time0 + 60000L * offset + departure;
return iternity;
} }
private String extractProfile( String s ) private String extractProfile( String s )
{ {
int idx = s.lastIndexOf( '/' ); int idx = s.lastIndexOf( '/' );
if ( idx >= 0 ) s = s.substring( idx+1 ); if ( idx >= 0 )
s = s.substring( idx + 1 );
idx = s.indexOf( '.' ); idx = s.indexOf( '.' );
if ( idx >= 0 ) s = s.substring( 0,idx ); if ( idx >= 0 )
s = s.substring( 0, idx );
return s; return s;
} }
} }

View file

@ -5,21 +5,52 @@
*/ */
package btools.memrouter; 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 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; String name;
public String getName()
{
return name;
}
} }

View file

@ -5,14 +5,21 @@
*/ */
package btools.memrouter; 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.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
final class TrainSchedule final class TrainSchedule
{ {
private static class TrainScheduleCron private static class TrainScheduleCron
@ -21,26 +28,23 @@ final class TrainSchedule
long hours; long hours;
long dows; long dows;
boolean isNegative;
String cronSource;
TrainScheduleCron( String value ) TrainScheduleCron( String value )
{ {
StringTokenizer tk = new StringTokenizer( value, "_" ); StringTokenizer tk = new StringTokenizer( value, "_" );
minutes = parseElement( tk.nextToken() ); minutes = parseElement( tk.nextToken() );
hours = parseElement( tk.nextToken() ); hours = parseElement( tk.nextToken() );
dows = parseElement( tk.nextToken() ); dows = parseElement( tk.nextToken() );
cronSource = value;
} }
private long parseElement( String s ) private long parseElement( String s )
{ {
if ( "*".equals( s ) ) return Long.MAX_VALUE; if ( "*".equals( s ) )
{
return Long.MAX_VALUE;
}
StringTokenizer tk = new StringTokenizer( s, "," ); StringTokenizer tk = new StringTokenizer( s, "," );
long res = 0; long res = 0;
while( tk.hasMoreTokens() ) while (tk.hasMoreTokens())
{ {
String sub = tk.nextToken(); String sub = tk.nextToken();
int start, end; int start, end;
@ -53,11 +57,11 @@ final class TrainSchedule
else else
{ {
start = Integer.parseInt( sub.substring( 0, idx ) ); start = Integer.parseInt( sub.substring( 0, idx ) );
end = Integer.parseInt( sub.substring( idx + 1) ); end = Integer.parseInt( sub.substring( idx + 1 ) );
} }
for( int i=start; i <= end ; i++ ) for ( int i = start; i <= end; i++ )
{ {
res |= (1L<<i); res |= ( 1L << i );
} }
} }
return res; return res;
@ -65,14 +69,13 @@ final class TrainSchedule
boolean matches( int minute, int hour, int dow ) boolean matches( int minute, int hour, int dow )
{ {
return ( (1L << minute) & minutes ) != 0 return ( ( 1L << minute ) & minutes ) != 0 && ( ( 1L << hour ) & hours ) != 0 && ( ( 1L << dow ) & dows ) != 0;
&& ( (1L << hour) & hours ) != 0
&& ( (1L << dow) & dows ) != 0;
} }
} }
private List<TrainScheduleCron> cronsPositive; private List<TrainScheduleCron> cronsPositive;
private List<TrainScheduleCron> cronsNegative; private List<TrainScheduleCron> cronsNegative;
private Map<String,List<Integer>> timeTable = new HashMap<String,List<Integer>>();
public TrainSchedule( String cronstring ) public TrainSchedule( String cronstring )
{ {
@ -81,38 +84,111 @@ final class TrainSchedule
cronsPositive = new ArrayList<TrainScheduleCron>(); cronsPositive = new ArrayList<TrainScheduleCron>();
cronsNegative = new ArrayList<TrainScheduleCron>(); cronsNegative = new ArrayList<TrainScheduleCron>();
while ( tk.hasMoreTokens() ) while (tk.hasMoreTokens())
{ {
String sign = tk.nextToken(); String prefix = tk.nextToken();
String value = tk.nextToken(); String value = tk.nextToken();
TrainScheduleCron cron = new TrainScheduleCron( value ); if ( "+".equals( prefix ) )
if ( "+".equals( sign ) )
{ {
cronsPositive.add( cron ); cronsPositive.add( new TrainScheduleCron( value ) );
} }
else if ( "-".equals( sign ) ) else if ( "-".equals( prefix ) )
{ {
cronsNegative.add( cron ); cronsNegative.add( new TrainScheduleCron( value ) );
}
else
{
// prefix is a calendar id, value a slash-separated time list
List<Integer> times = new ArrayList<Integer>();
StringTokenizer tk3 = new StringTokenizer( value, "/" );
while( tk3.hasMoreTokens() )
{
times.add( Integer.valueOf( time2Minute( tk3.nextToken() ) ) );
}
Collections.sort( times );
timeTable.put( prefix, times );
} }
else throw new IllegalArgumentException( "invalid cron sign: " + sign );
} }
} }
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 ) 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<Integer> alltimes = null;
boolean listIsCopy = false;
for( String calId : timeTable.keySet() )
{
if ( calendarHasDate( calId, sday ) )
{
List<Integer> times = timeTable.get( calId );
if ( alltimes == null )
{
alltimes = times;
}
else
{
if ( !listIsCopy )
{
alltimes = new ArrayList<Integer>( 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(); Calendar cal = Calendar.getInstance();
cal.setTime( new Date( timeFrom ) ); cal.setTime( new Date( timeFrom ) );
int minute = cal.get( Calendar.MINUTE ); int minute = cal.get( Calendar.MINUTE );
int hour = cal.get( Calendar.HOUR_OF_DAY ); int hour = cal.get( Calendar.HOUR_OF_DAY );
int dow = cal.get( Calendar.DAY_OF_WEEK ); int dow = cal.get( Calendar.DAY_OF_WEEK );
dow = dow > 1 ? dow -1 : dow+6; dow = dow > 1 ? dow - 1 : dow + 6;
for( int cnt=0; cnt < 10080; cnt++ ) for ( int cnt = 0; cnt < 180; cnt++ )
{ {
boolean veto = false; boolean veto = false;
for( TrainScheduleCron cron : cronsNegative ) for ( TrainScheduleCron cron : cronsNegative )
{ {
if ( cron.matches( minute, hour, dow ) ) if ( cron.matches( minute, hour, dow ) )
{ {
@ -122,9 +198,10 @@ final class TrainSchedule
} }
if ( !veto ) if ( !veto )
{ {
for( TrainScheduleCron cron : cronsPositive ) for ( TrainScheduleCron cron : cronsPositive )
{ {
if ( cron.matches( minute, hour, dow ) ) return cnt; if ( cron.matches( minute, hour, dow ) )
return cnt;
} }
} }
@ -143,4 +220,63 @@ final class TrainSchedule
} }
return -1; return -1;
} }
private static Map<String,Set<String>> calendarMap;
private static boolean calendarHasDate( String calId, String date )
{
if ( calendarMap == null )
{
try
{
readCalendar();
}
catch (Exception e)
{
throw new RuntimeException( "cannot readcalendar: " + e );
}
}
Set<String> 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<String,Set<String>>();
Map<String,String> uniqueMap = new HashMap<String,String>();
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();
Set<String> idSet = calendarMap.get( calId );
if ( idSet == null )
{
idSet = new HashSet<String>();
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" );
}
} }

View file

@ -65,7 +65,7 @@ public class TwinRoutingEngine extends RoutingEngine
*/ */
OsmLinkP.currentserial++; OsmLinkP.currentserial++;
ScheduledRouter router = new ScheduledRouter( graph, routingContext, this ); 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( "linksProcessed=" + router.linksProcessed + " linksReProcessed=" + router.linksReProcessed);
System.out.println( "skippedChained=" + router.skippedChained + " closedSkippedChained=" + router.closedSkippedChained); 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 wayTilesIn = new File( parentDir, "waytiles55");
File[] fahrplanFiles = new File[2]; File[] fahrplanFiles = new File[2];
fahrplanFiles[0] = new File( parentDir, "fahrplan_nahverkehr.txt" ); 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 = new GraphLoader();
graph.process( nodeTilesIn, wayTilesIn, fahrplanFiles, routingContext.expctxWay ); graph.process( nodeTilesIn, wayTilesIn, fahrplanFiles, routingContext.expctxWay );

View file

@ -1,12 +1,10 @@
package btools.memrouter; package btools.memrouter;
import java.util.Random; import java.io.File;
import java.util.HashMap; import java.net.URL;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import java.net.URL;
import java.io.File;
import btools.expressions.BExpressionContextWay; import btools.expressions.BExpressionContextWay;
import btools.expressions.BExpressionMetaData; import btools.expressions.BExpressionMetaData;

View file

@ -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<Integer> offsetList = new ArrayList<Integer>();
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 ) );
}
}

View file

@ -58,8 +58,8 @@ public class RouteServer extends Thread
BufferedWriter bw = null; BufferedWriter bw = null;
try try
{ {
br = new BufferedReader( new InputStreamReader( clientSocket.getInputStream() ) ); br = new BufferedReader( new InputStreamReader( clientSocket.getInputStream() , "UTF-8") );
bw = new BufferedWriter( new OutputStreamWriter( clientSocket.getOutputStream() ) ); bw = new BufferedWriter( new OutputStreamWriter( clientSocket.getOutputStream(), "UTF-8" ) );
// we just read the first line // we just read the first line
String getline = br.readLine(); String getline = br.readLine();