-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Expand file tree
/
Copy pathgenerateLandmarks.py
More file actions
executable file
·129 lines (111 loc) · 5.65 KB
/
generateLandmarks.py
File metadata and controls
executable file
·129 lines (111 loc) · 5.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/usr/bin/env python
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
# Copyright (C) 2010-2026 German Aerospace Center (DLR) and others.
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0/
# This Source Code may also be made available under the following Secondary
# Licenses when the conditions for such availability set forth in the Eclipse
# Public License 2.0 are satisfied: GNU General Public License, version 2
# or later which is available at
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
# @file generateLandmarks.py
# @author Jakob Erdmann
# @author Mirko Barthauer
# @date 2021-11-25
"""
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 # noqa
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)