Merge branch 'master' into cleanup-fileaccess
This commit is contained in:
commit
8c5a961011
39 changed files with 1637 additions and 1084 deletions
|
|
@ -8,5 +8,6 @@ dependencies {
|
|||
implementation project(':brouter-util')
|
||||
implementation project(':brouter-expressions')
|
||||
implementation project(':brouter-codec')
|
||||
testImplementation 'junit:junit:4.13.1'
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,9 @@ final class MessageData implements Cloneable
|
|||
+ "\t" + linknodecost
|
||||
+ "\t" + linkinitcost
|
||||
+ "\t" + wayKeyValues
|
||||
+ "\t" + ( nodeKeyValues == null ? "" : nodeKeyValues );
|
||||
+ "\t" + ( nodeKeyValues == null ? "" : nodeKeyValues )
|
||||
+ "\t" + ((int)time)
|
||||
+ "\t" + ((int)energy);
|
||||
}
|
||||
|
||||
void add( MessageData d )
|
||||
|
|
|
|||
|
|
@ -139,7 +139,10 @@ abstract class OsmPath implements OsmLinkHolder
|
|||
protected void addAddionalPenalty(OsmTrack refTrack, boolean detailMode, OsmPath origin, OsmLink link, RoutingContext rc )
|
||||
{
|
||||
byte[] description = link.descriptionBitmap;
|
||||
if ( description == null ) throw new IllegalArgumentException( "null description for: " + link );
|
||||
if ( description == null )
|
||||
{
|
||||
return; // could be a beeline path
|
||||
}
|
||||
|
||||
boolean recordTransferNodes = detailMode || rc.countTraffic;
|
||||
|
||||
|
|
@ -298,6 +301,16 @@ abstract class OsmPath implements OsmLinkHolder
|
|||
originElement = null; // prevent duplicate point
|
||||
}
|
||||
}
|
||||
|
||||
if ( rc.checkPendingEndpoint() )
|
||||
{
|
||||
dist = rc.calcDistance( rc.ilonshortest, rc.ilatshortest, lon2, lat2 );
|
||||
if ( rc.shortestmatch )
|
||||
{
|
||||
stopAtEndpoint = true;
|
||||
ele2 = interpolateEle( ele1, ele2, rc.wayfraction );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,8 +19,11 @@ import java.io.FileWriter;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringWriter;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import btools.mapaccess.MatchedWaypoint;
|
||||
import btools.mapaccess.OsmPos;
|
||||
|
|
@ -31,7 +34,7 @@ import btools.util.StringUtils;
|
|||
public final class OsmTrack
|
||||
{
|
||||
// csv-header-line
|
||||
private static final String MESSAGES_HEADER = "Longitude\tLatitude\tElevation\tDistance\tCostPerKm\tElevCost\tTurnCost\tNodeCost\tInitialCost\tWayTags\tNodeTags";
|
||||
private static final String MESSAGES_HEADER = "Longitude\tLatitude\tElevation\tDistance\tCostPerKm\tElevCost\tTurnCost\tNodeCost\tInitialCost\tWayTags\tNodeTags\tTime\tEnergy";
|
||||
|
||||
public MatchedWaypoint endPoint;
|
||||
public long[] nogoChecksums;
|
||||
|
|
@ -528,6 +531,23 @@ public final class OsmTrack
|
|||
.append( "</wpt>\n" );
|
||||
}
|
||||
}
|
||||
|
||||
if ( turnInstructionMode == 6 ) // orux style
|
||||
{
|
||||
for( VoiceHint hint: voiceHints.list )
|
||||
{
|
||||
sb.append( " <wpt lat=\"" ).append( formatILat( hint.ilat ) ).append( "\" lon=\"" )
|
||||
.append( formatILon( hint.ilon ) ).append( "\">" )
|
||||
.append( hint.selev == Short.MIN_VALUE ? "" : "<ele>" + (hint.selev / 4.) + "</ele>" )
|
||||
.append( "<extensions>\n" +
|
||||
"<om:oruxmapsextensions xmlns:om=\"http://www.oruxmaps.com/oruxmapsextensions/1/0\">\n" +
|
||||
"<om:ext type=\"ICON\" subtype=\"0\">" ).append("" + hint.getOruxAction() )
|
||||
.append( "</om:ext>\n" +
|
||||
"</om:oruxmapsextensions>\n" +
|
||||
"</extensions>\n" +
|
||||
"</wpt>" );
|
||||
}
|
||||
}
|
||||
|
||||
for( int i=0; i<=pois.size() - 1; i++ )
|
||||
{
|
||||
|
|
@ -691,8 +711,19 @@ public final class OsmTrack
|
|||
|
||||
public List<String> iternity;
|
||||
|
||||
public void writeJson( String filename ) throws Exception
|
||||
{
|
||||
BufferedWriter bw = new BufferedWriter( new FileWriter( filename ) );
|
||||
|
||||
bw.write( formatAsGeoJson() );
|
||||
bw.close();
|
||||
}
|
||||
|
||||
|
||||
public String formatAsGeoJson()
|
||||
{
|
||||
int turnInstructionMode = voiceHints != null ? voiceHints.turnInstructionMode : 0;
|
||||
|
||||
StringBuilder sb = new StringBuilder( 8192 );
|
||||
|
||||
sb.append( "{\n" );
|
||||
|
|
@ -714,7 +745,20 @@ public final class OsmTrack
|
|||
sb.append( " \"voicehints\": [\n" );
|
||||
for( VoiceHint hint: voiceHints.list )
|
||||
{
|
||||
sb.append( " [" ).append( hint.indexInTrack ).append( ',' ).append( hint.getCommand() ).append( ',' ).append( hint.getExitNumber() ).append( "],\n" );
|
||||
sb.append( " [" );
|
||||
sb.append( hint.indexInTrack );
|
||||
sb.append( ',' ).append( hint.getCommand() );
|
||||
sb.append( ',' ).append( hint.getExitNumber() );
|
||||
sb.append( ',' ).append( hint.distanceToNext );
|
||||
sb.append( ',' ).append( (int) hint.angle );
|
||||
|
||||
// not always include geometry because longer and only needed for comment style
|
||||
if ( turnInstructionMode == 4 ) // comment style
|
||||
{
|
||||
sb.append( ",\"" ).append( hint.formatGeometry() ).append( "\"" );
|
||||
}
|
||||
|
||||
sb.append( "],\n" );
|
||||
}
|
||||
sb.deleteCharAt( sb.lastIndexOf( "," ) );
|
||||
sb.append( " ],\n" );
|
||||
|
|
@ -729,7 +773,7 @@ public final class OsmTrack
|
|||
{
|
||||
sb.append( " [" ).append( sp.get(i) ).append( i> 0 ? "],\n" : "]\n" );
|
||||
}
|
||||
sb.append( " ]\n" );
|
||||
sb.append( " ],\n" );
|
||||
}
|
||||
}
|
||||
else // ... otherwise traditional message list
|
||||
|
|
@ -741,9 +785,24 @@ public final class OsmTrack
|
|||
sb.append( " [\"" ).append( m.replaceAll( "\t", "\", \"" ) ).append( "\"],\n" );
|
||||
}
|
||||
sb.deleteCharAt( sb.lastIndexOf( "," ) );
|
||||
sb.append( " ]\n" );
|
||||
sb.append( " ],\n" );
|
||||
}
|
||||
|
||||
if ( getTotalSeconds() > 0 ) {
|
||||
sb.append( " \"times\": [" );
|
||||
DecimalFormat decimalFormat = (DecimalFormat) NumberFormat.getInstance( Locale.ENGLISH );
|
||||
decimalFormat.applyPattern( "0.###" );
|
||||
for ( OsmPathElement n : nodes ) {
|
||||
sb.append( decimalFormat.format( n.getTime() ) ).append( "," );
|
||||
}
|
||||
sb.deleteCharAt( sb.lastIndexOf( "," ) );
|
||||
sb.append( "]\n" );
|
||||
} else {
|
||||
sb.deleteCharAt( sb.lastIndexOf( "," ) );
|
||||
}
|
||||
|
||||
sb.append( " },\n" );
|
||||
|
||||
if ( iternity != null )
|
||||
{
|
||||
sb.append( " \"iternity\": [\n" );
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import btools.expressions.BExpressionContextNode;
|
|||
import btools.expressions.BExpressionContextWay;
|
||||
import btools.mapaccess.GeometryDecoder;
|
||||
import btools.mapaccess.OsmLink;
|
||||
import btools.mapaccess.OsmNode;
|
||||
import btools.util.CheapAngleMeter;
|
||||
import btools.util.CheapRuler;
|
||||
|
||||
|
|
@ -191,7 +192,9 @@ public final class RoutingContext
|
|||
public List<OsmNodeNamed> poipoints;
|
||||
|
||||
public List<OsmNodeNamed> nogopoints = null;
|
||||
private List<OsmNodeNamed> nogopoints_all = null; // full list not filtered for wayoints-in-nogos
|
||||
private List<OsmNodeNamed> keepnogopoints = null;
|
||||
private OsmNodeNamed pendingEndpoint = null;
|
||||
|
||||
public Integer startDirection;
|
||||
public boolean startDirectionValid;
|
||||
|
|
@ -257,14 +260,29 @@ public final class RoutingContext
|
|||
}
|
||||
}
|
||||
|
||||
public void cleanNogolist( List<OsmNodeNamed> waypoints )
|
||||
/**
|
||||
* restore the full nogolist previously saved by cleanNogoList
|
||||
*/
|
||||
public void restoreNogoList()
|
||||
{
|
||||
nogopoints = nogopoints_all;
|
||||
}
|
||||
|
||||
/**
|
||||
* clean the nogolist (previoulsy saved by saveFullNogolist())
|
||||
* by removing nogos with waypoints within
|
||||
*
|
||||
* @return true if all wayoints are all in the same (full-weigth) nogo area (triggering bee-line-mode)
|
||||
*/
|
||||
public void cleanNogoList( List<OsmNode> waypoints )
|
||||
{
|
||||
nogopoints_all = nogopoints;
|
||||
if ( nogopoints == null ) return;
|
||||
List<OsmNodeNamed> nogos = new ArrayList<OsmNodeNamed>();
|
||||
for( OsmNodeNamed nogo : nogopoints )
|
||||
{
|
||||
boolean goodGuy = true;
|
||||
for( OsmNodeNamed wp : waypoints )
|
||||
for( OsmNode wp : waypoints )
|
||||
{
|
||||
if ( wp.calcDistance( nogo ) < nogo.radius
|
||||
&& (!(nogo instanceof OsmNogoPolygon)
|
||||
|
|
@ -273,7 +291,6 @@ public final class RoutingContext
|
|||
: ((OsmNogoPolygon)nogo).isOnPolyline(wp.ilon, wp.ilat))))
|
||||
{
|
||||
goodGuy = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( goodGuy ) nogos.add( nogo );
|
||||
|
|
@ -281,6 +298,31 @@ public final class RoutingContext
|
|||
nogopoints = nogos.isEmpty() ? null : nogos;
|
||||
}
|
||||
|
||||
public boolean allInOneNogo( List<OsmNode> waypoints )
|
||||
{
|
||||
if ( nogopoints == null ) return false;
|
||||
boolean allInTotal = false;
|
||||
for( OsmNodeNamed nogo : nogopoints )
|
||||
{
|
||||
boolean allIn = Double.isNaN( nogo.nogoWeight );
|
||||
for( OsmNode wp : waypoints )
|
||||
{
|
||||
int dist = wp.calcDistance( nogo );
|
||||
if ( dist < nogo.radius
|
||||
&& (!(nogo instanceof OsmNogoPolygon)
|
||||
|| (((OsmNogoPolygon)nogo).isClosed
|
||||
? ((OsmNogoPolygon)nogo).isWithin(wp.ilon, wp.ilat)
|
||||
: ((OsmNogoPolygon)nogo).isOnPolyline(wp.ilon, wp.ilat))))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
allIn = false;
|
||||
}
|
||||
allInTotal |= allIn;
|
||||
}
|
||||
return allInTotal;
|
||||
}
|
||||
|
||||
public long[] getNogoChecksums()
|
||||
{
|
||||
long[] cs = new long[3];
|
||||
|
|
@ -297,17 +339,36 @@ public final class RoutingContext
|
|||
}
|
||||
|
||||
public void setWaypoint( OsmNodeNamed wp, boolean endpoint )
|
||||
{
|
||||
setWaypoint( wp, null, endpoint );
|
||||
}
|
||||
|
||||
public void setWaypoint( OsmNodeNamed wp, OsmNodeNamed pendingEndpoint, boolean endpoint )
|
||||
{
|
||||
keepnogopoints = nogopoints;
|
||||
nogopoints = new ArrayList<OsmNodeNamed>();
|
||||
nogopoints.add( wp );
|
||||
if ( keepnogopoints != null ) nogopoints.addAll( keepnogopoints );
|
||||
isEndpoint = endpoint;
|
||||
this.pendingEndpoint = pendingEndpoint;
|
||||
}
|
||||
|
||||
public boolean checkPendingEndpoint()
|
||||
{
|
||||
if ( pendingEndpoint != null )
|
||||
{
|
||||
isEndpoint = true;
|
||||
nogopoints.set( 0, pendingEndpoint );
|
||||
pendingEndpoint = null;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void unsetWaypoint()
|
||||
{
|
||||
nogopoints = keepnogopoints;
|
||||
pendingEndpoint = null;
|
||||
isEndpoint = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -151,9 +151,6 @@ public class RoutingEngine extends Thread
|
|||
{
|
||||
try
|
||||
{
|
||||
// delete nogos with waypoints in them
|
||||
routingContext.cleanNogolist( waypoints );
|
||||
|
||||
startTime = System.currentTimeMillis();
|
||||
long startTime0 = startTime;
|
||||
this.maxRunningTime = maxRunningTime;
|
||||
|
|
@ -459,6 +456,29 @@ public class RoutingEngine extends Thread
|
|||
}
|
||||
|
||||
private OsmTrack searchTrack( MatchedWaypoint startWp, MatchedWaypoint endWp, OsmTrack nearbyTrack, OsmTrack refTrack )
|
||||
{
|
||||
// remove nogos with waypoints inside
|
||||
try
|
||||
{
|
||||
List<OsmNode> wpts2 = new ArrayList<OsmNode>();
|
||||
wpts2.add( startWp.waypoint );
|
||||
wpts2.add( endWp.waypoint );
|
||||
boolean calcBeeline = routingContext.allInOneNogo(wpts2);
|
||||
|
||||
if ( !calcBeeline ) return searchRoutedTrack( startWp, endWp, nearbyTrack, refTrack );
|
||||
|
||||
// we want a beeline-segment
|
||||
OsmPath path = routingContext.createPath( new OsmLink( null, startWp.crosspoint ) );
|
||||
path = routingContext.createPath( path, new OsmLink( startWp.crosspoint, endWp.crosspoint ), null, false );
|
||||
return compileTrack( path, false );
|
||||
}
|
||||
finally
|
||||
{
|
||||
routingContext.restoreNogoList();
|
||||
}
|
||||
}
|
||||
|
||||
private OsmTrack searchRoutedTrack( MatchedWaypoint startWp, MatchedWaypoint endWp, OsmTrack nearbyTrack, OsmTrack refTrack )
|
||||
{
|
||||
OsmTrack track = null;
|
||||
double[] airDistanceCostFactors = new double[]{ routingContext.pass1coefficient, routingContext.pass2coefficient };
|
||||
|
|
@ -587,55 +607,27 @@ public class RoutingEngine extends Thread
|
|||
|
||||
private OsmPath getStartPath( OsmNode n1, OsmNode n2, MatchedWaypoint mwp, OsmNodeNamed endPos, boolean sameSegmentSearch )
|
||||
{
|
||||
OsmPath p = getStartPath( n1, n2, new OsmNodeNamed( mwp.waypoint ), endPos );
|
||||
if ( endPos != null )
|
||||
{
|
||||
endPos.radius = 1.5;
|
||||
}
|
||||
OsmPath p = getStartPath( n1, n2, new OsmNodeNamed( mwp.crosspoint ), endPos, sameSegmentSearch );
|
||||
|
||||
// special case: start+end on same segment
|
||||
if ( sameSegmentSearch )
|
||||
if ( p.cost >= 0 && sameSegmentSearch && endPos != null && endPos.radius < 1.5 )
|
||||
{
|
||||
OsmPath pe = getEndPath( n1, p.getLink(), endPos );
|
||||
OsmPath pt = getEndPath( n1, p.getLink(), null );
|
||||
int costdelta = pt.cost - p.cost;
|
||||
if ( pe.cost >= costdelta )
|
||||
{
|
||||
pe.cost -= costdelta;
|
||||
|
||||
if ( guideTrack != null )
|
||||
{
|
||||
// nasty stuff: combine the path cause "new OsmPath()" cannot handle start+endpoint
|
||||
OsmPathElement startElement = p.originElement;
|
||||
while( startElement.origin != null )
|
||||
{
|
||||
startElement = startElement.origin;
|
||||
}
|
||||
if ( pe.originElement.cost > costdelta )
|
||||
{
|
||||
OsmPathElement e = pe.originElement;
|
||||
while( e.origin != null && e.origin.cost > costdelta )
|
||||
{
|
||||
e = e.origin;
|
||||
e.cost -= costdelta;
|
||||
}
|
||||
e.origin = startElement;
|
||||
}
|
||||
else
|
||||
{
|
||||
pe.originElement = startElement;
|
||||
}
|
||||
}
|
||||
pe.treedepth = 0; // hack: mark for the final-check
|
||||
return pe;
|
||||
}
|
||||
p.treedepth = 0; // hack: mark for the final-check
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private OsmPath getStartPath( OsmNode n1, OsmNode n2, OsmNodeNamed wp, OsmNodeNamed endPos )
|
||||
private OsmPath getStartPath( OsmNode n1, OsmNode n2, OsmNodeNamed wp, OsmNodeNamed endPos, boolean sameSegmentSearch )
|
||||
{
|
||||
try
|
||||
{
|
||||
routingContext.setWaypoint( wp, false );
|
||||
routingContext.setWaypoint( wp, sameSegmentSearch ? endPos : null, false );
|
||||
OsmPath bestPath = null;
|
||||
OsmLink bestLink = null;
|
||||
OsmLink startLink = new OsmLink( null, n1 );
|
||||
|
|
@ -650,7 +642,7 @@ public class RoutingEngine extends Thread
|
|||
if ( nextNode == n1 ) continue; // ?
|
||||
if ( nextNode != n2 ) continue; // just that link
|
||||
|
||||
wp.radius = 1e9;
|
||||
wp.radius = 1.5;
|
||||
OsmPath testPath = routingContext.createPath( startPath, link, null, guideTrack != null );
|
||||
testPath.airdistance = endPos == null ? 0 : nextNode.calcDistance( endPos );
|
||||
if ( wp.radius < minradius )
|
||||
|
|
@ -674,29 +666,15 @@ public class RoutingEngine extends Thread
|
|||
}
|
||||
}
|
||||
|
||||
private OsmPath getEndPath( OsmNode n1, OsmLink link, OsmNodeNamed wp )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( wp != null ) routingContext.setWaypoint( wp, true );
|
||||
OsmLink startLink = new OsmLink( null, n1 );
|
||||
OsmPath startPath = routingContext.createPath( startLink );
|
||||
startLink.addLinkHolder( startPath, null );
|
||||
|
||||
if ( wp != null ) wp.radius = 1.5;
|
||||
|
||||
return routingContext.createPath( startPath, link, null, guideTrack != null );
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ( wp != null ) routingContext.unsetWaypoint();
|
||||
}
|
||||
}
|
||||
|
||||
private OsmTrack findTrack( String operationName, MatchedWaypoint startWp, MatchedWaypoint endWp, OsmTrack costCuttingTrack, OsmTrack refTrack, boolean fastPartialRecalc )
|
||||
{
|
||||
try
|
||||
{
|
||||
List<OsmNode> wpts2 = new ArrayList<OsmNode>();
|
||||
if ( startWp != null ) wpts2.add( startWp.waypoint );
|
||||
if ( endWp != null ) wpts2.add( endWp.waypoint );
|
||||
routingContext.cleanNogoList(wpts2);
|
||||
|
||||
boolean detailed = guideTrack != null;
|
||||
resetCache( detailed );
|
||||
nodesCache.nodesMap.cleanupMode = detailed ? 0 : ( routingContext.considerTurnRestrictions ? 2 : 1 );
|
||||
|
|
@ -704,6 +682,7 @@ public class RoutingEngine extends Thread
|
|||
}
|
||||
finally
|
||||
{
|
||||
routingContext.restoreNogoList();
|
||||
nodesCache.clean( false ); // clean only non-virgin caches
|
||||
}
|
||||
}
|
||||
|
|
@ -978,13 +957,16 @@ public class RoutingEngine extends Thread
|
|||
((OsmPath)linkHolder).airdistance = -1; // invalidate the entry in the open set;
|
||||
}
|
||||
|
||||
boolean isBidir = currentLink.isBidirectional();
|
||||
sourceNode.unlinkLink ( currentLink );
|
||||
|
||||
// if the counterlink is alive and does not yet have a path, remove it
|
||||
if ( isBidir && currentLink.getFirstLinkHolder( currentNode ) == null && !routingContext.considerTurnRestrictions )
|
||||
if ( path.treedepth > 1 )
|
||||
{
|
||||
currentNode.unlinkLink(currentLink);
|
||||
boolean isBidir = currentLink.isBidirectional();
|
||||
sourceNode.unlinkLink( currentLink );
|
||||
|
||||
// if the counterlink is alive and does not yet have a path, remove it
|
||||
if ( isBidir && currentLink.getFirstLinkHolder( currentNode ) == null && !routingContext.considerTurnRestrictions )
|
||||
{
|
||||
currentNode.unlinkLink( currentLink );
|
||||
}
|
||||
}
|
||||
|
||||
// recheck cutoff before doing expensive stuff
|
||||
|
|
@ -1116,7 +1098,8 @@ public class RoutingEngine extends Thread
|
|||
OsmLinkHolder dominator = link.getFirstLinkHolder( currentNode );
|
||||
while( !trafficSim && dominator != null )
|
||||
{
|
||||
if ( bestPath.definitlyWorseThan( (OsmPath)dominator, routingContext ) )
|
||||
OsmPath dp = (OsmPath)dominator;
|
||||
if ( dp.airdistance != -1 && bestPath.definitlyWorseThan( dp, routingContext ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,6 +158,27 @@ public class VoiceHint
|
|||
default : throw new IllegalArgumentException( "unknown command: " + cmd );
|
||||
}
|
||||
}
|
||||
|
||||
public int getOruxAction()
|
||||
{
|
||||
switch ( cmd )
|
||||
{
|
||||
case TU : return 1003;
|
||||
case TSHL : return 1019;
|
||||
case TL : return 1000;
|
||||
case TSLL : return 1017;
|
||||
case KL : return 1015; // ?
|
||||
case C : return 1002;
|
||||
case KR : return 1014; // ?
|
||||
case TSLR : return 1016;
|
||||
case TR : return 1001;
|
||||
case TSHR : return 1018;
|
||||
case TRU : return 1003;
|
||||
case RNDB : return 1008 + roundaboutExit;
|
||||
case RNLB : return 1008 + roundaboutExit;
|
||||
default : throw new IllegalArgumentException( "unknown command: " + cmd );
|
||||
}
|
||||
}
|
||||
|
||||
public void calcCommand()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue