Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/edgesInDistricts.py
193859 views
1
#!/usr/bin/env python
2
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
# Copyright (C) 2007-2026 German Aerospace Center (DLR) and others.
4
# This program and the accompanying materials are made available under the
5
# terms of the Eclipse Public License 2.0 which is available at
6
# https://www.eclipse.org/legal/epl-2.0/
7
# This Source Code may also be made available under the following Secondary
8
# Licenses when the conditions for such availability set forth in the Eclipse
9
# Public License 2.0 are satisfied: GNU General Public License, version 2
10
# or later which is available at
11
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
14
# @file edgesInDistricts.py
15
# @author Daniel Krajzewicz
16
# @author Michael Behrisch
17
# @author Jakob Erdmann
18
# @date 2007-07-26
19
20
"""
21
Parsing a number of networks and taz (district) files with shapes
22
this script writes a taz file with all the edges which are inside
23
the relevant taz.
24
"""
25
from __future__ import print_function
26
from __future__ import absolute_import
27
import sys
28
import argparse
29
import collections
30
import sumolib
31
32
33
# written into the net. All members are "private".
34
class DistrictEdgeComputer:
35
36
def __init__(self, net):
37
self._net = net
38
self._districtEdges = collections.defaultdict(list)
39
self._edgeDistricts = collections.defaultdict(list)
40
self._invalidatedEdges = set()
41
42
def computeWithin(self, polygons, options):
43
districtBoxes = {}
44
for district in polygons:
45
if district.geo:
46
district.shape = [self._net.convertLonLat2XY(x, y) for x, y in district.shape]
47
districtBoxes[district.id] = district.getBoundingBox()
48
for idx, edge in enumerate(self._net.getEdges()):
49
shape = edge.getShape()
50
if (edge.getSpeed() < options.maxspeed and edge.getSpeed() > options.minspeed and
51
(options.internal or edge.getFunction() != "internal")):
52
if options.vclass is None or edge.allows(options.vclass):
53
if options.assign_from:
54
xmin, ymin = shape[0]
55
xmax, ymax = shape[0]
56
else:
57
xmin, ymin, xmax, ymax = edge.getBoundingBox()
58
for district in polygons:
59
dxmin, dymin, dxmax, dymax = districtBoxes[district.id]
60
if dxmin <= xmax and dymin <= ymax and dxmax >= xmin and dymax >= ymin:
61
if options.assign_from:
62
if sumolib.geomhelper.isWithin(shape[0], district.shape):
63
self._districtEdges[district].append(edge)
64
self._edgeDistricts[edge].append(district)
65
break
66
else:
67
for pos in shape:
68
if sumolib.geomhelper.isWithin(pos, district.shape):
69
self._districtEdges[
70
district].append(edge)
71
self._edgeDistricts[
72
edge].append(district)
73
break
74
if options.verbose and idx % 100 == 0:
75
sys.stdout.write("%s/%s\r" % (idx, len(self._net.getEdges())))
76
if options.complete:
77
for edge in self._edgeDistricts:
78
if len(self._edgeDistricts[edge]) > 1:
79
self._invalidatedEdges.add(edge)
80
81
def getEdgeDistrictMap(self):
82
result = {}
83
for edge, districts in self._edgeDistricts.items():
84
if len(districts) == 1:
85
result[edge] = districts[0]
86
return result
87
88
def writeResults(self, options):
89
fd = sumolib.openz(options.output, mode="w")
90
sumolib.xml.writeHeader(fd, "$Id$", "tazs", "taz_file.xsd")
91
lastId = None
92
lastEdges = set()
93
key = (lambda i: i[0].attributes[options.merge_param]) if options.merge_param else None
94
for idx, (district, edges) in enumerate(sorted(self._districtEdges.items(), key=key)):
95
filtered = [edge for edge in edges if edge not in self._invalidatedEdges and edge.getLength() >
96
options.min_length]
97
if len(filtered) == 0:
98
print("District '" + district.id + "' has no edges!")
99
else:
100
color = ' color="%s"' % district.color_str if district.color_str is not None else ''
101
if options.weighted:
102
if options.shapeinfo:
103
fd.write(' <taz id="%s" shape="%s"%s>\n' %
104
(district.id, district.getShapeString(), color))
105
else:
106
fd.write(' <taz id="%s">\n' % district.id)
107
for edge in filtered:
108
weight = edge.getSpeed() * edge.getLength()
109
fd.write(
110
' <tazSource id="%s" weight="%.2f"/>\n' % (edge.getID(), weight))
111
fd.write(
112
' <tazSink id="%s" weight="%.2f"/>\n' % (edge.getID(), weight))
113
fd.write(u" </taz>\n")
114
else:
115
if options.shapeinfo:
116
fd.write(' <taz id="%s" shape="%s"%s edges="%s"/>\n' %
117
(district.id, district.getShapeString(), color,
118
" ".join([e.getID() for e in filtered])))
119
else:
120
currentId = district.id
121
if options.merge_param is not None:
122
currentId = district.attributes[options.merge_param]
123
if options.merge_separator is not None and options.merge_separator in currentId:
124
currentId = currentId[:currentId.index(options.merge_separator)]
125
if lastId is not None:
126
if lastId == currentId:
127
lastEdges.update(filtered)
128
else:
129
fd.write(' <taz id="%s"%s edges="%s"/>\n' %
130
(lastId, color, " ".join(sorted([e.getID() for e in lastEdges]))))
131
lastId = None
132
if lastId is None:
133
lastId = currentId
134
lastEdges = set(filtered)
135
if options.verbose and idx % 100 == 0:
136
sys.stdout.write("%s/%s\r" % (idx, len(self._districtEdges)))
137
if lastId is not None:
138
fd.write(' <taz id="%s" edges="%s"/>\n' % (lastId, " ".join(sorted([e.getID() for e in lastEdges]))))
139
fd.write(u"</tazs>\n")
140
fd.close()
141
142
def getTotalLength(self, edgeID):
143
edge = self._net.getEdge(edgeID)
144
return edge.getLength() * edge.getLaneNumber()
145
146
147
def fillOptions(argParser):
148
argParser.add_argument("-v", "--verbose", category="processing", action="store_true",
149
default=False, help="tell me what you are doing")
150
argParser.add_argument("--complete", category="processing", action="store_true",
151
default=False, help="assign edges only if they are not in more than one district")
152
argParser.add_argument("-n", "--net-file", category="input",
153
help="read SUMO network from FILE (mandatory)", metavar="FILE")
154
argParser.add_argument("-t", "--taz-files", category="input",
155
help="read districts from FILEs", metavar="FILE")
156
argParser.add_argument("-o", "--output", category="output", default="districts.taz.xml",
157
help="write results to FILE", metavar="FILE")
158
argParser.add_argument("-x", "--max-speed", type=float, dest="maxspeed", category="processing",
159
default=1000.0, help="use lanes where speed is not greater than this (m/s)")
160
argParser.add_argument("-m", "--min-speed", type=float, dest="minspeed", category="processing",
161
default=0., help="use lanes where speed is greater than this (m/s)")
162
argParser.add_argument("-w", "--weighted", action="store_true", category="processing",
163
default=False, help="Weights sources/sinks by lane number and length")
164
argParser.add_argument("-f", "--assign-from", action="store_true", category="processing",
165
default=False, help="Assign the edge always to the district where the 'from' node " +
166
"is located")
167
argParser.add_argument("-i", "--internal", action="store_true", category="processing",
168
default=False, help="Include internal edges in output")
169
argParser.add_argument("-l", "--vclass", category="processing", help="Include only edges allowing VCLASS")
170
argParser.add_argument("-s", "--shapeinfo", category="processing", action="store_true",
171
default=False, help="write also the shape info in the file")
172
argParser.add_argument("--merge-separator", category="processing",
173
help="merge edge lists of taz starting with the same string up to the given separator")
174
argParser.add_argument("--merge-param", category="processing",
175
help="merge edge lists of taz/polygons having the same value for the given parameter")
176
argParser.add_argument("--min-length", type=float, category="processing",
177
default=0., help="use edges where length is greater than this (m)")
178
179
180
def parse_args(args=None):
181
argParser = sumolib.options.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
182
fillOptions(argParser)
183
return argParser.parse_args(args), argParser
184
185
186
if __name__ == "__main__":
187
options, argParser = parse_args()
188
if not options.net_file:
189
argParser.print_help()
190
argParser.exit("Error! Providing a network is mandatory")
191
192
if options.verbose:
193
print("Reading net '" + options.net_file + "'")
194
nets = options.net_file.split(",")
195
if len(nets) > 1:
196
print("Warning! Multiple networks specified. Parsing the first one for edges and tazs, the others for " +
197
"taz only.")
198
dec = DistrictEdgeComputer(sumolib.net.readNet(nets[0]))
199
tazFiles = nets + options.taz_files.split(",")
200
polygons = sumolib.shapes.polygon.read(tazFiles, includeTaz=True)
201
if options.verbose:
202
print("Calculating")
203
dec.computeWithin(polygons, options)
204
if options.verbose:
205
print("Writing results")
206
dec.writeResults(options)
207
208