Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/guisim/GUINet.cpp
193677 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-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 GUINet.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Michael Behrisch
18
/// @author Laura Bieker
19
/// @date Sept 2002
20
///
21
// A MSNet extended by some values for usage within the gui
22
/****************************************************************************/
23
#include <config.h>
24
25
#include <utility>
26
#include <set>
27
#include <vector>
28
#include <map>
29
#include <utils/shapes/ShapeContainer.h>
30
#include <utils/gui/globjects/GUIPolygon.h>
31
#include <utils/gui/globjects/GUIPointOfInterest.h>
32
#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
33
#include <utils/gui/div/GUIDesigns.h>
34
#include <utils/gui/div/GUIParameterTableWindow.h>
35
#include <utils/gui/div/GUIGlobalSelection.h>
36
#include <utils/gui/globjects/GUIShapeContainer.h>
37
#include <utils/xml/XMLSubSys.h>
38
#include <utils/common/MsgHandler.h>
39
#include <utils/common/StringUtils.h>
40
#include <utils/common/RGBColor.h>
41
#include <utils/iodevices/OutputDevice.h>
42
#include <utils/gui/div/GLObjectValuePassConnector.h>
43
#include <microsim/MSNet.h>
44
#include <microsim/MSEdgeWeightsStorage.h>
45
#include <microsim/MSJunction.h>
46
#include <microsim/output/MSDetectorControl.h>
47
#include <microsim/MSEdge.h>
48
#include <microsim/transportables/MSPModel.h>
49
#include <microsim/MSInsertionControl.h>
50
#include <microsim/traffic_lights/MSTrafficLightLogic.h>
51
#include <microsim/traffic_lights/MSTLLogicControl.h>
52
#include <microsim/MSJunctionControl.h>
53
#include <guisim/Command_Hotkey_TrafficLight.h>
54
#include <guisim/GUIEdge.h>
55
#include <guisim/GUILane.h>
56
#include <guisim/GUITransportableControl.h>
57
#include <guisim/GUILaneSpeedTrigger.h>
58
#include <guisim/GUIDetectorWrapper.h>
59
#include <guisim/GUICalibrator.h>
60
#include <guisim/GUITrafficLightLogicWrapper.h>
61
#include <guisim/GUIJunctionWrapper.h>
62
#include <guisim/GUIVehicleControl.h>
63
#include <gui/GUIGlobals.h>
64
#include <gui/GUIApplicationWindow.h>
65
#include "GUINet.h"
66
67
#include <mesogui/GUIMEVehicleControl.h>
68
69
70
// ===========================================================================
71
// definition of static variables used for visualisation of objects' values
72
// ===========================================================================
73
template std::vector< GLObjectValuePassConnector<double>* > GLObjectValuePassConnector<double>::myContainer;
74
template FXMutex GLObjectValuePassConnector<double>::myLock;
75
76
template std::vector< GLObjectValuePassConnector<std::pair<int, class MSPhaseDefinition> >* > GLObjectValuePassConnector<std::pair<int, class MSPhaseDefinition> >::myContainer;
77
template FXMutex GLObjectValuePassConnector<std::pair<int, class MSPhaseDefinition> >::myLock;
78
79
80
// ===========================================================================
81
// member method definitions
82
// ===========================================================================
83
GUINet::GUINet(MSVehicleControl* vc, MSEventControl* beginOfTimestepEvents,
84
MSEventControl* endOfTimestepEvents,
85
MSEventControl* insertionEvents) :
86
MSNet(vc, beginOfTimestepEvents, endOfTimestepEvents, insertionEvents, new GUIShapeContainer(myGrid)),
87
GUIGlObject(GLO_NETWORK, "", nullptr),
88
myLastSimDuration(0), /*myLastVisDuration(0),*/ myLastIdleDuration(0),
89
myLastVehicleMovementCount(0), myOverallVehicleCount(0), myOverallSimDuration(0) {
90
GUIGlObjectStorage::gIDStorage.setNetObject(this);
91
}
92
93
94
GUINet::~GUINet() {
95
if (myLock.locked()) {
96
myLock.unlock();
97
}
98
// delete allocated wrappers
99
// of junctions
100
for (std::vector<GUIJunctionWrapper*>::iterator i1 = myJunctionWrapper.begin(); i1 != myJunctionWrapper.end(); i1++) {
101
delete (*i1);
102
}
103
// of additional structures
104
GUIGlObject_AbstractAdd::clearDictionary();
105
// of tl-logics
106
for (Logics2WrapperMap::iterator i3 = myLogics2Wrapper.begin(); i3 != myLogics2Wrapper.end(); i3++) {
107
delete (*i3).second;
108
}
109
// of detectors
110
for (std::vector<GUIDetectorWrapper*>::iterator i = myDetectorWrapper.begin(); i != myDetectorWrapper.end(); ++i) {
111
delete *i;
112
}
113
// of calibrators
114
for (GUICalibrator* cw : myCalibratorWrapper) {
115
delete cw;
116
}
117
for (auto& item : myLoadedEdgeData) {
118
delete item.second;
119
}
120
}
121
122
123
const Boundary&
124
GUINet::getBoundary() const {
125
return myBoundary;
126
}
127
128
129
MSTransportableControl&
130
GUINet::getPersonControl() {
131
if (myPersonControl == nullptr) {
132
myPersonControl = new GUITransportableControl(true);
133
}
134
return *myPersonControl;
135
}
136
137
138
MSTransportableControl&
139
GUINet::getContainerControl() {
140
if (myContainerControl == nullptr) {
141
myContainerControl = new GUITransportableControl(false);
142
}
143
return *myContainerControl;
144
}
145
146
147
void
148
GUINet::initTLMap() {
149
// go through the loaded tl-logics
150
for (MSTrafficLightLogic* const tll : getTLSControl().getAllLogics()) {
151
createTLWrapper(tll);
152
}
153
}
154
155
156
void
157
GUINet::createTLWrapper(MSTrafficLightLogic* tll) {
158
if (myLogics2Wrapper.count(tll) > 0) {
159
return;
160
}
161
// get the links
162
const MSTrafficLightLogic::LinkVectorVector& links = tll->getLinks();
163
if (links.size() == 0) { // @legacy this should never happen in 0.13.0+ networks
164
return;
165
}
166
// build the wrapper
167
GUITrafficLightLogicWrapper* tllw = new GUITrafficLightLogicWrapper(*myLogics, *tll);
168
if (tll->hasParameter("hotkeyAbort")) {
169
Command_Hotkey_TrafficLight::registerHotkey(tll->getParameter("hotkeyAbort"), *tll);
170
}
171
// build the association link->wrapper
172
MSTrafficLightLogic::LinkVectorVector::const_iterator j;
173
for (j = links.begin(); j != links.end(); ++j) {
174
MSTrafficLightLogic::LinkVector::const_iterator j2;
175
for (j2 = (*j).begin(); j2 != (*j).end(); ++j2) {
176
myLinks2Logic[*j2] = tll->getID();
177
}
178
}
179
myGrid.addAdditionalGLObject(tllw);
180
myLogics2Wrapper[tll] = tllw;
181
}
182
183
184
Position
185
GUINet::getJunctionPosition(const std::string& name) const {
186
// !!! no check for existance!
187
return myJunctions->get(name)->getPosition();
188
}
189
190
191
bool
192
GUINet::vehicleExists(const std::string& name) const {
193
return myVehicleControl->getVehicle(name) != nullptr;
194
}
195
196
197
int
198
GUINet::getLinkTLID(const MSLink* const link) const {
199
if (myLinks2Logic.count(link) == 0) {
200
//assert(false);
201
return 0;
202
}
203
MSTrafficLightLogic* tll = myLogics->getActive(myLinks2Logic.find(link)->second);
204
if (myLogics2Wrapper.count(tll) == 0) {
205
// tll may have been added via traci. @see ticket #459
206
return 0;
207
}
208
return myLogics2Wrapper.find(tll)->second->getGlID();
209
}
210
211
212
int
213
GUINet::getLinkTLIndex(const MSLink* const link) const {
214
Links2LogicMap::const_iterator i = myLinks2Logic.find(link);
215
if (i == myLinks2Logic.end()) {
216
return -1;
217
}
218
if (myLogics2Wrapper.find(myLogics->getActive((*i).second)) == myLogics2Wrapper.end()) {
219
return -1;
220
}
221
return myLogics2Wrapper.find(myLogics->getActive((*i).second))->second->getLinkIndex(link);
222
}
223
224
225
GUITrafficLightLogicWrapper*
226
GUINet::getTLLWrapper(MSTrafficLightLogic* tll) {
227
if (myLogics2Wrapper.find(tll) == myLogics2Wrapper.end()) {
228
return nullptr;
229
}
230
return myLogics2Wrapper.find(tll)->second;
231
}
232
233
234
void
235
GUINet::guiSimulationStep() {
236
GLObjectValuePassConnector<double>::updateAll();
237
GLObjectValuePassConnector<std::pair<SUMOTime, MSPhaseDefinition> >::updateAll();
238
}
239
240
241
void
242
GUINet::simulationStep() {
243
FXMutexLock locker(myLock);
244
MSNet::simulationStep();
245
}
246
247
248
std::vector<GUIGlID>
249
GUINet::getJunctionIDs(bool includeInternal) const {
250
std::vector<GUIGlID> ret;
251
for (std::vector<GUIJunctionWrapper*>::const_iterator i = myJunctionWrapper.begin(); i != myJunctionWrapper.end(); ++i) {
252
if (!(*i)->isInternal() || includeInternal) {
253
ret.push_back((*i)->getGlID());
254
}
255
}
256
return ret;
257
}
258
259
260
std::vector<GUIGlID>
261
GUINet::getTLSIDs() const {
262
std::vector<GUIGlID> ret;
263
std::vector<std::string> ids;
264
for (std::map<MSTrafficLightLogic*, GUITrafficLightLogicWrapper*>::const_iterator i = myLogics2Wrapper.begin(); i != myLogics2Wrapper.end(); ++i) {
265
std::string sid = (*i).second->getMicrosimID();
266
if (find(ids.begin(), ids.end(), sid) == ids.end()) {
267
ret.push_back((*i).second->getGlID());
268
ids.push_back(sid);
269
}
270
}
271
return ret;
272
}
273
274
275
void
276
GUINet::initGUIStructures() {
277
// initialise detector storage for gui
278
const std::vector<SumoXMLTag> types = myDetectorControl->getAvailableTypes();
279
for (std::vector<SumoXMLTag>::const_iterator i = types.begin(); i != types.end(); ++i) {
280
for (const auto& j : myDetectorControl->getTypedDetectors(*i)) {
281
GUIDetectorWrapper* wrapper = j.second->buildDetectorGUIRepresentation();
282
if (wrapper != nullptr) {
283
myDetectorWrapper.push_back(wrapper);
284
myGrid.addAdditionalGLObject(wrapper);
285
}
286
}
287
}
288
// let's always track emission parameters for the GUI
289
MSGlobals::gHaveEmissions = true;
290
// initialise calibrators
291
for (auto& item : MSCalibrator::getInstances()) {
292
GUICalibrator* wrapper = new GUICalibrator(item.second);
293
myCalibratorWrapper.push_back(wrapper);
294
myGrid.addAdditionalGLObject(wrapper);
295
}
296
// initialise the tl-map
297
initTLMap();
298
// initialise edge storage for gui
299
const MSEdgeVector& edges = MSEdge::getAllEdges();
300
myEdgeWrapper.reserve(edges.size());
301
for (MSEdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) {
302
// VISIM connector edges shall be drawn (they have lanes)
303
if (!(*i)->isTazConnector() || (*i)->getLanes().size() > 0) {
304
myEdgeWrapper.push_back(static_cast<GUIEdge*>(*i));
305
}
306
}
307
// initialise junction storage for gui
308
int size = myJunctions->size();
309
myJunctionWrapper.reserve(size);
310
std::map<MSJunction*, std::string> junction2TLL;
311
for (const auto tls : getTLSControl().getAllLogics()) {
312
for (const auto& links : tls->getLinks()) {
313
for (const MSLink* l : links) {
314
junction2TLL[l->getJunction()] = l->getTLLogic()->getID();
315
}
316
}
317
}
318
for (const auto& i : *myJunctions) {
319
myJunctionWrapper.push_back(new GUIJunctionWrapper(*i.second, junction2TLL[i.second]));
320
}
321
// build the visualization tree
322
for (std::vector<GUIEdge*>::iterator i = myEdgeWrapper.begin(); i != myEdgeWrapper.end(); ++i) {
323
GUIEdge* edge = *i;
324
Boundary b;
325
const std::vector<MSLane*>& lanes = edge->getLanes();
326
for (std::vector<MSLane*>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
327
b.add((*j)->getShape().getBoxBoundary());
328
}
329
// make sure persons are always drawn and selectable since they depend on their edge being drawn
330
b.grow(MSPModel::SIDEWALK_OFFSET + 1 + lanes.front()->getWidth() / 2);
331
const float cmin[2] = { (float)b.xmin(), (float)b.ymin() };
332
const float cmax[2] = { (float)b.xmax(), (float)b.ymax() };
333
myGrid.Insert(cmin, cmax, edge);
334
myBoundary.add(b);
335
if (myBoundary.getWidth() > 10e16 || myBoundary.getHeight() > 10e16) {
336
throw ProcessError(TL("Network size exceeds 1 Lightyear. Please reconsider your inputs.\n"));
337
}
338
}
339
for (std::vector<GUIJunctionWrapper*>::iterator i = myJunctionWrapper.begin(); i != myJunctionWrapper.end(); ++i) {
340
GUIJunctionWrapper* junction = *i;
341
Boundary b = junction->getBoundary();
342
b.grow(2.);
343
const float cmin[2] = { (float)b.xmin(), (float)b.ymin() };
344
const float cmax[2] = { (float)b.xmax(), (float)b.ymax() };
345
myGrid.Insert(cmin, cmax, junction);
346
myBoundary.add(b);
347
}
348
myGrid.add(myBoundary);
349
350
if (OptionsCont::getOptions().isSet("alternative-net-file")) {
351
// build secondary visualization tree
352
for (GUIEdge* edge : myEdgeWrapper) {
353
Boundary b;
354
for (MSLane* lane : edge->getLanes()) {
355
b.add(static_cast<GUILane*>(lane)->getShape(true).getBoxBoundary());
356
}
357
// make sure persons are always drawn and selectable since they depend on their edge being drawn
358
b.grow(MSPModel::SIDEWALK_OFFSET + 1);
359
const float cmin[2] = { (float)b.xmin(), (float)b.ymin() };
360
const float cmax[2] = { (float)b.xmax(), (float)b.ymax() };
361
myGrid2.Insert(cmin, cmax, edge);
362
}
363
for (std::vector<GUIJunctionWrapper*>::iterator i = myJunctionWrapper.begin(); i != myJunctionWrapper.end(); ++i) {
364
GUIJunctionWrapper* junction = *i;
365
Position pos = junction->getJunction().getPosition(true);
366
Boundary b = Boundary(pos.x() - 3., pos.y() - 3., pos.x() + 3., pos.y() + 3.);
367
const float cmin[2] = { (float)b.xmin(), (float)b.ymin() };
368
const float cmax[2] = { (float)b.xmax(), (float)b.ymax() };
369
myGrid2.Insert(cmin, cmax, junction);
370
}
371
}
372
}
373
374
375
void
376
GUINet::registerRenderedObject(GUIGlObject* o) {
377
getVisualisationSpeedUp().addAdditionalGLObject(o);
378
if (OptionsCont::getOptions().isSet("alternative-net-file")) {
379
GUIGlobals::gSecondaryShape = true;
380
myGrid2.addAdditionalGLObject(o);
381
GUIGlobals::gSecondaryShape = false;
382
}
383
}
384
385
386
int
387
GUINet::getWholeDuration() const {
388
return myLastSimDuration +/*myLastVisDuration+*/myLastIdleDuration;
389
}
390
391
392
int
393
GUINet::getSimDuration() const {
394
return myLastSimDuration;
395
}
396
397
/*
398
int
399
GUINet::getVisDuration() const
400
{
401
return myLastVisDuration;
402
}
403
*/
404
405
406
double
407
GUINet::getRTFactor() const {
408
if (myLastSimDuration == 0) {
409
return -1;
410
}
411
return (double)DELTA_T / (double)myLastSimDuration;
412
}
413
414
415
double
416
GUINet::getUPS() const {
417
if (myLastSimDuration == 0) {
418
return -1;
419
}
420
return (double) myLastVehicleMovementCount / (double) myLastSimDuration * (double) 1000.;
421
}
422
423
424
double
425
GUINet::getMeanRTFactor(int duration) const {
426
if (myOverallSimDuration == 0) {
427
return -1;
428
}
429
return ((double)(duration) * (double) 1000. / (double)myOverallSimDuration);
430
}
431
432
433
double
434
GUINet::getMeanUPS() const {
435
if (myOverallSimDuration == 0) {
436
return -1;
437
}
438
return ((double)myVehiclesMoved / (double)myOverallSimDuration * (double) 1000.);
439
}
440
441
442
int
443
GUINet::getIdleDuration() const {
444
return myLastIdleDuration;
445
}
446
447
448
void
449
GUINet::setSimDuration(int val) {
450
myLastSimDuration = val;
451
myOverallSimDuration += val;
452
myLastVehicleMovementCount = getVehicleControl().getRunningVehicleNo();
453
myOverallVehicleCount += myLastVehicleMovementCount;
454
}
455
456
/*
457
void
458
GUINet::setVisDuration(int val)
459
{
460
myLastVisDuration = val;
461
}
462
*/
463
464
void
465
GUINet::setIdleDuration(int val) {
466
myLastIdleDuration = val;
467
}
468
469
470
GUIGLObjectPopupMenu*
471
GUINet::getPopUpMenu(GUIMainWindow& app,
472
GUISUMOAbstractView& parent) {
473
GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
474
buildPopupHeader(ret, app);
475
buildCenterPopupEntry(ret);
476
buildShowParamsPopupEntry(ret);
477
buildPositionCopyEntry(ret, app);
478
if (GeoConvHelper::getFinal().usingGeoProjection()) {
479
GUIDesigns::buildFXMenuCommand(ret, TL("Copy view geo-boundary to clipboard"), nullptr, ret, MID_COPY_VIEW_GEOBOUNDARY);
480
}
481
return ret;
482
}
483
484
485
GUIParameterTableWindow*
486
GUINet::getParameterWindow(GUIMainWindow& app,
487
GUISUMOAbstractView& parent) {
488
GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
489
// add items
490
ret->mkItem(TL("loaded vehicles [#]"), true,
491
new FunctionBinding<MSVehicleControl, int>(&getVehicleControl(), &MSVehicleControl::getLoadedVehicleNo));
492
ret->mkItem(TL("insertion-backlogged vehicles [#]"), true,
493
new FunctionBinding<MSInsertionControl, int>(&getInsertionControl(), &MSInsertionControl::getWaitingVehicleNo));
494
ret->mkItem(TL("departed vehicles [#]"), true,
495
new FunctionBinding<MSVehicleControl, int>(&getVehicleControl(), &MSVehicleControl::getDepartedVehicleNo));
496
ret->mkItem(TL("running vehicles [#]"), true,
497
new FunctionBinding<MSVehicleControl, int>(&getVehicleControl(), &MSVehicleControl::getRunningVehicleNo));
498
ret->mkItem(TL("arrived vehicles [#]"), true,
499
new FunctionBinding<MSVehicleControl, int>(&getVehicleControl(), &MSVehicleControl::getArrivedVehicleNo));
500
ret->mkItem(TL("discarded vehicles [#]"), true,
501
new FunctionBinding<MSVehicleControl, int>(&getVehicleControl(), &MSVehicleControl::getDiscardedVehicleNo));
502
ret->mkItem(TL("collisions [#]"), true,
503
new FunctionBinding<MSVehicleControl, int>(&getVehicleControl(), &MSVehicleControl::getCollisionCount));
504
ret->mkItem(TL("teleports [#]"), true,
505
new FunctionBinding<MSVehicleControl, int>(&getVehicleControl(), &MSVehicleControl::getTeleportCount));
506
ret->mkItem(TL("halting [#]"), true,
507
new FunctionBinding<MSVehicleControl, int>(&getVehicleControl(), &MSVehicleControl::getHaltingVehicleNo));
508
ret->mkItem(TL("stopped [#]"), true,
509
new FunctionBinding<MSVehicleControl, int>(&getVehicleControl(), &MSVehicleControl::getStoppedVehiclesCount));
510
ret->mkItem(TL("avg. speed [m/s]"), true,
511
new FunctionBinding<MSVehicleControl, double>(&getVehicleControl(), &MSVehicleControl::getVehicleMeanSpeed));
512
ret->mkItem(TL("avg. relative speed"), true,
513
new FunctionBinding<MSVehicleControl, double>(&getVehicleControl(), &MSVehicleControl::getVehicleMeanSpeedRelative));
514
if (myPersonControl != nullptr) {
515
ret->mkItem(TL("loaded persons [#]"), true,
516
new FunctionBinding<MSTransportableControl, int>(&getPersonControl(), &MSTransportableControl::getLoadedNumber));
517
ret->mkItem(TL("running persons [#]"), true,
518
new FunctionBinding<MSTransportableControl, int>(&getPersonControl(), &MSTransportableControl::getRunningNumber));
519
ret->mkItem(TL("jammed persons [#]"), true,
520
new FunctionBinding<MSTransportableControl, int>(&getPersonControl(), &MSTransportableControl::getJammedNumber));
521
}
522
ret->mkItem(TL("end time [s]"), false, OptionsCont::getOptions().getString("end"));
523
ret->mkItem(TL("begin time [s]"), false, OptionsCont::getOptions().getString("begin"));
524
// ret->mkItem(TL("time step [s]"), true, new FunctionBinding<GUINet, SUMOTime>(this, &GUINet::getCurrentTimeStep));
525
if (logSimulationDuration()) {
526
ret->mkItem(TL("step duration [ms]"), true, new FunctionBinding<GUINet, int>(this, &GUINet::getWholeDuration));
527
ret->mkItem(TL("FPS"), true, new FunctionBinding<GUISUMOAbstractView, double>(&parent, &GUISUMOAbstractView::getFPS));
528
ret->mkItem(TL("simulation duration [ms]"), true, new FunctionBinding<GUINet, int>(this, &GUINet::getSimDuration));
529
/*
530
ret->mkItem(TL("visualisation duration [ms]"), true,
531
new CastingFunctionBinding<GUINet, double, int>(
532
&(getNet()), &GUINet::getVisDuration));
533
*/
534
ret->mkItem(TL("idle duration [ms]"), true, new FunctionBinding<GUINet, int>(this, &GUINet::getIdleDuration));
535
ret->mkItem(TL("duration factor"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getRTFactor));
536
/*
537
ret->mkItem(TL("mean duration factor []"), true,
538
new FuncBinding_IntParam<GUINet, double>(
539
&(getNet()), &GUINet::getMeanRTFactor), 1);
540
*/
541
ret->mkItem(TL("updates per second"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getUPS));
542
ret->mkItem(TL("avg. updates per second"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getMeanUPS));
543
}
544
if (OptionsCont::getOptions().isSet("tripinfo-output") || OptionsCont::getOptions().getBool("duration-log.statistics")) {
545
ret->mkItem(TL("avg. trip length [m]"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getAvgRouteLength));
546
ret->mkItem(TL("avg. trip duration [s]"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getAvgDuration));
547
ret->mkItem(TL("avg. trip waiting time [s]"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getAvgWaitingTime));
548
ret->mkItem(TL("avg. trip time loss [s]"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getAvgTimeLoss));
549
ret->mkItem(TL("avg. trip depart delay [s]"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getAvgDepartDelay));
550
ret->mkItem(TL("avg. trip speed [m/s]"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getAvgTripSpeed));
551
if (myPersonControl != nullptr) {
552
ret->mkItem(TL("avg. walk length [m]"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getAvgWalkRouteLength));
553
ret->mkItem(TL("avg. walk duration [s]"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getAvgWalkDuration));
554
ret->mkItem(TL("avg. walk time loss [s]"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getAvgWalkTimeLoss));
555
}
556
}
557
ret->mkItem(TL("nodes [#]"), false, (int)getJunctionIDs(false).size());
558
ret->mkItem(TL("edges [#]"), false, (int)GUIEdge::getIDs(false).size());
559
ret->mkItem(TL("total edge length [km]"), false, GUIEdge::getTotalLength(false, false) / 1000);
560
ret->mkItem(TL("total lane length [km]"), false, GUIEdge::getTotalLength(false, true) / 1000);
561
ret->mkItem(TL("network version "), false, toString(myVersion));
562
563
// close building
564
ret->closeBuilding();
565
return ret;
566
}
567
568
569
void
570
GUINet::drawGL(const GUIVisualizationSettings& /*s*/) const {
571
}
572
573
574
Boundary
575
GUINet::getCenteringBoundary() const {
576
return getBoundary();
577
}
578
579
580
GUINet*
581
GUINet::getGUIInstance() {
582
GUINet* net = dynamic_cast<GUINet*>(MSNet::getInstance());
583
if (net != nullptr) {
584
return net;
585
}
586
throw ProcessError("A gui-network was not yet constructed.");
587
}
588
589
590
GUIVehicleControl*
591
GUINet::getGUIVehicleControl() {
592
return dynamic_cast<GUIVehicleControl*>(myVehicleControl);
593
}
594
595
596
void
597
GUINet::lock() {
598
myLock.lock();
599
}
600
601
602
void
603
GUINet::unlock() {
604
myLock.unlock();
605
}
606
607
GUIMEVehicleControl*
608
GUINet::getGUIMEVehicleControl() {
609
return dynamic_cast<GUIMEVehicleControl*>(myVehicleControl);
610
}
611
612
613
double
614
GUINet::getEdgeData(const MSEdge* edge, const std::string& attr) {
615
auto it = myLoadedEdgeData.find(attr);
616
if (it != myLoadedEdgeData.end()) {
617
double value;
618
bool found = it->second->retrieveExistingEffort(edge, STEPS2TIME(getCurrentTimeStep()), value);
619
if (found) {
620
return value;
621
} else {
622
return GUIVisualizationSettings::MISSING_DATA;
623
}
624
} else {
625
return GUIVisualizationSettings::MISSING_DATA;
626
}
627
}
628
629
630
double
631
GUINet::getMeanData(const MSLane* lane, const std::string& id, const std::string& attr) {
632
auto item = myDetectorControl->getMeanData().find(id);
633
if (item != myDetectorControl->getMeanData().end() && !item->second.empty()) {
634
SumoXMLAttr a = (SumoXMLAttr)SUMOXMLDefinitions::Attrs.get(attr);
635
return item->second.front()->getAttributeValue(lane, a, GUIVisualizationSettings::MISSING_DATA);
636
} else {
637
return GUIVisualizationSettings::MISSING_DATA;
638
}
639
}
640
641
642
void
643
GUINet::DiscoverAttributes::myStartElement(int element, const SUMOSAXAttributes& attrs) {
644
if (element == SUMO_TAG_EDGE || element == SUMO_TAG_LANE) {
645
std::vector<std::string> tmp = attrs.getAttributeNames();
646
edgeAttrs.insert(tmp.begin(), tmp.end());
647
} else if (element == SUMO_TAG_EDGEREL) {
648
for (const std::string& a : attrs.getAttributeNames()) {
649
if (a != "from" && a != "to") {
650
edgeAttrs.insert(a);
651
}
652
}
653
} else if (element == SUMO_TAG_INTERVAL) {
654
bool ok;
655
numIntervals++;
656
firstIntervalBegin = MIN2(firstIntervalBegin, attrs.getSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok));
657
lastIntervalEnd = MAX2(lastIntervalEnd, attrs.getSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok));
658
}
659
}
660
661
662
std::vector<std::string>
663
GUINet::DiscoverAttributes::getEdgeAttrs() {
664
edgeAttrs.erase(toString(SUMO_ATTR_ID));
665
return std::vector<std::string>(edgeAttrs.begin(), edgeAttrs.end());
666
}
667
668
669
void
670
GUINet::EdgeFloatTimeLineRetriever_GUI::addEdgeWeight(const std::string& id,
671
double value, double begTime, double endTime) const {
672
MSEdge* const edge = MSEdge::dictionary(id);
673
if (edge != nullptr) {
674
myWeightStorage->addEffort(edge, begTime, endTime, value);
675
} else {
676
WRITE_WARNINGF(TL("Trying to set data value for the unknown edge '%'."), id);
677
}
678
}
679
680
681
void
682
GUINet::EdgeFloatTimeLineRetriever_GUI::addEdgeRelWeight(const std::string& from, const std::string& to,
683
double val, double beg, double end) const {
684
MSEdge* const fromEdge = MSEdge::dictionary(from);
685
MSEdge* const toEdge = MSEdge::dictionary(to);
686
bool haveRel = false;
687
if (fromEdge != nullptr && toEdge != nullptr) {
688
for (auto item : fromEdge->getViaSuccessors()) {
689
if (item.first == toEdge) {
690
const MSEdge* edge = item.second;
691
while (edge != nullptr && edge->isInternal()) {
692
myWeightStorage->addEffort(edge, beg, end, val);
693
edge = edge->getViaSuccessors().front().second;
694
haveRel = true;
695
}
696
}
697
}
698
}
699
if (!haveRel) {
700
WRITE_WARNINGF(TL("Trying to set data value for the unknown relation from edge '%' to edge '%'."), from, to);
701
}
702
}
703
704
705
bool
706
GUINet::loadEdgeData(const std::string& file) {
707
// discover edge attributes
708
DiscoverAttributes discoveryHandler(file);
709
XMLSubSys::runParser(discoveryHandler, file);
710
std::vector<std::string> attrs = discoveryHandler.getEdgeAttrs();
711
WRITE_MESSAGE("Loading edgedata from '" + file + "':"
712
+ "\n " + toString(discoveryHandler.numIntervals) + " intervals between"
713
+ " " + time2string(discoveryHandler.firstIntervalBegin) + " and"
714
+ " " + time2string(discoveryHandler.lastIntervalEnd)
715
+ ".\n Found " + toString(attrs.size())
716
+ " attributes: " + toString(attrs));
717
if (discoveryHandler.lastIntervalEnd < string2time(OptionsCont::getOptions().getString("begin"))) {
718
WRITE_WARNING(TL("No data defined after simulation begin time."));
719
}
720
myEdgeDataEndTime = MAX2(myEdgeDataEndTime, discoveryHandler.lastIntervalEnd);
721
// create a retriever for each attribute
722
std::vector<EdgeFloatTimeLineRetriever_GUI> retrieverDefsInternal;
723
retrieverDefsInternal.reserve(attrs.size());
724
std::vector<SAXWeightsHandler::ToRetrieveDefinition*> retrieverDefs;
725
for (const std::string& attr : attrs) {
726
MSEdgeWeightsStorage* ws = new MSEdgeWeightsStorage();
727
myLoadedEdgeData[attr] = ws;
728
retrieverDefsInternal.push_back(EdgeFloatTimeLineRetriever_GUI(ws));
729
retrieverDefs.push_back(new SAXWeightsHandler::ToRetrieveDefinition(attr, true, retrieverDefsInternal.back()));
730
}
731
SAXWeightsHandler handler(retrieverDefs, "");
732
// temporarily modify warning threshold to avoid swamping the UI
733
const int threshold = MsgHandler::getWarningInstance()->getAggregationThreshold();
734
MsgHandler::getWarningInstance()->setAggregationThreshold(10);
735
bool ok = XMLSubSys::runParser(handler, file);
736
MsgHandler::getWarningInstance()->clear(false);
737
MsgHandler::getWarningInstance()->setAggregationThreshold(threshold);
738
return ok;
739
}
740
741
742
std::vector<std::string>
743
GUINet::getEdgeDataAttrs() const {
744
std::vector<std::string> result;
745
for (const auto& item : myLoadedEdgeData) {
746
result.push_back(item.first);
747
}
748
return result;
749
}
750
751
752
std::vector<std::string>
753
GUINet::getMeanDataIDs() const {
754
std::vector<std::string> result;
755
756
for (auto item : myDetectorControl->getMeanData()) {
757
result.push_back(item.first);
758
}
759
std::sort(result.begin(), result.end());
760
return result;
761
}
762
763
std::vector<std::string>
764
GUINet::getMeanDataAttrs(const std::string& meanDataID) const {
765
auto item = myDetectorControl->getMeanData().find(meanDataID);
766
if (item != myDetectorControl->getMeanData().end() && !item->second.empty()) {
767
return item->second.front()->getAttributeNames();
768
} else {
769
return std::vector<std::string>();
770
}
771
}
772
773
774
bool
775
GUINet::isSelected(const MSTrafficLightLogic* tll) const {
776
const auto it = myLogics2Wrapper.find(const_cast<MSTrafficLightLogic*>(tll));
777
return it != myLogics2Wrapper.end() && gSelected.isSelected(GLO_TLLOGIC, it->second->getGlID());
778
}
779
780
void
781
GUINet::updateGUI() const {
782
try {
783
// gui only
784
GUIApplicationWindow* aw = static_cast<GUIApplicationWindow*>(GUIMainWindow::getInstance());
785
// update the view
786
aw->handleEvent_SimulationStep(nullptr);
787
} catch (ProcessError&) { }
788
}
789
790
void
791
GUINet::addHotkey(int key, Command* press, Command* release) {
792
try {
793
// gui only
794
GUIApplicationWindow* aw = static_cast<GUIApplicationWindow*>(GUIMainWindow::getInstance());
795
// update the view
796
aw->addHotkey(key, press, release);
797
} catch (ProcessError&) { }
798
}
799
800
void
801
GUINet::flushOutputsAtEnd() {
802
mySkipFinalReset = true;
803
myDetectorControl->close(SIMSTEP);
804
OutputDevice::flushAll();
805
// update tracker windows
806
guiSimulationStep();
807
}
808
809
#ifdef HAVE_OSG
810
void
811
GUINet::updateColor(const GUIVisualizationSettings& s) {
812
for (std::vector<GUIEdge*>::const_iterator i = myEdgeWrapper.begin(); i != myEdgeWrapper.end(); ++i) {
813
if (!(*i)->isInternal()) {
814
const std::vector<MSLane*>& lanes = (*i)->getLanes();
815
for (std::vector<MSLane*>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
816
static_cast<GUILane*>(*j)->updateColor(s);
817
}
818
}
819
}
820
for (std::vector<GUIJunctionWrapper*>::iterator i = myJunctionWrapper.begin(); i != myJunctionWrapper.end(); ++i) {
821
(*i)->updateColor(s);
822
}
823
}
824
#endif
825
826
827
/****************************************************************************/
828
829