Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/guisim/GUINet.cpp
169666 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 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
void
226
GUINet::guiSimulationStep() {
227
GLObjectValuePassConnector<double>::updateAll();
228
GLObjectValuePassConnector<std::pair<SUMOTime, MSPhaseDefinition> >::updateAll();
229
}
230
231
232
void
233
GUINet::simulationStep() {
234
FXMutexLock locker(myLock);
235
MSNet::simulationStep();
236
}
237
238
239
std::vector<GUIGlID>
240
GUINet::getJunctionIDs(bool includeInternal) const {
241
std::vector<GUIGlID> ret;
242
for (std::vector<GUIJunctionWrapper*>::const_iterator i = myJunctionWrapper.begin(); i != myJunctionWrapper.end(); ++i) {
243
if (!(*i)->isInternal() || includeInternal) {
244
ret.push_back((*i)->getGlID());
245
}
246
}
247
return ret;
248
}
249
250
251
std::vector<GUIGlID>
252
GUINet::getTLSIDs() const {
253
std::vector<GUIGlID> ret;
254
std::vector<std::string> ids;
255
for (std::map<MSTrafficLightLogic*, GUITrafficLightLogicWrapper*>::const_iterator i = myLogics2Wrapper.begin(); i != myLogics2Wrapper.end(); ++i) {
256
std::string sid = (*i).second->getMicrosimID();
257
if (find(ids.begin(), ids.end(), sid) == ids.end()) {
258
ret.push_back((*i).second->getGlID());
259
ids.push_back(sid);
260
}
261
}
262
return ret;
263
}
264
265
266
void
267
GUINet::initGUIStructures() {
268
// initialise detector storage for gui
269
const std::vector<SumoXMLTag> types = myDetectorControl->getAvailableTypes();
270
for (std::vector<SumoXMLTag>::const_iterator i = types.begin(); i != types.end(); ++i) {
271
for (const auto& j : myDetectorControl->getTypedDetectors(*i)) {
272
GUIDetectorWrapper* wrapper = j.second->buildDetectorGUIRepresentation();
273
if (wrapper != nullptr) {
274
myDetectorWrapper.push_back(wrapper);
275
myGrid.addAdditionalGLObject(wrapper);
276
}
277
}
278
}
279
// let's always track emission parameters for the GUI
280
MSGlobals::gHaveEmissions = true;
281
// initialise calibrators
282
for (auto& item : MSCalibrator::getInstances()) {
283
GUICalibrator* wrapper = new GUICalibrator(item.second);
284
myCalibratorWrapper.push_back(wrapper);
285
myGrid.addAdditionalGLObject(wrapper);
286
}
287
// initialise the tl-map
288
initTLMap();
289
// initialise edge storage for gui
290
const MSEdgeVector& edges = MSEdge::getAllEdges();
291
myEdgeWrapper.reserve(edges.size());
292
for (MSEdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) {
293
// VISIM connector edges shall be drawn (they have lanes)
294
if (!(*i)->isTazConnector() || (*i)->getLanes().size() > 0) {
295
myEdgeWrapper.push_back(static_cast<GUIEdge*>(*i));
296
}
297
}
298
// initialise junction storage for gui
299
int size = myJunctions->size();
300
myJunctionWrapper.reserve(size);
301
std::map<MSJunction*, std::string> junction2TLL;
302
for (const auto tls : getTLSControl().getAllLogics()) {
303
for (const auto& links : tls->getLinks()) {
304
for (const MSLink* l : links) {
305
junction2TLL[l->getJunction()] = l->getTLLogic()->getID();
306
}
307
}
308
}
309
for (const auto& i : *myJunctions) {
310
myJunctionWrapper.push_back(new GUIJunctionWrapper(*i.second, junction2TLL[i.second]));
311
}
312
// build the visualization tree
313
for (std::vector<GUIEdge*>::iterator i = myEdgeWrapper.begin(); i != myEdgeWrapper.end(); ++i) {
314
GUIEdge* edge = *i;
315
Boundary b;
316
const std::vector<MSLane*>& lanes = edge->getLanes();
317
for (std::vector<MSLane*>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
318
b.add((*j)->getShape().getBoxBoundary());
319
}
320
// make sure persons are always drawn and selectable since they depend on their edge being drawn
321
b.grow(MSPModel::SIDEWALK_OFFSET + 1 + lanes.front()->getWidth() / 2);
322
const float cmin[2] = { (float)b.xmin(), (float)b.ymin() };
323
const float cmax[2] = { (float)b.xmax(), (float)b.ymax() };
324
myGrid.Insert(cmin, cmax, edge);
325
myBoundary.add(b);
326
if (myBoundary.getWidth() > 10e16 || myBoundary.getHeight() > 10e16) {
327
throw ProcessError(TL("Network size exceeds 1 Lightyear. Please reconsider your inputs.\n"));
328
}
329
}
330
for (std::vector<GUIJunctionWrapper*>::iterator i = myJunctionWrapper.begin(); i != myJunctionWrapper.end(); ++i) {
331
GUIJunctionWrapper* junction = *i;
332
Boundary b = junction->getBoundary();
333
b.grow(2.);
334
const float cmin[2] = { (float)b.xmin(), (float)b.ymin() };
335
const float cmax[2] = { (float)b.xmax(), (float)b.ymax() };
336
myGrid.Insert(cmin, cmax, junction);
337
myBoundary.add(b);
338
}
339
myGrid.add(myBoundary);
340
341
if (OptionsCont::getOptions().isSet("alternative-net-file")) {
342
// build secondary visualization tree
343
for (GUIEdge* edge : myEdgeWrapper) {
344
Boundary b;
345
for (MSLane* lane : edge->getLanes()) {
346
b.add(static_cast<GUILane*>(lane)->getShape(true).getBoxBoundary());
347
}
348
// make sure persons are always drawn and selectable since they depend on their edge being drawn
349
b.grow(MSPModel::SIDEWALK_OFFSET + 1);
350
const float cmin[2] = { (float)b.xmin(), (float)b.ymin() };
351
const float cmax[2] = { (float)b.xmax(), (float)b.ymax() };
352
myGrid2.Insert(cmin, cmax, edge);
353
}
354
for (std::vector<GUIJunctionWrapper*>::iterator i = myJunctionWrapper.begin(); i != myJunctionWrapper.end(); ++i) {
355
GUIJunctionWrapper* junction = *i;
356
Position pos = junction->getJunction().getPosition(true);
357
Boundary b = Boundary(pos.x() - 3., pos.y() - 3., pos.x() + 3., pos.y() + 3.);
358
const float cmin[2] = { (float)b.xmin(), (float)b.ymin() };
359
const float cmax[2] = { (float)b.xmax(), (float)b.ymax() };
360
myGrid2.Insert(cmin, cmax, junction);
361
}
362
}
363
}
364
365
366
void
367
GUINet::registerRenderedObject(GUIGlObject* o) {
368
getVisualisationSpeedUp().addAdditionalGLObject(o);
369
if (OptionsCont::getOptions().isSet("alternative-net-file")) {
370
GUIGlobals::gSecondaryShape = true;
371
myGrid2.addAdditionalGLObject(o);
372
GUIGlobals::gSecondaryShape = false;
373
}
374
}
375
376
377
int
378
GUINet::getWholeDuration() const {
379
return myLastSimDuration +/*myLastVisDuration+*/myLastIdleDuration;
380
}
381
382
383
int
384
GUINet::getSimDuration() const {
385
return myLastSimDuration;
386
}
387
388
/*
389
int
390
GUINet::getVisDuration() const
391
{
392
return myLastVisDuration;
393
}
394
*/
395
396
397
double
398
GUINet::getRTFactor() const {
399
if (myLastSimDuration == 0) {
400
return -1;
401
}
402
return (double)DELTA_T / (double)myLastSimDuration;
403
}
404
405
406
double
407
GUINet::getUPS() const {
408
if (myLastSimDuration == 0) {
409
return -1;
410
}
411
return (double) myLastVehicleMovementCount / (double) myLastSimDuration * (double) 1000.;
412
}
413
414
415
double
416
GUINet::getMeanRTFactor(int duration) const {
417
if (myOverallSimDuration == 0) {
418
return -1;
419
}
420
return ((double)(duration) * (double) 1000. / (double)myOverallSimDuration);
421
}
422
423
424
double
425
GUINet::getMeanUPS() const {
426
if (myOverallSimDuration == 0) {
427
return -1;
428
}
429
return ((double)myVehiclesMoved / (double)myOverallSimDuration * (double) 1000.);
430
}
431
432
433
int
434
GUINet::getIdleDuration() const {
435
return myLastIdleDuration;
436
}
437
438
439
void
440
GUINet::setSimDuration(int val) {
441
myLastSimDuration = val;
442
myOverallSimDuration += val;
443
myLastVehicleMovementCount = getVehicleControl().getRunningVehicleNo();
444
myOverallVehicleCount += myLastVehicleMovementCount;
445
}
446
447
/*
448
void
449
GUINet::setVisDuration(int val)
450
{
451
myLastVisDuration = val;
452
}
453
*/
454
455
void
456
GUINet::setIdleDuration(int val) {
457
myLastIdleDuration = val;
458
}
459
460
461
GUIGLObjectPopupMenu*
462
GUINet::getPopUpMenu(GUIMainWindow& app,
463
GUISUMOAbstractView& parent) {
464
GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
465
buildPopupHeader(ret, app);
466
buildCenterPopupEntry(ret);
467
buildShowParamsPopupEntry(ret);
468
buildPositionCopyEntry(ret, app);
469
if (GeoConvHelper::getFinal().usingGeoProjection()) {
470
GUIDesigns::buildFXMenuCommand(ret, TL("Copy view geo-boundary to clipboard"), nullptr, ret, MID_COPY_VIEW_GEOBOUNDARY);
471
}
472
return ret;
473
}
474
475
476
GUIParameterTableWindow*
477
GUINet::getParameterWindow(GUIMainWindow& app,
478
GUISUMOAbstractView& parent) {
479
GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
480
// add items
481
ret->mkItem(TL("loaded vehicles [#]"), true,
482
new FunctionBinding<MSVehicleControl, int>(&getVehicleControl(), &MSVehicleControl::getLoadedVehicleNo));
483
ret->mkItem(TL("insertion-backlogged vehicles [#]"), true,
484
new FunctionBinding<MSInsertionControl, int>(&getInsertionControl(), &MSInsertionControl::getWaitingVehicleNo));
485
ret->mkItem(TL("departed vehicles [#]"), true,
486
new FunctionBinding<MSVehicleControl, int>(&getVehicleControl(), &MSVehicleControl::getDepartedVehicleNo));
487
ret->mkItem(TL("running vehicles [#]"), true,
488
new FunctionBinding<MSVehicleControl, int>(&getVehicleControl(), &MSVehicleControl::getRunningVehicleNo));
489
ret->mkItem(TL("arrived vehicles [#]"), true,
490
new FunctionBinding<MSVehicleControl, int>(&getVehicleControl(), &MSVehicleControl::getArrivedVehicleNo));
491
ret->mkItem(TL("discarded vehicles [#]"), true,
492
new FunctionBinding<MSVehicleControl, int>(&getVehicleControl(), &MSVehicleControl::getDiscardedVehicleNo));
493
ret->mkItem(TL("collisions [#]"), true,
494
new FunctionBinding<MSVehicleControl, int>(&getVehicleControl(), &MSVehicleControl::getCollisionCount));
495
ret->mkItem(TL("teleports [#]"), true,
496
new FunctionBinding<MSVehicleControl, int>(&getVehicleControl(), &MSVehicleControl::getTeleportCount));
497
ret->mkItem(TL("halting [#]"), true,
498
new FunctionBinding<MSVehicleControl, int>(&getVehicleControl(), &MSVehicleControl::getHaltingVehicleNo));
499
ret->mkItem(TL("stopped [#]"), true,
500
new FunctionBinding<MSVehicleControl, int>(&getVehicleControl(), &MSVehicleControl::getStoppedVehiclesCount));
501
ret->mkItem(TL("avg. speed [m/s]"), true,
502
new FunctionBinding<MSVehicleControl, double>(&getVehicleControl(), &MSVehicleControl::getVehicleMeanSpeed));
503
ret->mkItem(TL("avg. relative speed"), true,
504
new FunctionBinding<MSVehicleControl, double>(&getVehicleControl(), &MSVehicleControl::getVehicleMeanSpeedRelative));
505
if (myPersonControl != nullptr) {
506
ret->mkItem(TL("loaded persons [#]"), true,
507
new FunctionBinding<MSTransportableControl, int>(&getPersonControl(), &MSTransportableControl::getLoadedNumber));
508
ret->mkItem(TL("running persons [#]"), true,
509
new FunctionBinding<MSTransportableControl, int>(&getPersonControl(), &MSTransportableControl::getRunningNumber));
510
ret->mkItem(TL("jammed persons [#]"), true,
511
new FunctionBinding<MSTransportableControl, int>(&getPersonControl(), &MSTransportableControl::getJammedNumber));
512
}
513
ret->mkItem(TL("end time [s]"), false, OptionsCont::getOptions().getString("end"));
514
ret->mkItem(TL("begin time [s]"), false, OptionsCont::getOptions().getString("begin"));
515
// ret->mkItem(TL("time step [s]"), true, new FunctionBinding<GUINet, SUMOTime>(this, &GUINet::getCurrentTimeStep));
516
if (logSimulationDuration()) {
517
ret->mkItem(TL("step duration [ms]"), true, new FunctionBinding<GUINet, int>(this, &GUINet::getWholeDuration));
518
ret->mkItem(TL("FPS"), true, new FunctionBinding<GUISUMOAbstractView, double>(&parent, &GUISUMOAbstractView::getFPS));
519
ret->mkItem(TL("simulation duration [ms]"), true, new FunctionBinding<GUINet, int>(this, &GUINet::getSimDuration));
520
/*
521
ret->mkItem(TL("visualisation duration [ms]"), true,
522
new CastingFunctionBinding<GUINet, double, int>(
523
&(getNet()), &GUINet::getVisDuration));
524
*/
525
ret->mkItem(TL("idle duration [ms]"), true, new FunctionBinding<GUINet, int>(this, &GUINet::getIdleDuration));
526
ret->mkItem(TL("duration factor"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getRTFactor));
527
/*
528
ret->mkItem(TL("mean duration factor []"), true,
529
new FuncBinding_IntParam<GUINet, double>(
530
&(getNet()), &GUINet::getMeanRTFactor), 1);
531
*/
532
ret->mkItem(TL("updates per second"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getUPS));
533
ret->mkItem(TL("avg. updates per second"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getMeanUPS));
534
}
535
if (OptionsCont::getOptions().isSet("tripinfo-output") || OptionsCont::getOptions().getBool("duration-log.statistics")) {
536
ret->mkItem(TL("avg. trip length [m]"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getAvgRouteLength));
537
ret->mkItem(TL("avg. trip duration [s]"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getAvgDuration));
538
ret->mkItem(TL("avg. trip waiting time [s]"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getAvgWaitingTime));
539
ret->mkItem(TL("avg. trip time loss [s]"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getAvgTimeLoss));
540
ret->mkItem(TL("avg. trip depart delay [s]"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getAvgDepartDelay));
541
ret->mkItem(TL("avg. trip speed [m/s]"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getAvgTripSpeed));
542
if (myPersonControl != nullptr) {
543
ret->mkItem(TL("avg. walk length [m]"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getAvgWalkRouteLength));
544
ret->mkItem(TL("avg. walk duration [s]"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getAvgWalkDuration));
545
ret->mkItem(TL("avg. walk time loss [s]"), true, new FunctionBinding<GUINet, double>(this, &GUINet::getAvgWalkTimeLoss));
546
}
547
}
548
ret->mkItem(TL("nodes [#]"), false, (int)getJunctionIDs(false).size());
549
ret->mkItem(TL("edges [#]"), false, (int)GUIEdge::getIDs(false).size());
550
ret->mkItem(TL("total edge length [km]"), false, GUIEdge::getTotalLength(false, false) / 1000);
551
ret->mkItem(TL("total lane length [km]"), false, GUIEdge::getTotalLength(false, true) / 1000);
552
ret->mkItem(TL("network version "), false, toString(myVersion));
553
554
// close building
555
ret->closeBuilding();
556
return ret;
557
}
558
559
560
void
561
GUINet::drawGL(const GUIVisualizationSettings& /*s*/) const {
562
}
563
564
565
Boundary
566
GUINet::getCenteringBoundary() const {
567
return getBoundary();
568
}
569
570
571
GUINet*
572
GUINet::getGUIInstance() {
573
GUINet* net = dynamic_cast<GUINet*>(MSNet::getInstance());
574
if (net != nullptr) {
575
return net;
576
}
577
throw ProcessError("A gui-network was not yet constructed.");
578
}
579
580
581
GUIVehicleControl*
582
GUINet::getGUIVehicleControl() {
583
return dynamic_cast<GUIVehicleControl*>(myVehicleControl);
584
}
585
586
587
void
588
GUINet::lock() {
589
myLock.lock();
590
}
591
592
593
void
594
GUINet::unlock() {
595
myLock.unlock();
596
}
597
598
GUIMEVehicleControl*
599
GUINet::getGUIMEVehicleControl() {
600
return dynamic_cast<GUIMEVehicleControl*>(myVehicleControl);
601
}
602
603
604
double
605
GUINet::getEdgeData(const MSEdge* edge, const std::string& attr) {
606
auto it = myLoadedEdgeData.find(attr);
607
if (it != myLoadedEdgeData.end()) {
608
double value;
609
bool found = it->second->retrieveExistingEffort(edge, STEPS2TIME(getCurrentTimeStep()), value);
610
if (found) {
611
return value;
612
} else {
613
return GUIVisualizationSettings::MISSING_DATA;
614
}
615
} else {
616
return GUIVisualizationSettings::MISSING_DATA;
617
}
618
}
619
620
621
double
622
GUINet::getMeanData(const MSLane* lane, const std::string& id, const std::string& attr) {
623
auto item = myDetectorControl->getMeanData().find(id);
624
if (item != myDetectorControl->getMeanData().end() && !item->second.empty()) {
625
SumoXMLAttr a = (SumoXMLAttr)SUMOXMLDefinitions::Attrs.get(attr);
626
return item->second.front()->getAttributeValue(lane, a, GUIVisualizationSettings::MISSING_DATA);
627
} else {
628
return GUIVisualizationSettings::MISSING_DATA;
629
}
630
}
631
632
633
void
634
GUINet::DiscoverAttributes::myStartElement(int element, const SUMOSAXAttributes& attrs) {
635
if (element == SUMO_TAG_EDGE || element == SUMO_TAG_LANE) {
636
std::vector<std::string> tmp = attrs.getAttributeNames();
637
edgeAttrs.insert(tmp.begin(), tmp.end());
638
} else if (element == SUMO_TAG_EDGEREL) {
639
for (const std::string& a : attrs.getAttributeNames()) {
640
if (a != "from" && a != "to") {
641
edgeAttrs.insert(a);
642
}
643
}
644
} else if (element == SUMO_TAG_INTERVAL) {
645
bool ok;
646
numIntervals++;
647
firstIntervalBegin = MIN2(firstIntervalBegin, attrs.getSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok));
648
lastIntervalEnd = MAX2(lastIntervalEnd, attrs.getSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok));
649
}
650
}
651
652
653
std::vector<std::string>
654
GUINet::DiscoverAttributes::getEdgeAttrs() {
655
edgeAttrs.erase(toString(SUMO_ATTR_ID));
656
return std::vector<std::string>(edgeAttrs.begin(), edgeAttrs.end());
657
}
658
659
660
void
661
GUINet::EdgeFloatTimeLineRetriever_GUI::addEdgeWeight(const std::string& id,
662
double value, double begTime, double endTime) const {
663
MSEdge* const edge = MSEdge::dictionary(id);
664
if (edge != nullptr) {
665
myWeightStorage->addEffort(edge, begTime, endTime, value);
666
} else {
667
WRITE_WARNINGF(TL("Trying to set data value for the unknown edge '%'."), id);
668
}
669
}
670
671
672
void
673
GUINet::EdgeFloatTimeLineRetriever_GUI::addEdgeRelWeight(const std::string& from, const std::string& to,
674
double val, double beg, double end) const {
675
MSEdge* const fromEdge = MSEdge::dictionary(from);
676
MSEdge* const toEdge = MSEdge::dictionary(to);
677
bool haveRel = false;
678
if (fromEdge != nullptr && toEdge != nullptr) {
679
for (auto item : fromEdge->getViaSuccessors()) {
680
if (item.first == toEdge) {
681
const MSEdge* edge = item.second;
682
while (edge != nullptr && edge->isInternal()) {
683
myWeightStorage->addEffort(edge, beg, end, val);
684
edge = edge->getViaSuccessors().front().second;
685
haveRel = true;
686
}
687
}
688
}
689
}
690
if (!haveRel) {
691
WRITE_WARNINGF(TL("Trying to set data value for the unknown relation from edge '%' to edge '%'."), from, to);
692
}
693
}
694
695
696
bool
697
GUINet::loadEdgeData(const std::string& file) {
698
// discover edge attributes
699
DiscoverAttributes discoveryHandler(file);
700
XMLSubSys::runParser(discoveryHandler, file);
701
std::vector<std::string> attrs = discoveryHandler.getEdgeAttrs();
702
WRITE_MESSAGE("Loading edgedata from '" + file + "':"
703
+ "\n " + toString(discoveryHandler.numIntervals) + " intervals between"
704
+ " " + time2string(discoveryHandler.firstIntervalBegin) + " and"
705
+ " " + time2string(discoveryHandler.lastIntervalEnd)
706
+ ".\n Found " + toString(attrs.size())
707
+ " attributes: " + toString(attrs));
708
if (discoveryHandler.lastIntervalEnd < string2time(OptionsCont::getOptions().getString("begin"))) {
709
WRITE_WARNING(TL("No data defined after simulation begin time."));
710
}
711
myEdgeDataEndTime = MAX2(myEdgeDataEndTime, discoveryHandler.lastIntervalEnd);
712
// create a retriever for each attribute
713
std::vector<EdgeFloatTimeLineRetriever_GUI> retrieverDefsInternal;
714
retrieverDefsInternal.reserve(attrs.size());
715
std::vector<SAXWeightsHandler::ToRetrieveDefinition*> retrieverDefs;
716
for (const std::string& attr : attrs) {
717
MSEdgeWeightsStorage* ws = new MSEdgeWeightsStorage();
718
myLoadedEdgeData[attr] = ws;
719
retrieverDefsInternal.push_back(EdgeFloatTimeLineRetriever_GUI(ws));
720
retrieverDefs.push_back(new SAXWeightsHandler::ToRetrieveDefinition(attr, true, retrieverDefsInternal.back()));
721
}
722
SAXWeightsHandler handler(retrieverDefs, "");
723
// temporarily modify warning threshold to avoid swamping the UI
724
const int threshold = MsgHandler::getWarningInstance()->getAggregationThreshold();
725
MsgHandler::getWarningInstance()->setAggregationThreshold(10);
726
bool ok = XMLSubSys::runParser(handler, file);
727
MsgHandler::getWarningInstance()->clear(false);
728
MsgHandler::getWarningInstance()->setAggregationThreshold(threshold);
729
return ok;
730
}
731
732
733
std::vector<std::string>
734
GUINet::getEdgeDataAttrs() const {
735
std::vector<std::string> result;
736
for (const auto& item : myLoadedEdgeData) {
737
result.push_back(item.first);
738
}
739
return result;
740
}
741
742
743
std::vector<std::string>
744
GUINet::getMeanDataIDs() const {
745
std::vector<std::string> result;
746
747
for (auto item : myDetectorControl->getMeanData()) {
748
result.push_back(item.first);
749
}
750
std::sort(result.begin(), result.end());
751
return result;
752
}
753
754
std::vector<std::string>
755
GUINet::getMeanDataAttrs(const std::string& meanDataID) const {
756
auto item = myDetectorControl->getMeanData().find(meanDataID);
757
if (item != myDetectorControl->getMeanData().end() && !item->second.empty()) {
758
return item->second.front()->getAttributeNames();
759
} else {
760
return std::vector<std::string>();
761
}
762
}
763
764
765
bool
766
GUINet::isSelected(const MSTrafficLightLogic* tll) const {
767
const auto it = myLogics2Wrapper.find(const_cast<MSTrafficLightLogic*>(tll));
768
return it != myLogics2Wrapper.end() && gSelected.isSelected(GLO_TLLOGIC, it->second->getGlID());
769
}
770
771
void
772
GUINet::updateGUI() const {
773
try {
774
// gui only
775
GUIApplicationWindow* aw = static_cast<GUIApplicationWindow*>(GUIMainWindow::getInstance());
776
// update the view
777
aw->handleEvent_SimulationStep(nullptr);
778
} catch (ProcessError&) { }
779
}
780
781
void
782
GUINet::addHotkey(int key, Command* press, Command* release) {
783
try {
784
// gui only
785
GUIApplicationWindow* aw = static_cast<GUIApplicationWindow*>(GUIMainWindow::getInstance());
786
// update the view
787
aw->addHotkey(key, press, release);
788
} catch (ProcessError&) { }
789
}
790
791
void
792
GUINet::flushOutputsAtEnd() {
793
mySkipFinalReset = true;
794
myDetectorControl->close(SIMSTEP);
795
OutputDevice::flushAll();
796
// update tracker windows
797
guiSimulationStep();
798
}
799
800
#ifdef HAVE_OSG
801
void
802
GUINet::updateColor(const GUIVisualizationSettings& s) {
803
for (std::vector<GUIEdge*>::const_iterator i = myEdgeWrapper.begin(); i != myEdgeWrapper.end(); ++i) {
804
if (!(*i)->isInternal()) {
805
const std::vector<MSLane*>& lanes = (*i)->getLanes();
806
for (std::vector<MSLane*>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
807
static_cast<GUILane*>(*j)->updateColor(s);
808
}
809
}
810
}
811
for (std::vector<GUIJunctionWrapper*>::iterator i = myJunctionWrapper.begin(); i != myJunctionWrapper.end(); ++i) {
812
(*i)->updateColor(s);
813
}
814
}
815
#endif
816
817
818
/****************************************************************************/
819
820