forked from eclipse-sumo/sumo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtraceExporter.py
executable file
·347 lines (310 loc) · 13.8 KB
/
traceExporter.py
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
#!/usr/bin/env python
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
# Copyright (C) 2013-2021 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 traceExporter.py
# @author Daniel Krajzewicz
# @author Jakob Erdmann
# @author Michael Behrisch
# @author Evamarie Wiessner
# @date 2013-01-15
from __future__ import print_function
from __future__ import absolute_import
import os
import sys
import gzip
import random
import datetime
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'tools'))
sys.path.append(os.path.join(os.environ.get(
"SUMO_HOME", os.path.join(os.path.dirname(__file__), '..', '..')), 'tools'))
from sumolib.miscutils import getSocketStream # noqa
import sumolib.net # noqa
from sumolib.output.convert import phem, omnet, shawn, ns2, gpsdat, kml, gpx, poi, ipg, fcdfilter, keplerjson # noqa
class FCDTimeEntry:
def __init__(self, t):
self.time = t
self.vehicle = []
def disturb_gps(x, y, deviation):
if deviation == 0:
return x, y
x += random.gauss(0, deviation)
y += random.gauss(0, deviation)
return x, y
def _getOutputStream(name):
if not name:
return None
if name.endswith(".gz"):
return gzip.open(name, "wt")
return open(name, "w")
def _closeOutputStream(strm):
if strm:
strm.close()
def makeEntries(movables, chosen, options):
if options.boundary:
xmin, ymin, xmax, ymax = [float(e)
for e in options.boundary.split(",")]
result = []
negative = False
for v in movables:
if v.id not in chosen:
chosen[v.id] = random.random() < options.penetration
if chosen[v.id]:
v.x, v.y = disturb_gps(float(v.x), float(v.y), options.blur)
if v.x < 0 or v.y < 0:
if options.shift:
v.x = round(v.x + float(options.shift), 2)
v.y = round(v.y + float(options.shift), 2)
else:
negative = True
if not v.z:
v.z = 0
if not options.boundary or (v.x >= xmin and v.x <= xmax and v.y >= ymin and v.y <= ymax):
if v.lane:
v.edge = sumolib._laneID2edgeID(v.lane)
result.append(v)
return result, negative
def procFCDStream(fcdstream, options):
pt = -1 # "prior" time step
lt = -1 # "last" time step
lastExported = -1
chosen = {}
hasWarning = False
for q in fcdstream:
pt = lt
lt = sumolib.miscutils.parseTime(q.time)
if options.begin and options.begin > lt:
continue # do not export steps before a set begin
if options.end and options.end <= lt:
continue # do not export steps after a set end
if lastExported >= 0 and (options.delta and options.delta + lastExported > lt):
continue # do not export between delta-t, if set
lastExported = lt
e = FCDTimeEntry(lt)
if q.vehicle:
result, warning = makeEntries(q.vehicle, chosen, options)
e.vehicle += result
hasWarning = hasWarning or warning
if options.persons and q.person:
result, warning = makeEntries(q.person, chosen, options)
e.vehicle += result
hasWarning = hasWarning or warning
yield e
t = lt - pt + lt
if hasWarning:
print("One or more coordinates are negative, some applications might need strictly positive values. " +
"To avoid this use the option --shift.")
yield FCDTimeEntry(t)
def runMethod(inputFile, outputFile, writer, options, further={}):
further["app"] = os.path.split(__file__)[1]
further["orig-ids"] = options.orig_ids
further["ignore-gaps"] = options.ignore_gaps
if options.base >= 0:
further["base-date"] = datetime.datetime.fromtimestamp(options.base)
else:
further["base-date"] = datetime.datetime.now().replace(hour=0,
minute=0, second=0, microsecond=0)
o = _getOutputStream(outputFile)
if inputFile.isdigit():
inp = getSocketStream(int(inputFile))
else:
inp = inputFile
fcdStream = sumolib.output.parse(inp, "timestep")
ret = writer(procFCDStream(fcdStream, options), o, further)
_closeOutputStream(o)
return ret
def main(args=None):
"""The main function; parses options and converts..."""
# ---------- build and read options ----------
USAGE = """Usage %prog -i <FCDDATA> [options]
Converts the given fcd file (generated by sumo --fcd-output) into the selected
output format. Optionally the output can be sampled, filtered and distorted.
"""
from optparse import OptionParser
optParser = OptionParser(usage=USAGE)
optParser.add_option("-i", "--fcd-input", dest="fcd", metavar="FILE",
help="Defines the FCD-output file to use as input " +
"(numeric value is interpreted as port to listen on)")
optParser.add_option("-n", "--net-input", dest="net", metavar="FILE",
help="Defines the network file to use as input")
optParser.add_option("-p", "--penetration", type="float", dest="penetration",
default=1., help="Defines the percentage (0-1) of vehicles to export")
optParser.add_option("-b", "--begin", dest="begin",
type="float", help="Defines the first step to export")
optParser.add_option("-e", "--end", dest="end",
type="float", help="Defines the first step not longer to export")
optParser.add_option("-d", "--delta-t", dest="delta",
type="float", help="Defines the export step length")
optParser.add_option("--gps-blur", dest="blur", default=0,
type="float", help="Defines the GPS blur")
optParser.add_option(
"--boundary", help="Defines the bounding box as 'xmin,ymin,xmax,ymax'")
optParser.add_option("-s", "--seed", dest="seed", default=42,
type="float", help="Defines the randomizer seed")
optParser.add_option(
"--base-date", dest="base", default=-1, type="int", help="Defines the base date")
optParser.add_option("--orig-ids", dest="orig_ids", default=False, action="store_true",
help="Write original vehicle IDs instead of a running index")
optParser.add_option("--ignore-gaps", dest="ignore_gaps", default=False, action="store_true",
help="Ignore steps where a vehicle is not in the network")
optParser.add_option("--persons", default=False, action="store_true",
help="Include person data")
# PHEM
optParser.add_option("--dri-output", dest="dri", metavar="FILE",
help="Defines the name of the PHEM .dri-file to generate")
optParser.add_option("--str-output", dest="str", metavar="FILE",
help="Defines the name of the PHEM .str-file to generate")
optParser.add_option("--fzp-output", dest="fzp", metavar="FILE",
help="Defines the name of the PHEM .fzp-file to generate")
optParser.add_option("--flt-output", dest="flt", metavar="FILE",
help="Defines the name of the PHEM .flt-file to generate")
# OMNET
optParser.add_option("--omnet-output", dest="omnet", metavar="FILE",
help="Defines the name of the OMNET file to generate")
# Shawn
optParser.add_option("--shawn-output", dest="shawn", metavar="FILE",
help="Defines the name of the Shawn file to generate")
# ns2
optParser.add_option("--ns2activity-output", dest="ns2activity", metavar="FILE",
help="Defines the name of the ns2 file to generate")
optParser.add_option("--ns2config-output", dest="ns2config", metavar="FILE",
help="Defines the name of the ns2 file to generate")
optParser.add_option("--ns2mobility-output", dest="ns2mobility", metavar="FILE",
help="Defines the name of the ns2 file to generate")
# GPSDAT
optParser.add_option("--gpsdat-output", dest="gpsdat", metavar="FILE",
help="Defines the name of the gpsdat file to generate")
# KML
optParser.add_option("--kml-output", dest="kml", metavar="FILE",
help="Defines the name of the kml file to generate")
# GPX
optParser.add_option("--gpx-output", dest="gpx", metavar="FILE",
help="Defines the name of the gpx file to generate")
# POI
optParser.add_option("--poi-output", dest="poi", metavar="FILE",
help="Defines the name of the poi file to generate")
# FCD
optParser.add_option("--fcd-filter", dest="fcdfilter", metavar="FILE",
help="Defines the name of the filter definition file")
# kepler.gl JSON
optParser.add_option("--keplerjson-output", dest="keplerjson", metavar="FILE",
help="Defines the name of the kelper.gl JSON file to generate")
optParser.add_option("--fcd-filter-comment", dest="fcdcomment",
help="Extra comments to include in fcd file")
optParser.add_option("--fcd-filter-type", dest="fcdtype",
help="vehicle type to include in fcd file")
optParser.add_option("--shift", dest="shift",
help="shift coordinates to postive values only")
# IPG
optParser.add_option("--ipg-output", dest="ipg", metavar="FILE",
help="Defines the name of the ipg trace file to generate")
# parse
if len(args) == 1:
sys.exit(USAGE.replace('%prog', os.path.basename(__file__)))
options, remaining_args = optParser.parse_args(args=args)
if options.seed:
random.seed(options.seed)
# ---------- process ----------
net = None
# ----- check needed values
if options.delta and options.delta <= 0:
print("delta-t must be a positive value.")
return 1
# phem
if (options.dri or options.fzp or options.flt) and not options.fcd:
print("A fcd-output from SUMO must be given using the --fcd-input.")
return 1
if (options.str or options.fzp or options.flt) and not options.net:
print("A SUMO network must be given using the --net-input option.")
return 1
# omnet
if options.omnet and not options.fcd:
print("A fcd-output from SUMO must be given using the --fcd-input.")
return 1
# ----- check needed values
# ----- OMNET
if options.omnet:
runMethod(options.fcd, options.omnet, omnet.fcd2omnet, options)
# ----- OMNET
# ----- Shawn
if options.shawn:
runMethod(options.fcd, options.shawn, shawn.fcd2shawn, options)
# ----- Shawn
# ----- GPSDAT
if options.gpsdat:
runMethod(options.fcd, options.gpsdat, gpsdat.fcd2gpsdat, options)
# ----- GPSDAT
# ----- KML
if options.kml:
runMethod(options.fcd, options.kml, kml.fcd2kml, options)
# ----- KML
# ----- GPX
if options.gpx:
runMethod(options.fcd, options.gpx, gpx.fcd2gpx, options)
# ----- GPX
# ----- POI
if options.poi:
runMethod(options.fcd, options.poi, poi.fcd2poi, options)
# ----- POI
# ----- FCD
if options.fcdfilter:
runMethod(options.fcd, None, fcdfilter.fcdfilter, options,
{"filter": options.fcdfilter, "comment": options.fcdcomment, "type": options.fcdtype})
# ----- FCD
# ----- kepler.gl JSON
if options.keplerjson:
runMethod(options.fcd, options.keplerjson, keplerjson.fcd2keplerjson, options)
# ----- kepler.gl JSON
# ----- ns2
if options.ns2mobility or options.ns2config or options.ns2activity:
vIDm, vehInfo, begin, end, area = runMethod(
options.fcd, options.ns2mobility, ns2.fcd2ns2mobility, options)
if options.ns2activity:
o = _getOutputStream(options.ns2activity)
ns2.writeNS2activity(o, vehInfo)
_closeOutputStream(o)
if options.ns2config:
o = _getOutputStream(options.ns2config)
ns2.writeNS2config(
o, vehInfo, options.ns2activity, options.ns2mobility, begin, end, area)
_closeOutputStream(o)
# ----- ns2
# ----- PHEM
# .dri
if options.dri:
runMethod(options.fcd, options.dri, phem.fcd2dri, options)
# .str (we need the net for other outputs, too)
if options.str or options.fzp or options.flt:
if not options.net:
print("A SUMO network must be given using the --net-input option.")
return 1
if not net:
net = sumolib.net.readNet(options.net)
o = _getOutputStream(options.str)
sIDm = phem.net2str(net, o)
_closeOutputStream(o)
# .fzp
if options.flt or options.fzp:
vIDm, vtIDm = runMethod(
options.fcd, options.fzp, phem.fcd2fzp, options, {"phemStreetMap": sIDm})
# .flt
if options.flt:
o = _getOutputStream(options.flt)
phem.vehicleTypes2flt(o, vtIDm)
_closeOutputStream(o)
# ----- PHEM
# ----- IPG
if options.ipg:
runMethod(options.fcd, options.ipg, ipg.fcd2ipg, options)
# ----- IPG
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))