Add obstacleaccess & obstaclecost into the parameters
This commit is contained in:
parent
3b717b0dbb
commit
f1b7900b19
7 changed files with 104 additions and 43 deletions
|
@ -17,6 +17,10 @@ namespace AspectedRouting.IO.LuaSkeleton
|
|||
|
||||
internal string ToLuaWithTags(IExpression bare)
|
||||
{
|
||||
if (bare == null)
|
||||
{
|
||||
throw new NullReferenceException("bare is null");
|
||||
}
|
||||
var opt = bare.Apply(new LuaLiteral(Typs.Tags, "tags")).SpecializeToSmallestType().Optimize(out _);
|
||||
return this.ToLua(opt);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,9 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AspectedRouting.IO.LuaSkeleton;
|
||||
using AspectedRouting.IO.LuaSnippets;
|
||||
using AspectedRouting.Language;
|
||||
using AspectedRouting.Language.Functions;
|
||||
using AspectedRouting.Language.Typ;
|
||||
|
||||
namespace AspectedRouting.IO.itinero2
|
||||
|
@ -12,15 +14,9 @@ namespace AspectedRouting.IO.itinero2
|
|||
private string GenerateFactorFunction()
|
||||
{
|
||||
var parameters = new Dictionary<string, IExpression>();
|
||||
foreach (var (name, value) in _profile.DefaultParameters)
|
||||
{
|
||||
parameters[name] = value;
|
||||
}
|
||||
foreach (var (name, value) in _profile.DefaultParameters) parameters[name] = value;
|
||||
|
||||
foreach (var (name, value) in _profile.Behaviours[_behaviourName])
|
||||
{
|
||||
parameters[name] = value;
|
||||
}
|
||||
foreach (var (name, value) in _profile.Behaviours[_behaviourName]) parameters[name] = value;
|
||||
|
||||
|
||||
var aspects = new List<string>();
|
||||
|
@ -28,15 +24,9 @@ namespace AspectedRouting.IO.itinero2
|
|||
foreach (var (paramName, expr) in _profile.Priority)
|
||||
{
|
||||
var weightExpr = parameters[paramName].Evaluate(_context);
|
||||
if (!(weightExpr is double weight))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!(weightExpr is double weight)) continue;
|
||||
|
||||
if (weight == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (weight == 0) continue;
|
||||
|
||||
// The expression might still have multiple typings,
|
||||
// which take inputs different from 'Tags', so we specialize the expr first
|
||||
|
@ -45,7 +35,8 @@ namespace AspectedRouting.IO.itinero2
|
|||
.PruneTypes(tp => !(tp is Curry));
|
||||
var exprSpecialized = appliedExpr.Optimize(out _);
|
||||
|
||||
if (exprSpecialized.Types.First().Equals(Typs.Bool) || exprSpecialized.Types.First().Equals(Typs.String))
|
||||
if (exprSpecialized.Types.First().Equals(Typs.Bool) ||
|
||||
exprSpecialized.Types.First().Equals(Typs.String))
|
||||
{
|
||||
_skeleton.AddDep("parse");
|
||||
exprSpecialized = Funcs.Parse.Apply(exprSpecialized);
|
||||
|
@ -53,14 +44,12 @@ namespace AspectedRouting.IO.itinero2
|
|||
|
||||
var exprInLua = _skeleton.ToLua(exprSpecialized);
|
||||
if (exprInLua.Contains("constRight") || exprInLua.Contains("firstArg"))
|
||||
{
|
||||
throw new Exception("Not optimized properly:" + exprSpecialized.Repr());
|
||||
}
|
||||
aspects.Add(weight + " * " + exprInLua);
|
||||
}
|
||||
|
||||
Console.WriteLine(aspects.Lined());
|
||||
var code = new List<string>()
|
||||
var code = new List<string>
|
||||
{
|
||||
"--[[",
|
||||
"Generates the factor according to the priorities and the parameters for this behaviour",
|
||||
|
@ -81,8 +70,8 @@ namespace AspectedRouting.IO.itinero2
|
|||
_skeleton.AddDep("containedIn");
|
||||
_skeleton.AddDep("str_split");
|
||||
_skeleton.AddDep("calculate_turn_cost_factor");
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the turn cost factor for relation attributes or obstacles.
|
||||
Keep in mind that there are no true relations in the routerDB anymore, instead the attributes are copied onto a turn cost object.
|
||||
|
@ -97,17 +86,32 @@ If result.factor is positive, that is the cost.
|
|||
|
||||
There is no forward or backward, so this should always be the same for the same attributes
|
||||
*/
|
||||
|
||||
var code = new List<string> {
|
||||
"--[[ Function called by itinero2 on every turn restriction relation"," ]]",
|
||||
|
||||
var tags = new LuaLiteral(Typs.Tags, "attributes");
|
||||
var hasAccess = _profile.ObstacleAccess.Apply(tags).SpecializeToSmallestType().Optimize(out _);
|
||||
var code = new List<string>
|
||||
{
|
||||
"--[[ Function called by itinero2 on every turn restriction relation", " ]]",
|
||||
"function turn_cost_factor(attributes, result)",
|
||||
" result.factor = calculate_turn_cost_factor(attributes, vehicle_types)" ,
|
||||
|
||||
"local has_access",
|
||||
Snippets.Convert(_skeleton, "has_access", hasAccess),
|
||||
"if ( has_access == \"no\" or has_access == \"false\") then",
|
||||
" result.factor = -1",
|
||||
"else",
|
||||
Snippets.Convert(_skeleton, "result.factor", _profile.ObstacleCost.Apply(tags).SpecializeToSmallestType().Optimize(out _)),
|
||||
"end",
|
||||
"",
|
||||
|
||||
" -- not known by the profile or invalid value - use the default implementation",
|
||||
" if (result.factor == nil) then",
|
||||
" result.factor = calculate_turn_cost_factor(attributes, vehicle_types)",
|
||||
" end",
|
||||
"end",
|
||||
""
|
||||
};
|
||||
return code.Lined();
|
||||
}
|
||||
|
||||
|
||||
private string GenerateMainFunction()
|
||||
{
|
||||
var parameters = _profile.Behaviours[_behaviourName];
|
||||
|
|
|
@ -113,7 +113,8 @@ namespace AspectedRouting.IO.jsonParser
|
|||
var access = ParseProfileProperty(e, contextWithParameters, "access").Finalize();
|
||||
var oneway = ParseProfileProperty(e, contextWithParameters, "oneway").Finalize();
|
||||
var speed = ParseProfileProperty(e, contextWithParameters, "speed").Finalize();
|
||||
|
||||
var obstacle_access = ParseProfileProperty(e, contextWithParameters, "obstacleaccess", Funcs.Const.Apply(new Constant(new Var("any"), null))).Finalize();
|
||||
var obstacle_cost = ParseProfileProperty(e, contextWithParameters, "obstaclecost", Funcs.Const.Apply(new Constant(Typs.Double,0))).Finalize();
|
||||
|
||||
IExpression TagsApplied(IExpression x)
|
||||
{
|
||||
|
@ -171,6 +172,7 @@ namespace AspectedRouting.IO.jsonParser
|
|||
access,
|
||||
oneway,
|
||||
speed,
|
||||
obstacle_access, obstacle_cost,
|
||||
weights,
|
||||
metadata,
|
||||
lastChange
|
||||
|
|
|
@ -12,11 +12,17 @@ namespace AspectedRouting.IO.jsonParser
|
|||
{
|
||||
public static partial class JsonParser
|
||||
{
|
||||
internal static IExpression ParseProfileProperty(JsonElement e, Context c, string property)
|
||||
internal static IExpression ParseProfileProperty(JsonElement e, Context c, string property, IExpression defaultExpression = null)
|
||||
{
|
||||
if (!e.TryGetProperty(property, out var prop)) {
|
||||
throw new ArgumentException("Not a valid profile: the declaration expression for '" + property +
|
||||
"' is missing");
|
||||
if (defaultExpression == null)
|
||||
{
|
||||
throw new ArgumentException("Not a valid profile: the declaration expression for '" + property +
|
||||
"' is missing");
|
||||
}
|
||||
|
||||
Console.Error.WriteLine("WARNING: no expression defined for "+property+", using the default instead");
|
||||
return defaultExpression;
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -46,6 +52,11 @@ namespace AspectedRouting.IO.jsonParser
|
|||
if (c.ResultType is Curry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (c.ResultType is ListType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (pruned.SpecializeToSmallestType().Types.Count() != 1) {
|
||||
|
|
|
@ -28,8 +28,13 @@ namespace AspectedRouting.Language.Expression
|
|||
public IExpression Access { get; }
|
||||
public IExpression Oneway { get; }
|
||||
public IExpression Speed { get; }
|
||||
|
||||
public IExpression ObstacleAccess { get; }
|
||||
public IExpression ObstacleCost { get; }
|
||||
|
||||
public Dictionary<string, IExpression> Priority { get; }
|
||||
|
||||
|
||||
/**
|
||||
* Moment of last change of any upstream file
|
||||
*/
|
||||
|
@ -39,6 +44,7 @@ namespace AspectedRouting.Language.Expression
|
|||
List<string> vehicleTyps, Dictionary<string, IExpression> defaultParameters,
|
||||
Dictionary<string, Dictionary<string, IExpression>> behaviours,
|
||||
IExpression access, IExpression oneway, IExpression speed,
|
||||
IExpression obstacleAccess, IExpression obstacleCost,
|
||||
Dictionary<string, IExpression> priority, List<string> metadata, DateTime lastChange)
|
||||
{
|
||||
Name = name;
|
||||
|
@ -46,9 +52,11 @@ namespace AspectedRouting.Language.Expression
|
|||
Author = author;
|
||||
Filename = filename;
|
||||
VehicleTyps = vehicleTyps;
|
||||
Access = access.Optimize(out var _);
|
||||
Oneway = oneway.Optimize(out var _);
|
||||
Speed = speed.Optimize(out var _);
|
||||
Access = access.Optimize(out _);
|
||||
Oneway = oneway.Optimize(out _);
|
||||
Speed = speed.Optimize(out _);
|
||||
ObstacleAccess = obstacleAccess.Optimize(out _);
|
||||
ObstacleCost = obstacleCost.Optimize(out _);
|
||||
Priority = priority;
|
||||
Metadata = metadata;
|
||||
LastChange = lastChange;
|
||||
|
@ -58,10 +66,16 @@ namespace AspectedRouting.Language.Expression
|
|||
CheckTypes(Access, "access");
|
||||
CheckTypes(Oneway, "oneway");
|
||||
CheckTypes(Speed, "speed");
|
||||
CheckTypes(ObstacleAccess, "obstacleaccess");
|
||||
CheckTypes(ObstacleCost, "obstaclecost");
|
||||
}
|
||||
|
||||
private static void CheckTypes(IExpression e, string name)
|
||||
{
|
||||
if (e == null)
|
||||
{
|
||||
throw new Exception("No expression given for " +name);
|
||||
}
|
||||
if (e.Types.Count() == 1)
|
||||
{
|
||||
return;
|
||||
|
@ -73,11 +87,11 @@ namespace AspectedRouting.Language.Expression
|
|||
|
||||
public List<IExpression> AllExpressions(Context ctx)
|
||||
{
|
||||
var l = new List<IExpression> { Access, Oneway, Speed };
|
||||
var l = new List<IExpression> { Access, Oneway, Speed, ObstacleAccess, ObstacleCost };
|
||||
l.AddRange(DefaultParameters.Values);
|
||||
l.AddRange(Behaviours.Values.SelectMany(b => b.Values));
|
||||
l.AddRange(Priority.Values);
|
||||
|
||||
|
||||
|
||||
var allExpr = new List<IExpression>();
|
||||
allExpr.AddRange(l);
|
||||
|
@ -100,10 +114,14 @@ namespace AspectedRouting.Language.Expression
|
|||
|
||||
public List<IExpression> AllExpressionsFor(string behaviourName, Context context)
|
||||
{
|
||||
var allExpressions = new List<IExpression>();
|
||||
allExpressions.Add(Access);
|
||||
allExpressions.Add(Oneway);
|
||||
allExpressions.Add(Speed);
|
||||
var allExpressions = new List<IExpression>
|
||||
{
|
||||
Access,
|
||||
Oneway,
|
||||
Speed,
|
||||
ObstacleAccess,
|
||||
ObstacleCost
|
||||
};
|
||||
|
||||
var behaviourContext = new Context(context);
|
||||
var behaviourParameters = ParametersFor(behaviourName);
|
||||
|
|
|
@ -111,7 +111,7 @@ namespace AspectedRouting.Language.Functions
|
|||
{
|
||||
if (i >= 0)
|
||||
{
|
||||
Types = new[] { Typs.Double, Typs.Nat, Typs.Nat, Typs.PDouble };
|
||||
Types = new[] { Typs.Double, Typs.Int, Typs.Nat, Typs.PDouble };
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -24,9 +24,11 @@ Aspects can use the following (extra) tags:
|
|||
- `oneway` is a field in the vehicle file. It should be an expression returning `both`, `with` or `against`.
|
||||
When calculated, the tag `oneway` is added to the tags for the other aspects to be calculated.
|
||||
- `speed`: an expression indicating how fast the vehicle can go there. It should take into account legal, practical and social aspects. An example expression could be `{"$min", ["$legal_maxspeed", "#defaultspeed"]}`
|
||||
- `obstacleaccess` and `obstaclecost` are two (optional) expressions that calculate whether an obstacle can be passed and if so, if there is a penalty for this. See detailed explanations below
|
||||
|
||||
- `priorities`: a table of `{'#paramName', expression}` determining the priority (1/cost) of a way, per meter. The formula used is `paramName * expression + paramName0 * expression0 + ...` (`speed`, `access` and `oneway` can be used here as tags indicate the earlier defined respective aspects). Use a weight == 1 to get the shortest route or `$speed` to get the fastest route
|
||||
|
||||
|
||||
# Calculating oneway and forward/backward speeds
|
||||
|
||||
There are two possibilities in order to calculate the possible direction of a traveller can go over an edge:
|
||||
|
@ -36,9 +38,29 @@ There are two possibilities in order to calculate the possible direction of a tr
|
|||
|
||||
Note that `_direction=with` and `_direction=against` are _not_ supported in Itinero1.0 profiles. For maximal compatibility and programming comfort, a mixture of both techniques should be used. For example, one aspect interpreting the legal onewayness in tandem with one aspect determining comfort by direction is optimal.
|
||||
|
||||
# Obstacle costs
|
||||
|
||||
(Note: this only works with itinero2.0)
|
||||
|
||||
Obstacles are objects which are encountered on nodes, e.g. bollards, traffic lights but also turn restrictions.
|
||||
|
||||
The first property for this is `obstacleaccess` which calculates wether or not a vehicle can pass the obstacle.
|
||||
The possible values are:
|
||||
|
||||
- "no" of "false": the current vehicle _cannot_ pass this obstacle and should take a different route
|
||||
- "yes" or "true": the current vehicle _can_ pass this obstacle. The turn cost will be calculated
|
||||
- `null`: same as 'yes'
|
||||
|
||||
If `obstacleaccess` is not `no` or `false`, then `obstaclecost` will be triggered. This possible return values are:
|
||||
|
||||
- a positive number, indicating the cost for passing this obstacle
|
||||
- 0: there is no cost to cross this obstacle
|
||||
- null: this profile has no knowledge of a cost, will be interpreted as `0`
|
||||
|
||||
If the resulting cost is null, the default implementation will be used.
|
||||
|
||||
# Pitfalls
|
||||
|
||||
"$all" should not be used together with a mapping: it checks if all _present_ keys return true or yes (or some other value); it does _not_ check that all the specified keys in the mapping are present.
|
||||
|
||||
For this, an additional 'mustHaveKeys' should be added added
|
||||
For this, an additional 'mustHaveKeys' should be added added
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue