"""
Create a landmark table input file for generating a full table duarouter options
--astar.landmark-distances --astar.save-landmark-distances
for a given netfile and with a given number of landmarks
The landmarks are somewhat evenly spaced around the rim of the network
"""
from __future__ import print_function
from __future__ import absolute_import
import os
import sys
import random
from math import pi, degrees
if 'SUMO_HOME' in os.environ:
sys.path.append(os.path.join(os.environ['SUMO_HOME'], 'tools'))
import sumolib
def get_options(args=None):
optParser = sumolib.options.ArgumentParser(description="Generate random boundary landmarks for a given network")
optParser.add_argument("-n", "--net-file", category="input", dest="netfile", required=True,
help="define the net file (mandatory)")
optParser.add_argument("-o", "--output-file", category="output", dest="outfile",
default="landmarks.txt", help="define the output filename")
optParser.add_argument("--selection-output", category="output", dest="selout",
help="Write a selection file for visualization")
optParser.add_argument("-N", "--number", category="processing", type=int, default=10,
help="Define number of landmarks to generate")
optParser.add_argument("--geo", category="processing", action="store_true", default=False,
help="Store landmarks as geo-coordinates instead of edge IDs")
optParser.add_argument("-d", "--no-deadends", category="processing", action="store_true", default=False,
dest="noDeadends",
help="Only use edges that have at least one follower and one successor")
optParser.add_argument("-p", "--min-priority", category="processing", type=int, default=-10, dest="minPrio",
help="Only use edges with priority of at least INT")
optParser.add_argument("-s", "--seed", category="processing", type=int, default=42, help="random seed")
optParser.add_argument("--random", category="processing", action="store_true", default=False,
help="use a random seed to initialize the random number generator")
optParser.add_argument("--vclass", category="processing", default="passenger",
help="only use edges which permit the given vehicle class")
optParser.add_argument("-v", "--verbose", category="processing", action="store_true",
default=False, help="tell me what you are doing")
return optParser.parse_args(args=args)
def filterEdges(options, edges):
return [e for e in edges if (
e.getPriority() >= options.minPrio
and e.allows(options.vclass)
and (not options.noDeadends or (e.getAllowedOutgoing(options.vclass) and e.getIncoming())))]
def getAngles(net, edges):
"""compute angle towards network center and sort edges by this angle"""
xmin, ymin, xmax, ymax = net.getBoundary()
center = ((xmin + xmax) / 2, (ymin + ymax) / 2)
result = []
for e in edges:
pos = e.getToNode().getCoord()
angle = sumolib.geomhelper.angleTo2D(center, pos)
dist = sumolib.geomhelper.distance(center, pos)
result.append((angle, dist, e))
result.sort(key=lambda x: x[0:2])
return result
def main(options):
if not options.random:
random.seed(options.seed)
net = sumolib.net.readNet(options.netfile)
if options.geo and not net.hasGeoProj():
print("Network does not provide geo-projection. Option --geo cannot be used", file=sys.stderr)
sys.exit(1)
edges = filterEdges(options, net.getEdges())
edgeAngles = getAngles(net, edges)
angleSteps = [-pi + (i + 1) * 2 * pi / options.number for i in range(options.number)]
i = 0
landmarks = []
aPrev = -pi
for a in angleSteps:
edgeDistances = []
while i < len(edgeAngles) and edgeAngles[i][0] < a:
edgeDistances.append(edgeAngles[i][1:])
i += 1
if edgeDistances:
edgeDistances.sort(key=lambda x: x[0])
landmarks.append(edgeDistances[-1][1])
else:
print("Found no edges between angles %.0f and %0.f" % (degrees(aPrev), degrees(a)), file=sys.stderr)
aPrev = a
with open(options.outfile, 'w') as outf:
for e in landmarks:
if options.geo:
x, y = sumolib.geomhelper.positionAtShapeOffset(e.getShape(), e.getLength() / 2)
outf.write("%f %f\n" % net.convertXY2LonLat(x, y))
else:
outf.write("%s\n" % e.getID())
if options.selout:
with open(options.selout, 'w') as outf:
for e in landmarks:
outf.write("edge:%s\n" % e.getID())
if __name__ == "__main__":
if not main(get_options()):
sys.exit(1)