Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/guisim/GUIEdge.cpp
193863 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 GUIEdge.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Michael Behrisch
18
/// @author Laura Bieker
19
/// @date Sept 2002
20
///
21
// A road/street connecting two junctions (gui-version)
22
/****************************************************************************/
23
#include <config.h>
24
25
#include <vector>
26
#include <cmath>
27
#include <string>
28
#include <algorithm>
29
#include <utils/common/MsgHandler.h>
30
#include <utils/foxtools/fxheader.h>
31
#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
32
#include <utils/gui/windows/GUIMainWindow.h>
33
#include <utils/gui/windows/GUISUMOAbstractView.h>
34
#include <utils/geom/GeomHelper.h>
35
#include <utils/gui/div/GUIParameterTableWindow.h>
36
#include <utils/gui/div/GLHelper.h>
37
#include <utils/gui/div/GUIGlobalSelection.h>
38
#include <utils/gui/globjects/GLIncludes.h>
39
#include <gui/GUIGlobals.h>
40
#include <microsim/MSBaseVehicle.h>
41
#include <microsim/MSEdge.h>
42
#include <microsim/MSJunction.h>
43
#include <microsim/MSLaneChanger.h>
44
#include <microsim/MSInsertionControl.h>
45
#include <microsim/MSGlobals.h>
46
#include <microsim/logging/CastingFunctionBinding.h>
47
#include <microsim/logging/FunctionBinding.h>
48
#include <utils/gui/div/GUIDesigns.h>
49
#include <mesogui/GUIMEVehicleControl.h>
50
#include <mesogui/GUIMEVehicle.h>
51
#include <mesosim/MESegment.h>
52
#include <mesosim/MELoop.h>
53
#include <mesosim/MEVehicle.h>
54
55
#include "GUITriggeredRerouter.h"
56
#include "GUIEdge.h"
57
#include "GUIVehicle.h"
58
#include "GUINet.h"
59
#include "GUILane.h"
60
#include "GUIPerson.h"
61
#include "GUIContainer.h"
62
63
64
GUIEdge::GUIEdge(const std::string& id, int numericalID,
65
const SumoXMLEdgeFunc function,
66
const std::string& streetName, const std::string& edgeType,
67
const std::string& routingType, int priority,
68
double distance) :
69
MSEdge(id, numericalID, function, streetName, edgeType, routingType, priority, distance),
70
GUIGlObject(GLO_EDGE, id, GUIIconSubSys::getIcon(GUIIcon::EDGE)),
71
myLock(true)
72
{}
73
74
75
GUIEdge::~GUIEdge() {
76
// just to quit cleanly on a failure
77
if (myLock.locked()) {
78
myLock.unlock();
79
}
80
}
81
82
void
83
GUIEdge::closeBuilding() {
84
MSEdge::closeBuilding();
85
bool hasNormalSuccessors = false;
86
for (const MSEdge* out : getSuccessors()) {
87
if (!out->isTazConnector()) {
88
hasNormalSuccessors = true;
89
break;
90
}
91
}
92
myShowDeadEnd = (!isTazConnector() && !hasNormalSuccessors && getToJunction()->getOutgoing().size() > 0
93
&& (getPermissions() & ~SVC_PEDESTRIAN) != 0
94
&& (getToJunction()->getOutgoing().size() > 1 ||
95
getToJunction()->getOutgoing().front()->getToJunction() != getFromJunction()));
96
}
97
98
MSLane&
99
GUIEdge::getLane(int laneNo) {
100
assert(laneNo < (int)myLanes->size());
101
return *((*myLanes)[laneNo]);
102
}
103
104
105
std::vector<GUIGlID>
106
GUIEdge::getIDs(bool includeInternal) {
107
std::vector<GUIGlID> ret;
108
ret.reserve(MSEdge::myDict.size());
109
for (MSEdge::DictType::const_iterator i = MSEdge::myDict.begin(); i != MSEdge::myDict.end(); ++i) {
110
const GUIEdge* edge = dynamic_cast<const GUIEdge*>(i->second);
111
assert(edge);
112
if (includeInternal || edge->isNormal()) {
113
ret.push_back(edge->getGlID());
114
}
115
}
116
return ret;
117
}
118
119
120
double
121
GUIEdge::getTotalLength(bool includeInternal, bool eachLane) {
122
double result = 0;
123
for (MSEdge::DictType::const_iterator i = MSEdge::myDict.begin(); i != MSEdge::myDict.end(); ++i) {
124
const MSEdge* edge = i->second;
125
if (includeInternal || !edge->isInternal()) {
126
// @note needs to be change once lanes may have different length
127
result += edge->getLength() * (eachLane ? (double)edge->getLanes().size() : 1.);
128
}
129
}
130
return result;
131
}
132
133
134
Boundary
135
GUIEdge::getBoundary() const {
136
Boundary ret;
137
const bool s2 = GUIGlobals::gSecondaryShape;
138
if (!isTazConnector()) {
139
for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
140
ret.add((*i)->getShape(s2).getBoxBoundary());
141
}
142
} else {
143
// take the starting coordinates of all follower edges and the endpoints
144
// of all successor edges
145
for (MSEdgeVector::const_iterator it = mySuccessors.begin(); it != mySuccessors.end(); ++it) {
146
const std::vector<MSLane*>& lanes = (*it)->getLanes();
147
for (std::vector<MSLane*>::const_iterator it_lane = lanes.begin(); it_lane != lanes.end(); ++it_lane) {
148
ret.add((*it_lane)->getShape(s2).front());
149
}
150
}
151
for (MSEdgeVector::const_iterator it = myPredecessors.begin(); it != myPredecessors.end(); ++it) {
152
const std::vector<MSLane*>& lanes = (*it)->getLanes();
153
for (std::vector<MSLane*>::const_iterator it_lane = lanes.begin(); it_lane != lanes.end(); ++it_lane) {
154
ret.add((*it_lane)->getShape(s2).back());
155
}
156
}
157
}
158
ret.grow(10);
159
return ret;
160
}
161
162
163
GUIGLObjectPopupMenu*
164
GUIEdge::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
165
GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
166
buildPopupHeader(ret, app);
167
buildCenterPopupEntry(ret);
168
buildNameCopyPopupEntry(ret);
169
buildSelectionPopupEntry(ret);
170
if (MSGlobals::gUseMesoSim) {
171
buildShowParamsPopupEntry(ret);
172
buildShowTypeParamsPopupEntry(ret);
173
}
174
MESegment* segment = getSegmentAtPosition(parent.getPositionInformation());
175
GUIDesigns::buildFXMenuCommand(ret, "segment: " + toString(segment->getIndex()), nullptr, nullptr, 0);
176
buildPositionCopyEntry(ret, app);
177
return ret;
178
}
179
180
181
GUIParameterTableWindow*
182
GUIEdge::getParameterWindow(GUIMainWindow& app,
183
GUISUMOAbstractView& parent) {
184
GUIParameterTableWindow* ret = nullptr;
185
ret = new GUIParameterTableWindow(app, *this);
186
// add edge items
187
ret->mkItem(TL("max speed [m/s]"), false, getAllowedSpeed());
188
ret->mkItem(TL("length [m]"), false, (*myLanes)[0]->getLength());
189
ret->mkItem(TL("street name"), false, getStreetName());
190
ret->mkItem(TL("pending insertions [#]"), true, new FunctionBinding<GUIEdge, double>(this, &GUIEdge::getPendingEmits));
191
ret->mkItem(TL("mean friction [%]"), true, new FunctionBinding<GUIEdge, double>(this, &MSEdge::getMeanFriction, 100.));
192
ret->mkItem(TL("mean vehicle speed [m/s]"), true, new FunctionBinding<GUIEdge, double>(this, &GUIEdge::getMeanSpeed));
193
ret->mkItem(TL("routing speed [m/s]"), true, new FunctionBinding<MSEdge, double>(this, &MSEdge::getRoutingSpeed));
194
ret->mkItem(TL("time penalty [s]"), true, new FunctionBinding<MSEdge, double>(this, &MSEdge::getTimePenalty));
195
ret->mkItem(TL("brutto occupancy [%]"), true, new FunctionBinding<GUIEdge, double>(this, &GUIEdge::getBruttoOccupancy, 100.));
196
ret->mkItem(TL("edge flow [veh/h/m]"), true, new FunctionBinding<GUIEdge, double>(this, &GUIEdge::getFlow));
197
ret->mkItem(TL("vehicles [#]"), true, new CastingFunctionBinding<GUIEdge, int, int>(this, &MSEdge::getVehicleNumber));
198
// add segment items
199
MESegment* segment = getSegmentAtPosition(parent.getPositionInformation());
200
ret->mkItem(TL("segment index"), false, segment->getIndex());
201
ret->mkItem(TL("segment queues"), false, segment->numQueues());
202
ret->mkItem(TL("segment length [m]"), false, segment->getLength());
203
ret->mkItem(TL("segment allowed speed [m/s]"), false, segment->getEdge().getSpeedLimit());
204
ret->mkItem(TL("segment jam threshold [%]"), false, segment->getRelativeJamThreshold() * 100);
205
ret->mkItem(TL("segment brutto occupancy [%]"), true, new FunctionBinding<MESegment, double>(segment, &MESegment::getRelativeOccupancy, 100));
206
ret->mkItem(TL("segment mean vehicle speed [m/s]"), true, new FunctionBinding<MESegment, double>(segment, &MESegment::getMeanSpeed));
207
ret->mkItem(TL("segment flow [veh/h/m]"), true, new FunctionBinding<MESegment, double>(segment, &MESegment::getFlow));
208
ret->mkItem(TL("segment vehicles [#]"), true, new CastingFunctionBinding<MESegment, int, int>(segment, &MESegment::getCarNumber));
209
ret->mkItem(TL("segment leader leave time"), true, new FunctionBinding<MESegment, double>(segment, &MESegment::getEventTimeSeconds));
210
ret->mkItem(TL("segment headway [s]"), true, new FunctionBinding<MESegment, double>(segment, &MESegment::getLastHeadwaySeconds));
211
ret->mkItem(TL("segment entry block time [s]"), true, new FunctionBinding<MESegment, double>(segment, &MESegment::getEntryBlockTimeSeconds));
212
// lane params
213
for (MSLane* lane : *myLanes) {
214
for (const auto& kv : lane->getParametersMap()) {
215
ret->mkItem(("laneParam " + toString(lane->getIndex()) + ":" + kv.first).c_str(), false, kv.second);
216
}
217
}
218
// close building
219
ret->closeBuilding();
220
return ret;
221
}
222
223
GUIParameterTableWindow*
224
GUIEdge::getTypeParameterWindow(GUIMainWindow& app,
225
GUISUMOAbstractView&) {
226
GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
227
const MESegment::MesoEdgeType& edgeType = MSNet::getInstance()->getMesoType(getEdgeType());
228
// add items
229
ret->mkItem(TL("Type Information:"), false, "");
230
ret->mkItem(TL("type [id]"), false, getEdgeType());
231
ret->mkItem(TL("routing type [id]"), false, getRoutingType());
232
ret->mkItem(TL("tauff"), false, STEPS2TIME(edgeType.tauff));
233
ret->mkItem(TL("taufj"), false, STEPS2TIME(edgeType.taufj));
234
ret->mkItem(TL("taujf"), false, STEPS2TIME(edgeType.taujf));
235
ret->mkItem(TL("taujj"), false, STEPS2TIME(edgeType.taujj));
236
ret->mkItem(TL("jam threshold"), false, edgeType.jamThreshold);
237
ret->mkItem(TL("junction control"), false, edgeType.junctionControl);
238
ret->mkItem(TL("tls penalty"), false, edgeType.tlsPenalty);
239
ret->mkItem(TL("tls flow penalty"), false, edgeType.tlsFlowPenalty);
240
ret->mkItem(TL("minor penalty"), false, STEPS2TIME(edgeType.minorPenalty));
241
ret->mkItem(TL("overtaking"), false, edgeType.overtaking);
242
// close building
243
ret->closeBuilding();
244
return ret;
245
}
246
247
248
Boundary
249
GUIEdge::getCenteringBoundary() const {
250
Boundary b = getBoundary();
251
// ensure that vehicles and persons on the side are drawn even if the edge
252
// is outside the view
253
b.grow(10);
254
return b;
255
}
256
257
const std::string
258
GUIEdge::getOptionalName() const {
259
return myStreetName;
260
}
261
262
void
263
GUIEdge::drawGL(const GUIVisualizationSettings& s) const {
264
if (s.hideConnectors && myFunction == SumoXMLEdgeFunc::CONNECTOR) {
265
return;
266
}
267
GLHelper::pushName(getGlID());
268
// draw the lanes
269
if (MSGlobals::gUseMesoSim) {
270
setColor(s);
271
}
272
for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
273
static_cast<GUILane*>(*i)->drawGL(s);
274
}
275
if (MSGlobals::gUseMesoSim) {
276
if (s.scale * s.vehicleSize.getExaggeration(s, nullptr) > s.vehicleSize.minSize) {
277
drawMesoVehicles(s);
278
}
279
}
280
GLHelper::popName();
281
// (optionally) draw the name and/or the street name
282
GUILane* lane2 = dynamic_cast<GUILane*>((*myLanes).back());
283
const GUIGlObject* selCheck = gSelected.isSelected(this) ? (GUIGlObject*)this : (GUIGlObject*)lane2;
284
const bool drawEdgeName = s.edgeName.show(selCheck) && myFunction == SumoXMLEdgeFunc::NORMAL;
285
const bool drawInternalEdgeName = s.internalEdgeName.show(selCheck) && myFunction == SumoXMLEdgeFunc::INTERNAL;
286
const bool drawCwaEdgeName = s.cwaEdgeName.show(selCheck) && (myFunction == SumoXMLEdgeFunc::CROSSING || myFunction == SumoXMLEdgeFunc::WALKINGAREA);
287
const bool drawStreetName = s.streetName.show(selCheck) && myStreetName != "";
288
const bool drawEdgeValue = s.edgeValue.show(selCheck) && (myFunction == SumoXMLEdgeFunc::NORMAL
289
|| (myFunction == SumoXMLEdgeFunc::INTERNAL && !s.drawJunctionShape)
290
|| ((myFunction == SumoXMLEdgeFunc::CROSSING || myFunction == SumoXMLEdgeFunc::WALKINGAREA) && s.drawCrossingsAndWalkingareas));
291
const bool drawEdgeScaleValue = s.edgeScaleValue.show(selCheck) && (myFunction == SumoXMLEdgeFunc::NORMAL
292
|| (myFunction == SumoXMLEdgeFunc::INTERNAL && !s.drawJunctionShape)
293
|| ((myFunction == SumoXMLEdgeFunc::CROSSING || myFunction == SumoXMLEdgeFunc::WALKINGAREA) && s.drawCrossingsAndWalkingareas));
294
if (drawEdgeName || drawInternalEdgeName || drawCwaEdgeName || drawStreetName || drawEdgeValue || drawEdgeScaleValue) {
295
GUILane* lane1 = dynamic_cast<GUILane*>((*myLanes)[0]);
296
if (lane1 != nullptr && lane2 != nullptr) {
297
const bool s2 = s.secondaryShape;
298
const bool spreadSuperposed = s.spreadSuperposed && getBidiEdge() != nullptr;
299
Position p = lane1->getShape(s2).positionAtOffset(lane1->getShape(s2).length() / (double) 2.);
300
p.add(lane2->getShape(s2).positionAtOffset(lane2->getShape(s2).length() / (double) 2.));
301
p.mul(.5);
302
if (spreadSuperposed) {
303
// move name to the right of the edge and towards its beginning
304
const double dist = 0.6 * s.edgeName.scaledSize(s.scale);
305
const double shiftA = lane1->getShape(s2).rotationAtOffset(lane1->getShape(s2).length() / (double) 2.) - DEG2RAD(135);
306
Position shift(dist * cos(shiftA), dist * sin(shiftA));
307
p.add(shift);
308
}
309
double angle = s.getTextAngle(lane1->getShape(s2).rotationDegreeAtOffset(lane1->getShape(s2).length() / (double) 2.) + 90);
310
if (drawEdgeName) {
311
drawName(p, s.scale, s.edgeName, angle, true);
312
} else if (drawInternalEdgeName) {
313
drawName(p, s.scale, s.internalEdgeName, angle, true);
314
} else if (drawCwaEdgeName) {
315
drawName(p, s.scale, s.cwaEdgeName, angle, true);
316
}
317
if (drawStreetName) {
318
GLHelper::drawTextSettings(s.streetName, getStreetName(), p, s.scale, angle);
319
}
320
if (drawEdgeValue) {
321
const int activeScheme = s.getLaneEdgeMode();
322
std::string value = "";
323
if (activeScheme == 31) {
324
// edge param, could be non-numerical
325
value = getParameter(s.edgeParam, "");
326
} else if (activeScheme == 32) {
327
// lane param, could be non-numerical
328
value = lane2->getParameter(s.laneParam, "");
329
} else {
330
// use numerical value value of leftmost lane to hopefully avoid sidewalks, bikelanes etc
331
const double doubleValue = (MSGlobals::gUseMesoSim
332
? getColorValue(s, activeScheme)
333
: lane2->getColorValueWithFunctional(s, activeScheme));
334
const RGBColor color = (MSGlobals::gUseMesoSim ? s.edgeColorer : s.laneColorer).getScheme().getColor(doubleValue);
335
if (doubleValue != s.MISSING_DATA
336
&& color.alpha() != 0
337
&& (!s.edgeValueRainBow.hideMin || doubleValue > s.edgeValueRainBow.minThreshold)
338
&& (!s.edgeValueRainBow.hideMax || doubleValue < s.edgeValueRainBow.maxThreshold)
339
) {
340
value = toString(doubleValue);
341
}
342
}
343
if (value != "") {
344
if (drawEdgeName || drawInternalEdgeName || drawCwaEdgeName) {
345
const double dist = 0.4 * (s.edgeName.scaledSize(s.scale) + s.edgeValue.scaledSize(s.scale));
346
const double shiftA = lane1->getShape(s2).rotationAtOffset(lane1->getShape(s2).length() / (double) 2.) - DEG2RAD(90);
347
Position shift(dist * cos(shiftA), dist * sin(shiftA));
348
p.add(shift);
349
}
350
GLHelper::drawTextSettings(s.edgeValue, value, p, s.scale, angle);
351
}
352
}
353
if (drawEdgeScaleValue) {
354
const int activeScheme = s.getLaneEdgeScaleMode();
355
std::string value = "";
356
// use numerical value value of leftmost lane to hopefully avoid sidewalks, bikelanes etc
357
const double doubleValue = (MSGlobals::gUseMesoSim
358
? getScaleValue(s, activeScheme)
359
: lane2->getScaleValue(s, activeScheme, s2));
360
if (doubleValue != s.MISSING_DATA) {
361
value = toString(doubleValue);
362
}
363
if (value != "") {
364
if (drawEdgeName || drawInternalEdgeName || drawCwaEdgeName || drawEdgeValue) {
365
const double dist = 0.4 * (s.edgeName.scaledSize(s.scale) + s.edgeScaleValue.scaledSize(s.scale));
366
const double shiftA = lane1->getShape(s2).rotationAtOffset(lane1->getShape(s2).length() / (double) 2.) - DEG2RAD(90);
367
Position shift(dist * cos(shiftA), dist * sin(shiftA));
368
p.add(shift);
369
}
370
GLHelper::drawTextSettings(s.edgeScaleValue, value, p, s.scale, angle);
371
}
372
}
373
}
374
}
375
if (s.scale * s.personSize.getExaggeration(s, nullptr) > s.personSize.minSize) {
376
FXMutexLock locker(myLock);
377
for (MSTransportable* t : myPersons) {
378
GUIPerson* person = dynamic_cast<GUIPerson*>(t);
379
assert(person != 0);
380
person->drawGL(s);
381
}
382
}
383
if (s.scale * s.containerSize.getExaggeration(s, nullptr) > s.containerSize.minSize) {
384
FXMutexLock locker(myLock);
385
for (MSTransportable* t : myContainers) {
386
GUIContainer* container = dynamic_cast<GUIContainer*>(t);
387
assert(container != 0);
388
container->drawGL(s);
389
}
390
}
391
}
392
393
394
void
395
GUIEdge::drawMesoVehicles(const GUIVisualizationSettings& s) const {
396
GUIMEVehicleControl* vehicleControl = GUINet::getGUIInstance()->getGUIMEVehicleControl();
397
const double now = SIMTIME;
398
if (vehicleControl != nullptr) {
399
// draw the meso vehicles
400
vehicleControl->secureVehicles();
401
FXMutexLock locker(myLock);
402
int laneIndex = 0;
403
for (std::vector<MSLane*>::const_iterator msl = myLanes->begin(); msl != myLanes->end(); ++msl, ++laneIndex) {
404
GUILane* l = static_cast<GUILane*>(*msl);
405
// go through the vehicles
406
double segmentOffset = 0; // offset at start of current segment
407
for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this);
408
segment != nullptr; segment = segment->getNextSegment()) {
409
const double length = segment->getLength();
410
if (laneIndex < segment->numQueues()) {
411
// make a copy so we don't have to worry about synchronization
412
std::vector<MEVehicle*> queue = segment->getQueue(laneIndex);
413
const int queueSize = (int)queue.size();
414
double vehiclePosition = segmentOffset + length;
415
// draw vehicles beginning with the leader at the end of the segment
416
double latOff = 0.;
417
for (int i = 0; i < queueSize; ++i) {
418
const GUIMEVehicle* const veh = static_cast<GUIMEVehicle*>(queue[queueSize - i - 1]);
419
const double intendedLeave = MIN2(veh->getEventTimeSeconds(), veh->getBlockTimeSeconds());
420
const double entry = veh->getLastEntryTimeSeconds();
421
const double relPos = segmentOffset + length * (now - entry) / (intendedLeave - entry);
422
if (relPos < vehiclePosition) {
423
vehiclePosition = relPos;
424
}
425
while (vehiclePosition < segmentOffset) {
426
// if there is only a single queue for a
427
// multi-lane edge shift vehicles and start
428
// drawing again from the end of the segment
429
vehiclePosition += length;
430
latOff += 0.2;
431
}
432
/// @fixme use correct shape for geometryPositionAtOffset
433
const Position p = l->geometryPositionAtOffset(vehiclePosition, latOff);
434
const double angle = l->getShape(s.secondaryShape).rotationAtOffset(l->interpolateLanePosToGeometryPos(vehiclePosition));
435
veh->drawOnPos(s, p, angle);
436
vehiclePosition -= veh->getVehicleType().getLengthWithGap();
437
}
438
}
439
segmentOffset += length;
440
}
441
GLHelper::popMatrix();
442
}
443
vehicleControl->releaseVehicles();
444
}
445
}
446
447
448
449
double
450
GUIEdge::getAllowedSpeed() const {
451
return (*myLanes)[0]->getSpeedLimit();
452
}
453
454
455
double
456
GUIEdge::getRelativeSpeed() const {
457
return getMeanSpeed() / getAllowedSpeed();
458
}
459
460
461
void
462
GUIEdge::setColor(const GUIVisualizationSettings& s) const {
463
myMesoColor = RGBColor(0, 0, 0); // default background color when using multiColor
464
const GUIColorer& c = s.edgeColorer;
465
if (!setFunctionalColor(c) && !setMultiColor(c)) {
466
myMesoColor = c.getScheme().getColor(getColorValue(s, c.getActive()));
467
}
468
}
469
470
471
bool
472
GUIEdge::setFunctionalColor(const GUIColorer& c) const {
473
const int activeScheme = c.getActive();
474
int activeMicroScheme = -1;
475
switch (activeScheme) {
476
case 0:
477
activeMicroScheme = 0; // color uniform
478
break;
479
case 9:
480
activeMicroScheme = 18; // color by angle
481
break;
482
case 17:
483
activeMicroScheme = 30; // color by TAZ
484
break;
485
default:
486
return false;
487
}
488
GUILane* guiLane = static_cast<GUILane*>(getLanes()[0]);
489
return guiLane->setFunctionalColor(c, myMesoColor, activeMicroScheme);
490
}
491
492
493
bool
494
GUIEdge::setMultiColor(const GUIColorer& c) const {
495
const int activeScheme = c.getActive();
496
mySegmentColors.clear();
497
switch (activeScheme) {
498
case 10: // alternating segments
499
for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this);
500
segment != nullptr; segment = segment->getNextSegment()) {
501
mySegmentColors.push_back(c.getScheme().getColor(segment->getIndex() % 2));
502
}
503
//std::cout << getID() << " scheme=" << c.getScheme().getName() << " schemeCols=" << c.getScheme().getColors().size() << " thresh=" << toString(c.getScheme().getThresholds()) << " segmentColors=" << mySegmentColors.size() << " [0]=" << mySegmentColors[0] << " [1]=" << mySegmentColors[1] << "\n";
504
return true;
505
case 11: // by segment jammed state
506
for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this);
507
segment != nullptr; segment = segment->getNextSegment()) {
508
mySegmentColors.push_back(
509
c.getScheme().getColor(segment->getRelativeOccupancy() > segment->getRelativeJamThreshold() ? 2 :
510
(segment->getRelativeOccupancy() * 2 < segment->getRelativeJamThreshold() ? 0 : 1)));
511
}
512
return true;
513
case 12: // by segment occupancy
514
for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this);
515
segment != nullptr; segment = segment->getNextSegment()) {
516
mySegmentColors.push_back(c.getScheme().getColor(segment->getRelativeOccupancy()));
517
}
518
return true;
519
case 13: // by segment speed
520
for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this);
521
segment != nullptr; segment = segment->getNextSegment()) {
522
mySegmentColors.push_back(c.getScheme().getColor(segment->getMeanSpeed()));
523
}
524
return true;
525
case 14: // by segment flow
526
for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this);
527
segment != nullptr; segment = segment->getNextSegment()) {
528
mySegmentColors.push_back(c.getScheme().getColor(3600 * segment->getCarNumber() * segment->getMeanSpeed() / segment->getLength()));
529
}
530
return true;
531
case 15: // by segment relative speed
532
for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this);
533
segment != nullptr; segment = segment->getNextSegment()) {
534
mySegmentColors.push_back(c.getScheme().getColor(segment->getMeanSpeed() / getAllowedSpeed()));
535
}
536
return true;
537
default:
538
return false;
539
}
540
}
541
542
543
double
544
GUIEdge::getColorValue(const GUIVisualizationSettings& s, int activeScheme) const {
545
switch (activeScheme) {
546
case 1:
547
return gSelected.isSelected(getType(), getGlID());
548
case 2:
549
return (double)getFunction();
550
case 3:
551
return getAllowedSpeed();
552
case 4:
553
return getBruttoOccupancy();
554
case 5:
555
return getMeanSpeed();
556
case 6:
557
return getFlow();
558
case 7:
559
return getRelativeSpeed();
560
case 8:
561
return getRoutingSpeed();
562
case 16:
563
return getPendingEmits();
564
case 18:
565
// by numerical edge param value
566
try {
567
return StringUtils::toDouble(getParameter(s.edgeParam, "0"));
568
} catch (NumberFormatException&) {
569
try {
570
return StringUtils::toBool(getParameter(s.edgeParam, "0"));
571
} catch (BoolFormatException&) {
572
return -1;
573
}
574
}
575
case 19:
576
// by edge data value
577
return GUINet::getGUIInstance()->getEdgeData(this, s.edgeData);
578
}
579
return 0;
580
}
581
582
583
double
584
GUIEdge::getScaleValue(const GUIVisualizationSettings& s, int activeScheme) const {
585
switch (activeScheme) {
586
case 1:
587
return gSelected.isSelected(getType(), getGlID());
588
case 2:
589
return getAllowedSpeed();
590
case 3:
591
return getBruttoOccupancy();
592
case 4:
593
return getMeanSpeed();
594
case 5:
595
return getFlow();
596
case 6:
597
return getRelativeSpeed();
598
case 7:
599
return getPendingEmits();
600
case 8:
601
// by edge data value
602
return GUINet::getGUIInstance()->getEdgeData(this, s.edgeDataScaling);
603
}
604
return 0;
605
}
606
607
608
MESegment*
609
GUIEdge::getSegmentAtPosition(const Position& pos) {
610
const PositionVector& shape = getLanes()[0]->getShape();
611
const double lanePos = shape.nearest_offset_to_point2D(pos);
612
return MSGlobals::gMesoNet->getSegmentForEdge(*this, lanePos);
613
}
614
615
616
617
void
618
GUIEdge::closeTraffic(const GUILane* lane) {
619
const std::vector<MSLane*>& lanes = getLanes();
620
const bool isClosed = lane->isClosed();
621
for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
622
GUILane* l = dynamic_cast<GUILane*>(*i);
623
if (l->isClosed() == isClosed) {
624
l->closeTraffic(false);
625
}
626
}
627
rebuildAllowedLanes();
628
}
629
630
631
void
632
GUIEdge::addRerouter() {
633
MSEdgeVector edges;
634
edges.push_back(this);
635
GUITriggeredRerouter* rr = new GUITriggeredRerouter(getID() + "_dynamic_rerouter", edges, 1, false, false, 0, "", Position::INVALID,
636
std::numeric_limits<double>::max(), GUINet::getGUIInstance()->getVisualisationSpeedUp());
637
638
MSTriggeredRerouter::RerouteInterval ri;
639
ri.begin = MSNet::getInstance()->getCurrentTimeStep();
640
ri.end = SUMOTime_MAX;
641
ri.edgeProbs.add(&MSTriggeredRerouter::mySpecialDest_keepDestination, 1.);
642
rr->myIntervals.push_back(ri);
643
644
// trigger rerouting for vehicles already on this edge
645
const std::vector<MSLane*>& lanes = getLanes();
646
for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
647
const MSLane::VehCont& vehicles = (*i)->getVehiclesSecure();
648
for (MSLane::VehCont::const_iterator v = vehicles.begin(); v != vehicles.end(); ++v) {
649
if ((*v)->getLane() == (*i)) {
650
rr->notifyEnter(**v, MSMoveReminder::NOTIFICATION_JUNCTION);
651
} // else: this is the shadow during a continuous lane change
652
}
653
(*i)->releaseVehicles();
654
}
655
}
656
657
658
bool
659
GUIEdge::isSelected() const {
660
return gSelected.isSelected(GLO_EDGE, getGlID());
661
}
662
663
double
664
GUIEdge::getPendingEmits() const {
665
return MSNet::getInstance()->getInsertionControl().getPendingEmits(getLanes()[0]);
666
}
667
668
double
669
GUIEdge::getClickPriority() const {
670
if (!MSGlobals::gUseMesoSim) {
671
// do not select edgse in meso mode
672
return INVALID_PRIORITY;
673
}
674
return GLO_EDGE;
675
}
676
/****************************************************************************/
677
678