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