im-router-update
This commit is contained in:
parent
cd8082f2b2
commit
d277db0bd1
19 changed files with 1506 additions and 903 deletions
|
@ -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
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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" ) ) )
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -27,6 +27,8 @@ import btools.util.LazyArrayOfLists;
|
||||||
public class GraphLoader extends MapCreatorBase
|
public class GraphLoader extends MapCreatorBase
|
||||||
{
|
{
|
||||||
private CompactLongMap<OsmNodeP> nodesMap;
|
private CompactLongMap<OsmNodeP> nodesMap;
|
||||||
|
|
||||||
|
private Map<String, StationNode> stationMap;
|
||||||
|
|
||||||
private BExpressionContextWay expctxWay;
|
private BExpressionContextWay expctxWay;
|
||||||
|
|
||||||
|
@ -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,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
|
if ( transitonly )
|
||||||
|
{
|
||||||
int ilon = pos.getILon();
|
return matchStationForPosition( pos );
|
||||||
int ilat = pos.getILat();
|
}
|
||||||
|
|
||||||
|
int ilon = pos.getILon();
|
||||||
|
int ilat = pos.getILat();
|
||||||
|
|
||||||
List<OsmNodeP> nodes = new ArrayList<OsmNodeP>();
|
List<OsmNodeP> nodes = new ArrayList<OsmNodeP>();
|
||||||
nodes.addAll( subListForPos( ilon-6125, ilat-6125 ) );
|
nodes.addAll( subListForPos( ilon-6125, ilat-6125 ) );
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
|
||||||
|
|
||||||
public static OffsetSet emptySet()
|
protected BitSet mask;
|
||||||
|
|
||||||
|
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, existingSets );
|
||||||
set = new OffsetSet( m );
|
// System.out.println( "created set: " + set + " instancecount=" + existingSets.size() );
|
||||||
existingSets.put( mm, set );
|
}
|
||||||
instancecount++;
|
return set;
|
||||||
System.out.println( "created set: " + set + " instancecount=" + instancecount );
|
|
||||||
}
|
|
||||||
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 )
|
||||||
{
|
{
|
||||||
OffsetSet gate = gateHolder.getOffsetSet();
|
if ( max < size )
|
||||||
long gmask = gate.mask;
|
{
|
||||||
|
BitSet fmask = (BitSet)mask.clone();
|
||||||
long fmask = in.mask;
|
fmask.set( max > 0 ? max : 0, size, false );
|
||||||
|
return create( fmask );
|
||||||
// delete the high offsets with offset + timeDiff >= maxoffset
|
}
|
||||||
fmask = timeDiff > 31 ? 0L : ( fmask << timeDiff ) >> timeDiff;
|
return this;
|
||||||
|
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
@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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,16 +5,15 @@
|
||||||
*/
|
*/
|
||||||
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The target is either the next link or the target node
|
* The target is either the next link or the target node
|
||||||
*/
|
*/
|
||||||
protected OsmNodeP sourceNode;
|
protected OsmNodeP sourceNode;
|
||||||
|
@ -23,12 +22,12 @@ 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()
|
||||||
{
|
{
|
||||||
return descriptionBitmap == null;
|
return descriptionBitmap == null;
|
||||||
|
@ -44,59 +43,61 @@ public class OsmLinkP implements OffsetSetHolder
|
||||||
sourceNode = source;
|
sourceNode = source;
|
||||||
targetNode = target;
|
targetNode = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected OsmLinkP()
|
protected OsmLinkP()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public OffsetSet getOffsetSet()
|
public OffsetSet getOffsetSet()
|
||||||
{
|
{
|
||||||
return offsets;
|
return offsets;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOffsetSet( OffsetSet offsets )
|
public void setOffsetSet( OffsetSet offsets )
|
||||||
{
|
{
|
||||||
this.offsets = offsets;
|
this.offsets = offsets;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isVirgin()
|
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() )
|
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
|
||||||
*/
|
*/
|
||||||
public void setNext( OsmLinkP link, OsmNodeP source )
|
public void setNext( OsmLinkP link, OsmNodeP source )
|
||||||
{
|
{
|
||||||
if ( sourceNode == source )
|
if ( sourceNode == source )
|
||||||
{
|
{
|
||||||
next = link;
|
next = link;
|
||||||
}
|
}
|
||||||
else if ( targetNode == source )
|
else if ( targetNode == source )
|
||||||
{
|
{
|
||||||
previous = link;
|
previous = link;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new IllegalArgumentException( "internal error: setNext: unknown source" );
|
throw new IllegalArgumentException( "internal error: setNext: unknown source" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the relevant next-pointer for the given source
|
* Get the relevant next-pointer for the given source
|
||||||
*/
|
*/
|
||||||
|
@ -107,7 +108,7 @@ public class OsmLinkP implements OffsetSetHolder
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
else if ( targetNode == source )
|
else if ( targetNode == source )
|
||||||
{
|
{
|
||||||
return previous;
|
return previous;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -126,7 +127,7 @@ public class OsmLinkP implements OffsetSetHolder
|
||||||
return targetNode;
|
return targetNode;
|
||||||
}
|
}
|
||||||
else if ( targetNode == source )
|
else if ( targetNode == source )
|
||||||
{
|
{
|
||||||
return sourceNode;
|
return sourceNode;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -145,7 +146,7 @@ public class OsmLinkP implements OffsetSetHolder
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if ( targetNode == source )
|
else if ( targetNode == source )
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -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>";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,150 +7,169 @@ 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;
|
||||||
{
|
StationNode lastStationInLine = null;
|
||||||
ScheduledLine currentLine = null;
|
|
||||||
StationNode lastStationInLine = null;
|
|
||||||
|
|
||||||
boolean readingLocations = false;
|
boolean readingLocations = false;
|
||||||
|
|
||||||
Map<String,StationNode> stationMap = new HashMap<String,StationNode>();
|
|
||||||
|
|
||||||
|
|
||||||
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++;
|
|
||||||
|
|
||||||
// link station to connecting node
|
Map<String, StationNode> stationMap = new HashMap<String, StationNode>();
|
||||||
OsmLinkP link = new OsmLinkP( station, node );
|
|
||||||
link.descriptionBitmap = null;
|
for ( File file : files )
|
||||||
station.addLink( link );
|
{
|
||||||
node.addLink( link );
|
BufferedReader br = null;
|
||||||
|
try
|
||||||
int distance = station.calcDistance( node );
|
{
|
||||||
System.out.println( "matched connection for station " + station.name + " at " + distance + " meter" );
|
br = new BufferedReader( new InputStreamReader( new FileInputStream( file ) , "ISO-8859-1" ) );
|
||||||
}
|
for ( ;; )
|
||||||
}
|
{
|
||||||
locIdx++;
|
String line = br.readLine();
|
||||||
}
|
if ( line == null )
|
||||||
if ( nconnections > 0 )
|
break;
|
||||||
{
|
line = line.trim();
|
||||||
station.selev = (short)(elev / nconnections);
|
if ( line.length() == 0 )
|
||||||
}
|
continue;
|
||||||
stationMap.put( station.name, station );
|
|
||||||
}
|
if ( line.startsWith( "#" ) )
|
||||||
else if ( currentLine != null )
|
continue;
|
||||||
{
|
|
||||||
int idx = line.indexOf( ' ' );
|
if ( line.startsWith( "-- locations" ) )
|
||||||
String name = line.substring( 0, idx );
|
{
|
||||||
StationNode nextStationInLine = stationMap.get( name );
|
readingLocations = true;
|
||||||
String value = line.substring( idx ).trim();
|
continue;
|
||||||
int offsetMinute = 0;
|
}
|
||||||
if ( lastStationInLine == null )
|
if ( line.startsWith( "-- trainline" ) )
|
||||||
{
|
{
|
||||||
currentLine.schedule = new TrainSchedule( value );
|
readingLocations = false;
|
||||||
}
|
currentLine = new ScheduledLine();
|
||||||
else
|
currentLine.name = line.substring( "-- trainline".length() ).trim();
|
||||||
{
|
lastStationInLine = null;
|
||||||
if ( value.startsWith( "+") ) value = value.substring( 1 );
|
continue;
|
||||||
offsetMinute = Integer.parseInt( value );
|
}
|
||||||
|
if ( readingLocations )
|
||||||
ScheduledLink link = new ScheduledLink( lastStationInLine, nextStationInLine );
|
{
|
||||||
link.line = currentLine;
|
StationNode station = new StationNode();
|
||||||
link.indexInLine = currentLine.offsetMinutes.size()-1;
|
|
||||||
|
// Eschborn 50.14323,8.56112
|
||||||
System.out.println( "adding: " + link );
|
StringTokenizer tk = new StringTokenizer( line, " \t" );
|
||||||
lastStationInLine.addLink( link );
|
station.name = tk.nextToken();
|
||||||
}
|
|
||||||
currentLine.offsetMinutes.add( Integer.valueOf( offsetMinute ) );
|
if ( stationMap.containsKey( station.name ) )
|
||||||
|
{
|
||||||
lastStationInLine = nextStationInLine;
|
System.out.println( "skipping station name already known: " + station.name );
|
||||||
}
|
continue;
|
||||||
}
|
}
|
||||||
br.close();
|
|
||||||
System.out.println( "read " + stationMap.size() + " stations" );
|
int locIdx = 0;
|
||||||
}
|
String loc = null;
|
||||||
}
|
int elev = 0;
|
||||||
catch( Exception e )
|
int nconnections = 0;
|
||||||
{
|
while (tk.hasMoreTokens() || locIdx == 1)
|
||||||
throw new RuntimeException( e );
|
{
|
||||||
}
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,93 +11,96 @@ 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 the individual
|
||||||
* get a list of departures relative to the start-time plus
|
* offsets according to the offset mask
|
||||||
* the individual offsets according to the offset mask
|
*
|
||||||
*
|
* departures with the same wait-time are aggregated in one result element
|
||||||
* departures with the same wait-time are aggregated in one
|
* with multiple 1-bits in the offset mask
|
||||||
* result element 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
|
||||||
* @param id the value to add to this set.
|
* 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 offsetEnd = offsetMinutes.get(idx+1).intValue();
|
|
||||||
|
|
||||||
|
|
||||||
Map<Integer,List<Integer>> waitOffsets = getDepartures( offsetStart, timeFrom + timeFromCorrection, offsets );
|
|
||||||
|
|
||||||
for( Map.Entry<Integer,List<Integer>> 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<Integer,List<Integer>> getDepartures( int offsetStart, long timeFrom, OffsetSet offsets )
|
int offsetStart = offsetMinutes.get( idx ).intValue();
|
||||||
{
|
int offsetEnd = offsetMinutes.get( idx + 1 ).intValue();
|
||||||
Map<Integer,List<Integer>> waitOffsets = new HashMap<Integer,List<Integer>>();
|
|
||||||
int size = offsets.size();
|
Map<Integer, List<Integer>> waitOffsets = getDepartures( offsetStart, timeFrom + timeFromCorrection, offsets );
|
||||||
|
|
||||||
for(int offset = 0;;)
|
for ( Map.Entry<Integer, List<Integer>> e : waitOffsets.entrySet() )
|
||||||
{
|
{
|
||||||
// skip to next offset bit
|
ScheduledDeparture depart = new ScheduledDeparture();
|
||||||
while( offset < size && !offsets.contains( offset ) )
|
depart.waitTime = e.getKey().intValue() * 60000L + timeFromCorrection;
|
||||||
{
|
depart.offsets = offsets.create( e.getValue() );
|
||||||
offset++;
|
depart.rideTime = ( offsetEnd - offsetStart ) * 60000L;
|
||||||
}
|
result.add( depart );
|
||||||
if ( offset >= size ) return waitOffsets;
|
}
|
||||||
|
return result;
|
||||||
int toNext = schedule.getMinutesToNext( timeFrom + 60000L*(offset - offsetStart ) );
|
}
|
||||||
if ( toNext < 0 ) return waitOffsets;
|
|
||||||
int departOffset = offset + toNext;
|
private Map<Integer, List<Integer>> getDepartures( int offsetStart, long timeFrom, OffsetSet offsets )
|
||||||
|
{
|
||||||
// whats the closest offset within the next toNext minutes
|
Map<Integer, List<Integer>> waitOffsets = new HashMap<Integer, List<Integer>>();
|
||||||
int lastOffset = offset;
|
int size = offsets.size();
|
||||||
while( toNext-- >= 0 && offset < size )
|
|
||||||
{
|
for ( int offset = 0;; )
|
||||||
if ( offsets.contains( offset ) )
|
{
|
||||||
{
|
// skip to next offset bit
|
||||||
lastOffset = offset;
|
while (offset < size && !offsets.contains( offset ))
|
||||||
}
|
{
|
||||||
offset++;
|
offset++;
|
||||||
}
|
}
|
||||||
|
if ( offset >= size )
|
||||||
if ( lastOffset == size-1 ) return waitOffsets; // todo?
|
return waitOffsets;
|
||||||
|
|
||||||
int waitTime = departOffset - lastOffset;
|
int toNext = schedule.getMinutesToNext( timeFrom + 60000L * ( offset - offsetStart ) );
|
||||||
|
|
||||||
// if we have that wait time in the list, just add the offset bit
|
if ( toNext < 0 )
|
||||||
List<Integer> offsetList = waitOffsets.get( Integer.valueOf( waitTime ) );
|
return waitOffsets;
|
||||||
if ( offsetList == null )
|
int departOffset = offset + toNext;
|
||||||
{
|
|
||||||
offsetList = new ArrayList<Integer>();
|
// whats the closest offset within the next toNext minutes
|
||||||
waitOffsets.put( Integer.valueOf( waitTime ), offsetList );
|
int lastOffset = offset;
|
||||||
}
|
while (toNext-- >= 0 && offset < size)
|
||||||
offsetList.add( Integer.valueOf( lastOffset ) );
|
{
|
||||||
}
|
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<Integer> offsetList = waitOffsets.get( Integer.valueOf( waitTime ) );
|
||||||
|
if ( offsetList == null )
|
||||||
|
{
|
||||||
|
offsetList = new ArrayList<Integer>();
|
||||||
|
waitOffsets.put( Integer.valueOf( waitTime ), offsetList );
|
||||||
|
}
|
||||||
|
offsetList.add( Integer.valueOf( lastOffset ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,406 +18,578 @@ 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 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;
|
|
||||||
|
|
||||||
SortedHeap<ScheduledTrip> openSet = new SortedHeap<ScheduledTrip>();
|
public long linksProcessed = 0L;
|
||||||
|
public long linksReProcessed = 0L;
|
||||||
|
public long closedSkippedChained = 0L;
|
||||||
|
public long skippedChained = 0L;
|
||||||
|
|
||||||
ScheduledRouter( GraphLoader graph, RoutingContext rc, RoutingEngine re )
|
private RoutingContext rc;
|
||||||
{
|
private 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 );
|
|
||||||
|
|
||||||
// SimpleDateFormat df = new SimpleDateFormat( "dd.MM.yyyy-HH:mm" );
|
private long time0;
|
||||||
// time0 = df.parse(startTime).getTime();
|
private OsmNodeP start;
|
||||||
time0 = System.currentTimeMillis() + (long)(rc.starttimeoffset * 60000L );
|
private OsmNodeP end;
|
||||||
long minutes0 = (time0 + 59999L) / 60000L;
|
|
||||||
time0 = minutes0 * 60000L;
|
|
||||||
|
|
||||||
OffsetSet finishedOffsets = OffsetSet.emptySet();
|
SortedHeap<ScheduledTrip> openSet = new SortedHeap<ScheduledTrip>();
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// check local closure for links:
|
ScheduledRouter( GraphLoader graph, RoutingContext rc, RoutingEngine re )
|
||||||
offsets = currentLink.filterAndClose( offsets, trip.arrival, currentLink instanceof ScheduledLink );
|
{
|
||||||
if ( offsets == null ) continue;
|
this.graph = graph;
|
||||||
|
this.rc = rc;
|
||||||
|
this.re = re;
|
||||||
// check for arrival
|
}
|
||||||
if ( currentNode == end )
|
|
||||||
{
|
private static List<Iternity> trips = new ArrayList<Iternity>();
|
||||||
for( int offset = 0; offset<trip.offsets.size(); offset++ )
|
private static long oldChecksum = 0;
|
||||||
{
|
|
||||||
if ( trip.offsets.contains( offset ) )
|
private String startEndText()
|
||||||
{
|
{
|
||||||
track = compileTrip( trip, offset );
|
return (start == null ? "unmatched" : start.getName() ) + "->" + (end == null ? "unmatched" : end.getName() );
|
||||||
System.out.println( "---- begin route ------ (cost " + track.cost + ")" );
|
}
|
||||||
for( String s : track.iternity ) System.out.println( s );
|
|
||||||
System.out.println( "---- end route ------" );
|
public OsmTrack findRoute( OsmPos startPos, OsmPos endPos, int alternativeIdx ) throws Exception
|
||||||
break; // + plus more offsets..
|
{
|
||||||
}
|
if ( alternativeIdx == -1 ) // lowest cost result
|
||||||
}
|
|
||||||
finishedOffsets = finishedOffsets.add( offsets );
|
|
||||||
if ( solutionCount++ >= 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 )
|
|
||||||
{
|
{
|
||||||
int distance = nextTrip.getTargetNode().calcDistance( end );
|
List<Iternity> singleTrip = _findRoute( startPos, endPos, true );
|
||||||
nextTrip.adjustedCost = nextTrip.cost + (int)(distance * rc.pass1coefficient + 0.5);
|
if ( singleTrip.isEmpty() )
|
||||||
openSet.add( nextTrip.adjustedCost, nextTrip );
|
{
|
||||||
|
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
|
// check for identical params
|
||||||
rc.nogomatch = false;
|
long[] nogocheck = rc.getNogoChecksums();
|
||||||
int distance = rc.calcDistance( currentNode.ilon, currentNode.ilat, node.ilon, node.ilat );
|
|
||||||
if ( rc.nogomatch )
|
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 );
|
||||||
|
|
||||||
|
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<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 )
|
||||||
|
{
|
||||||
|
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<ScheduledDeparture> 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;
|
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 );
|
waycost += (int) rc.expctxWay.getInitialcost();
|
||||||
|
|
||||||
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<ScheduledDeparture> 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 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if ( link.isWayLink() )
|
|
||||||
|
if ( node.getNodeDecsription() != null )
|
||||||
{
|
{
|
||||||
// get costfactor
|
rc.expctxNode.evaluate( rc.expctxWay.getNodeAccessGranted() != 0., node.getNodeDecsription(), null );
|
||||||
rc.expctxWay.evaluate( link.isReverse(currentNode), link.descriptionBitmap, null );
|
float initialcost = rc.expctxNode.getInitialcost();
|
||||||
|
if ( initialcost >= 1000000. )
|
||||||
// *** penalty for distance
|
{
|
||||||
float costfactor = rc.expctxWay.getCostfactor();
|
return;
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
}
|
waycost += (int) initialcost;
|
||||||
|
|
||||||
private OsmTrack compileTrip( ScheduledTrip trip, int offset )
|
|
||||||
{
|
|
||||||
OsmTrack track = new OsmTrack();
|
|
||||||
track.iternity = new ArrayList<String>();
|
|
||||||
ScheduledTrip current = trip;
|
|
||||||
ScheduledLine lastLine = new ScheduledLine();
|
|
||||||
ScheduledLine dummyLine = new ScheduledLine();
|
|
||||||
List<ScheduledTrip> list = new ArrayList<ScheduledTrip>();
|
|
||||||
|
|
||||||
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 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return track;
|
// *** penalty for turning angles
|
||||||
}
|
if ( trip.originNode != null )
|
||||||
|
{
|
||||||
private String extractProfile( String s )
|
// penalty proportional to direction change
|
||||||
{
|
double cos = rc.calcCosAngle( trip.originNode.ilon, trip.originNode.ilat, currentNode.ilon, currentNode.ilat, node.ilon, node.ilat );
|
||||||
int idx = s.lastIndexOf( '/' );
|
int turncost = (int) ( cos * rc.expctxWay.getTurncost() + 0.2 ); // e.g. turncost=90 -> 90 degree = 90m penalty
|
||||||
if ( idx >= 0 ) s = s.substring( idx+1 );
|
waycost += turncost;
|
||||||
idx = s.indexOf( '.' );
|
}
|
||||||
if ( idx >= 0 ) s = s.substring( 0,idx );
|
|
||||||
return s;
|
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<ScheduledTrip> list = new ArrayList<ScheduledTrip>();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,142 +5,278 @@
|
||||||
*/
|
*/
|
||||||
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
|
||||||
{
|
{
|
||||||
long minutes;
|
long minutes;
|
||||||
long hours;
|
long hours;
|
||||||
long dows;
|
long dows;
|
||||||
|
|
||||||
boolean isNegative;
|
|
||||||
|
|
||||||
String cronSource;
|
|
||||||
|
|
||||||
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, "_" );
|
return Long.MAX_VALUE;
|
||||||
minutes = parseElement( tk.nextToken() );
|
|
||||||
hours = parseElement( tk.nextToken() );
|
|
||||||
dows = parseElement( tk.nextToken() );
|
|
||||||
|
|
||||||
cronSource = 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<TrainScheduleCron> cronsPositive;
|
||||||
|
private List<TrainScheduleCron> cronsNegative;
|
||||||
|
private Map<String,List<Integer>> timeTable = new HashMap<String,List<Integer>>();
|
||||||
|
|
||||||
|
public TrainSchedule( String cronstring )
|
||||||
|
{
|
||||||
|
StringTokenizer tk = new StringTokenizer( cronstring, " " );
|
||||||
|
|
||||||
|
cronsPositive = new ArrayList<TrainScheduleCron>();
|
||||||
|
cronsNegative = new ArrayList<TrainScheduleCron>();
|
||||||
|
|
||||||
|
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<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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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<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();
|
||||||
|
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<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();
|
||||||
|
|
||||||
private long parseElement( String s )
|
Set<String> idSet = calendarMap.get( calId );
|
||||||
{
|
if ( idSet == null )
|
||||||
if ( "*".equals( s ) ) return Long.MAX_VALUE;
|
{
|
||||||
StringTokenizer tk = new StringTokenizer( s, "," );
|
idSet = new HashSet<String>();
|
||||||
long res = 0;
|
calendarMap.put( calId, idSet );
|
||||||
while( tk.hasMoreTokens() )
|
}
|
||||||
{
|
String uniqueDate = uniqueMap.get( calDate );
|
||||||
String sub = tk.nextToken();
|
if ( uniqueDate == null )
|
||||||
int start, end;
|
{
|
||||||
int idx = sub.indexOf( '-' );
|
uniqueDate = calDate;
|
||||||
if ( idx < 0 )
|
uniqueMap.put( uniqueDate, uniqueDate );
|
||||||
{
|
}
|
||||||
start = Integer.parseInt( sub );
|
idSet.add( uniqueDate );
|
||||||
end = start;
|
}
|
||||||
}
|
br.close();
|
||||||
else
|
System.out.println( "read calendar with " + calendarMap.size() + " ids" );
|
||||||
{
|
}
|
||||||
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<TrainScheduleCron> cronsPositive;
|
|
||||||
private List<TrainScheduleCron> cronsNegative;
|
|
||||||
|
|
||||||
public TrainSchedule( String cronstring )
|
|
||||||
{
|
|
||||||
StringTokenizer tk = new StringTokenizer( cronstring, " " );
|
|
||||||
|
|
||||||
cronsPositive = new ArrayList<TrainScheduleCron>();
|
|
||||||
cronsNegative = new ArrayList<TrainScheduleCron>();
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 ) );
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue