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 GUIBaseVehicle.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @author Laura Bieker-Walz
19 : /// @date Sept 2002
20 : ///
21 : // A MSVehicle extended by some values for usage within the gui
22 : /****************************************************************************/
23 : #include <config.h>
24 :
25 : #include <cmath>
26 : #include <vector>
27 : #include <string>
28 : #include <functional>
29 : #include <utils/common/MsgHandler.h>
30 : #include <utils/common/StringUtils.h>
31 : #include <utils/common/StringTokenizer.h>
32 : #include <utils/geom/GeomHelper.h>
33 : #include <utils/vehicle/SUMOVehicleParameter.h>
34 : #include <utils/emissions/PollutantsInterface.h>
35 : #include <utils/gui/globjects/GLIncludes.h>
36 : #include <utils/gui/windows/GUISUMOAbstractView.h>
37 : #include <utils/gui/windows/GUIAppEnum.h>
38 : #include <utils/gui/images/GUITexturesHelper.h>
39 : #include <utils/gui/div/GUIGlobalSelection.h>
40 : #include <utils/gui/div/GLHelper.h>
41 : #include <utils/gui/div/GUIGlobalSelection.h>
42 : #include <utils/gui/div/GUIBaseVehicleHelper.h>
43 : #include <mesosim/MEVehicle.h>
44 : #include <mesosim/MELoop.h>
45 : #include <microsim/MSVehicle.h>
46 : #include <microsim/MSLane.h>
47 : #include <microsim/logging/CastingFunctionBinding.h>
48 : #include <microsim/logging/FunctionBinding.h>
49 : #include <microsim/MSVehicleControl.h>
50 : #include <microsim/MSStop.h>
51 : #include <microsim/MSTrainHelper.h>
52 : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
53 : #include <microsim/devices/MSDevice_Vehroutes.h>
54 : #include <microsim/devices/MSDevice_Transportable.h>
55 : #include <microsim/devices/MSDevice_BTreceiver.h>
56 : #include <microsim/trigger/MSStoppingPlaceRerouter.h>
57 : #include <gui/GUIApplicationWindow.h>
58 : #include <gui/GUIGlobals.h>
59 : #include <utils/gui/div/GUIDesigns.h>
60 :
61 : #include "GUIBaseVehicle.h"
62 : #include "GUIChargingStation.h"
63 : #include "GUIPerson.h"
64 : #include "GUIContainer.h"
65 : #include "GUINet.h"
66 : #include "GUIEdge.h"
67 : #include "GUILane.h"
68 : #include "GUIParkingArea.h"
69 :
70 : //#define DRAW_BOUNDING_BOX
71 :
72 : // ===========================================================================
73 : // FOX callback mapping
74 : // ===========================================================================
75 : FXDEFMAP(GUIBaseVehicle::GUIBaseVehiclePopupMenu) GUIBaseVehiclePopupMenuMap[] = {
76 : FXMAPFUNC(SEL_COMMAND, MID_SHOW_ALLROUTES, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowAllRoutes),
77 : FXMAPFUNC(SEL_COMMAND, MID_HIDE_ALLROUTES, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideAllRoutes),
78 : FXMAPFUNC(SEL_COMMAND, MID_SHOW_CURRENTROUTE, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowCurrentRoute),
79 : FXMAPFUNC(SEL_COMMAND, MID_HIDE_CURRENTROUTE, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideCurrentRoute),
80 : FXMAPFUNC(SEL_COMMAND, MID_SHOW_FUTUREROUTE, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowFutureRoute),
81 : FXMAPFUNC(SEL_COMMAND, MID_HIDE_FUTUREROUTE, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideFutureRoute),
82 : FXMAPFUNC(SEL_COMMAND, MID_SHOW_ROUTE_NOLOOPS, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowRouteNoLoops),
83 : FXMAPFUNC(SEL_COMMAND, MID_HIDE_ROUTE_NOLOOPS, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideRouteNoLoops),
84 : FXMAPFUNC(SEL_COMMAND, MID_SHOW_BEST_LANES, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowBestLanes),
85 : FXMAPFUNC(SEL_COMMAND, MID_HIDE_BEST_LANES, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideBestLanes),
86 : FXMAPFUNC(SEL_COMMAND, MID_START_TRACK, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdStartTrack),
87 : FXMAPFUNC(SEL_COMMAND, MID_STOP_TRACK, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdStopTrack),
88 : FXMAPFUNC(SEL_COMMAND, MID_SHOW_LFLINKITEMS, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowLFLinkItems),
89 : FXMAPFUNC(SEL_COMMAND, MID_HIDE_LFLINKITEMS, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideLFLinkItems),
90 : FXMAPFUNC(SEL_COMMAND, MID_SHOW_FOES, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowFoes),
91 : FXMAPFUNC(SEL_COMMAND, MID_SELECT_TRANSPORTED, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdSelectTransported),
92 : FXMAPFUNC(SEL_COMMAND, MID_REMOVE_OBJECT, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdRemoveObject),
93 : FXMAPFUNC(SEL_COMMAND, MID_TOGGLE_STOP, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdToggleStop),
94 : };
95 :
96 : // Object implementation
97 0 : FXIMPLEMENT(GUIBaseVehicle::GUIBaseVehiclePopupMenu, GUIGLObjectPopupMenu, GUIBaseVehiclePopupMenuMap, ARRAYNUMBER(GUIBaseVehiclePopupMenuMap))
98 :
99 : // ===========================================================================
100 : // method definitions
101 : // ===========================================================================
102 : /* -------------------------------------------------------------------------
103 : * GUIBaseVehicle::GUIBaseVehiclePopupMenu - methods
104 : * ----------------------------------------------------------------------- */
105 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::GUIBaseVehiclePopupMenu(
106 0 : GUIMainWindow& app, GUISUMOAbstractView& parent, GUIGlObject& o)
107 0 : : GUIGLObjectPopupMenu(app, parent, o) {
108 0 : }
109 :
110 :
111 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::~GUIBaseVehiclePopupMenu() {}
112 :
113 :
114 : long
115 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowAllRoutes(FXObject*, FXSelector, void*) {
116 : assert(myObject->getType() == GLO_VEHICLE);
117 0 : if (!static_cast<GUIBaseVehicle*>(myObject)->hasActiveAddVisualisation(myParent, VO_SHOW_ALL_ROUTES)) {
118 0 : static_cast<GUIBaseVehicle*>(myObject)->addActiveAddVisualisation(myParent, VO_SHOW_ALL_ROUTES);
119 : }
120 0 : return 1;
121 : }
122 :
123 : long
124 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideAllRoutes(FXObject*, FXSelector, void*) {
125 : assert(myObject->getType() == GLO_VEHICLE);
126 0 : static_cast<GUIBaseVehicle*>(myObject)->removeActiveAddVisualisation(myParent, VO_SHOW_ALL_ROUTES);
127 0 : return 1;
128 : }
129 :
130 :
131 : long
132 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowCurrentRoute(FXObject*, FXSelector, void*) {
133 : assert(myObject->getType() == GLO_VEHICLE);
134 0 : if (!static_cast<GUIBaseVehicle*>(myObject)->hasActiveAddVisualisation(myParent, VO_SHOW_ROUTE)) {
135 0 : static_cast<GUIBaseVehicle*>(myObject)->addActiveAddVisualisation(myParent, VO_SHOW_ROUTE);
136 : }
137 0 : return 1;
138 : }
139 :
140 : long
141 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideCurrentRoute(FXObject*, FXSelector, void*) {
142 : assert(myObject->getType() == GLO_VEHICLE);
143 0 : static_cast<GUIBaseVehicle*>(myObject)->removeActiveAddVisualisation(myParent, VO_SHOW_ROUTE);
144 0 : return 1;
145 : }
146 :
147 :
148 : long
149 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowFutureRoute(FXObject*, FXSelector, void*) {
150 : assert(myObject->getType() == GLO_VEHICLE);
151 0 : if (!static_cast<GUIBaseVehicle*>(myObject)->hasActiveAddVisualisation(myParent, VO_SHOW_FUTURE_ROUTE)) {
152 0 : static_cast<GUIBaseVehicle*>(myObject)->addActiveAddVisualisation(myParent, VO_SHOW_FUTURE_ROUTE);
153 : }
154 0 : return 1;
155 : }
156 :
157 : long
158 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideFutureRoute(FXObject*, FXSelector, void*) {
159 : assert(myObject->getType() == GLO_VEHICLE);
160 0 : static_cast<GUIBaseVehicle*>(myObject)->removeActiveAddVisualisation(myParent, VO_SHOW_FUTURE_ROUTE);
161 0 : return 1;
162 : }
163 :
164 :
165 : long
166 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowRouteNoLoops(FXObject*, FXSelector, void*) {
167 : assert(myObject->getType() == GLO_VEHICLE);
168 0 : if (!static_cast<GUIBaseVehicle*>(myObject)->hasActiveAddVisualisation(myParent, VO_SHOW_ROUTE_NOLOOP)) {
169 0 : static_cast<GUIBaseVehicle*>(myObject)->addActiveAddVisualisation(myParent, VO_SHOW_ROUTE_NOLOOP);
170 : }
171 0 : return 1;
172 : }
173 :
174 : long
175 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideRouteNoLoops(FXObject*, FXSelector, void*) {
176 : assert(myObject->getType() == GLO_VEHICLE);
177 0 : static_cast<GUIBaseVehicle*>(myObject)->removeActiveAddVisualisation(myParent, VO_SHOW_ROUTE_NOLOOP);
178 0 : return 1;
179 : }
180 :
181 :
182 : long
183 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowBestLanes(FXObject*, FXSelector, void*) {
184 : assert(myObject->getType() == GLO_VEHICLE);
185 0 : if (!static_cast<GUIBaseVehicle*>(myObject)->hasActiveAddVisualisation(myParent, VO_SHOW_BEST_LANES)) {
186 0 : static_cast<GUIBaseVehicle*>(myObject)->addActiveAddVisualisation(myParent, VO_SHOW_BEST_LANES);
187 : }
188 0 : return 1;
189 : }
190 :
191 : long
192 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideBestLanes(FXObject*, FXSelector, void*) {
193 : assert(myObject->getType() == GLO_VEHICLE);
194 0 : static_cast<GUIBaseVehicle*>(myObject)->removeActiveAddVisualisation(myParent, VO_SHOW_BEST_LANES);
195 0 : return 1;
196 : }
197 :
198 :
199 : long
200 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdStartTrack(FXObject*, FXSelector, void*) {
201 : assert(myObject->getType() == GLO_VEHICLE);
202 0 : if (myParent->getTrackedID() != static_cast<GUIBaseVehicle*>(myObject)->getGlID()) {
203 0 : myParent->startTrack(static_cast<GUIBaseVehicle*>(myObject)->getGlID());
204 : }
205 0 : return 1;
206 : }
207 :
208 : long
209 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdStopTrack(FXObject*, FXSelector, void*) {
210 : assert(myObject->getType() == GLO_VEHICLE);
211 0 : myParent->stopTrack();
212 0 : return 1;
213 : }
214 :
215 :
216 : long
217 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowLFLinkItems(FXObject*, FXSelector, void*) {
218 : assert(myObject->getType() == GLO_VEHICLE);
219 0 : if (!static_cast<GUIBaseVehicle*>(myObject)->hasActiveAddVisualisation(myParent, VO_SHOW_LFLINKITEMS)) {
220 0 : static_cast<GUIBaseVehicle*>(myObject)->addActiveAddVisualisation(myParent, VO_SHOW_LFLINKITEMS);
221 : }
222 0 : return 1;
223 : }
224 :
225 : long
226 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideLFLinkItems(FXObject*, FXSelector, void*) {
227 : assert(myObject->getType() == GLO_VEHICLE);
228 0 : static_cast<GUIBaseVehicle*>(myObject)->removeActiveAddVisualisation(myParent, VO_SHOW_LFLINKITEMS);
229 0 : return 1;
230 : }
231 :
232 : long
233 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowFoes(FXObject*, FXSelector, void*) {
234 : assert(myObject->getType() == GLO_VEHICLE);
235 0 : static_cast<GUIBaseVehicle*>(myObject)->selectBlockingFoes();
236 0 : myParent->update();
237 0 : return 1;
238 : }
239 :
240 :
241 : long
242 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdSelectTransported(FXObject*, FXSelector, void*) {
243 : assert(myObject->getType() == GLO_VEHICLE);
244 0 : const MSBaseVehicle& veh = static_cast<GUIBaseVehicle*>(myObject)->getVehicle();
245 0 : for (const MSTransportable* t : veh.getPersons()) {
246 0 : gSelected.select((static_cast<const GUIPerson*>(t))->getGlID());
247 : }
248 0 : for (MSTransportable* t : veh.getContainers()) {
249 0 : gSelected.select((static_cast<const GUIContainer*>(t))->getGlID());
250 : }
251 0 : myParent->update();
252 0 : return 1;
253 : }
254 :
255 : long
256 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdRemoveObject(FXObject*, FXSelector, void*) {
257 0 : GUIBaseVehicle* baseVeh = static_cast<GUIBaseVehicle*>(myObject);
258 0 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(&baseVeh->myVehicle);
259 0 : if (microVeh != nullptr) {
260 : MSLane* lane = microVeh->getMutableLane();
261 0 : if (lane != nullptr) {
262 0 : lane->getVehiclesSecure();
263 0 : lane->removeVehicle(microVeh, MSMoveReminder::NOTIFICATION_VAPORIZED_GUI);
264 : }
265 0 : microVeh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_VAPORIZED_GUI);
266 0 : if (lane != nullptr) {
267 0 : lane->releaseVehicles();
268 : }
269 : } else {
270 0 : MEVehicle* mesoVeh = dynamic_cast<MEVehicle*>(&baseVeh->myVehicle);
271 0 : MSGlobals::gMesoNet->vaporizeCar(mesoVeh, MSMoveReminder::NOTIFICATION_VAPORIZED_GUI);
272 : }
273 0 : MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(&baseVeh->myVehicle);
274 0 : myParent->destroyPopup();
275 0 : myParent->update();
276 0 : return 1;
277 : }
278 :
279 :
280 : long
281 0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdToggleStop(FXObject*, FXSelector, void*) {
282 0 : GUIBaseVehicle* baseVeh = static_cast<GUIBaseVehicle*>(myObject);
283 0 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(&baseVeh->myVehicle);
284 0 : if (microVeh != nullptr) {
285 0 : if (microVeh->isStopped()) {
286 0 : microVeh->resumeFromStopping();
287 : } else {
288 : std::string errorOut;
289 0 : const double brakeGap = microVeh->getCarFollowModel().brakeGap(microVeh->getSpeed());
290 0 : std::pair<const MSLane*, double> stopPos = microVeh->getLanePosAfterDist(brakeGap);
291 0 : if (stopPos.first != nullptr) {
292 0 : SUMOVehicleParameter::Stop stop;
293 : stop.lane = stopPos.first->getID();
294 0 : stop.startPos = stopPos.second;
295 0 : stop.endPos = stopPos.second + POSITION_EPS;
296 0 : stop.duration = TIME2STEPS(3600);
297 0 : microVeh->addTraciStop(stop, errorOut);
298 0 : if (errorOut != "") {
299 0 : WRITE_WARNING(errorOut);
300 : }
301 0 : }
302 : }
303 : } else {
304 0 : WRITE_WARNING(TL("GUI-triggered stop not implemented for meso"));
305 : }
306 0 : myParent->update();
307 0 : return 1;
308 : }
309 :
310 :
311 : /* -------------------------------------------------------------------------
312 : * GUIBaseVehicle - methods
313 : * ----------------------------------------------------------------------- */
314 :
315 765017 : GUIBaseVehicle::GUIBaseVehicle(MSBaseVehicle& vehicle) :
316 : GUIGlObject(GLO_VEHICLE, vehicle.getID(), GUIIconSubSys::getIcon(GUIIcon::VEHICLE)),
317 765017 : myVehicle(vehicle),
318 765017 : myPopup(nullptr) {
319 : // as it is possible to show all vehicle routes, we have to store them... (bug [ 2519761 ])
320 765017 : myRoutes = MSDevice_Vehroutes::buildVehicleDevices(myVehicle, myVehicle.myDevices, 5);
321 765017 : myVehicle.myMoveReminders.push_back(std::make_pair(myRoutes, 0.));
322 765017 : mySeatPositions.push_back(Seat()); // ensure length 1
323 765017 : myContainerPositions.push_back(Seat()); // ensure length 1
324 765017 : }
325 :
326 :
327 764972 : GUIBaseVehicle::~GUIBaseVehicle() {
328 764972 : myLock.lock();
329 764981 : for (std::map<GUISUMOAbstractView*, int>::iterator i = myAdditionalVisualizations.begin(); i != myAdditionalVisualizations.end(); ++i) {
330 9 : if (i->first->getTrackedID() == getGlID()) {
331 0 : i->first->stopTrack();
332 : }
333 13 : while (i->first->removeAdditionalGLVisualisation(this));
334 : }
335 764972 : myLock.unlock();
336 764972 : delete myRoutes;
337 764972 : if (myPopup != nullptr) {
338 0 : myPopup->getParentView()->destroyPopup();
339 : }
340 1529944 : }
341 :
342 :
343 : GUIGLObjectPopupMenu*
344 0 : GUIBaseVehicle::getPopUpMenu(GUIMainWindow& app,
345 : GUISUMOAbstractView& parent) {
346 0 : GUIGLObjectPopupMenu* ret = new GUIBaseVehiclePopupMenu(app, parent, *this);
347 0 : buildPopupHeader(ret, app);
348 0 : buildCenterPopupEntry(ret);
349 0 : buildNameCopyPopupEntry(ret);
350 0 : buildSelectionPopupEntry(ret);
351 : //
352 0 : if (hasActiveAddVisualisation(&parent, VO_SHOW_ROUTE)) {
353 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Hide Current Route"), nullptr, ret, MID_HIDE_CURRENTROUTE);
354 : } else {
355 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Show Current Route"), nullptr, ret, MID_SHOW_CURRENTROUTE);
356 : }
357 0 : if (hasActiveAddVisualisation(&parent, VO_SHOW_FUTURE_ROUTE)) {
358 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Hide Future Route"), nullptr, ret, MID_HIDE_FUTUREROUTE);
359 : } else {
360 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Show Future Route"), nullptr, ret, MID_SHOW_FUTUREROUTE);
361 : }
362 0 : if (hasActiveAddVisualisation(&parent, VO_SHOW_ALL_ROUTES)) {
363 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Hide All Routes"), nullptr, ret, MID_HIDE_ALLROUTES);
364 : } else {
365 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Show All Routes"), nullptr, ret, MID_SHOW_ALLROUTES);
366 : }
367 0 : if (hasActiveAddVisualisation(&parent, VO_SHOW_ROUTE_NOLOOP)) {
368 0 : FXMenuCheck* showLoops = new FXMenuCheck(ret, TL("Draw looped routes"), ret, MID_HIDE_ROUTE_NOLOOPS);
369 0 : showLoops->setCheck(false);
370 : } else {
371 0 : FXMenuCheck* showLoops = new FXMenuCheck(ret, TL("Draw looped routes"), ret, MID_SHOW_ROUTE_NOLOOPS);
372 0 : showLoops->setCheck(true);
373 : }
374 0 : if (hasActiveAddVisualisation(&parent, VO_SHOW_BEST_LANES)) {
375 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Hide Best Lanes"), nullptr, ret, MID_HIDE_BEST_LANES);
376 : } else {
377 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Show Best Lanes"), nullptr, ret, MID_SHOW_BEST_LANES);
378 : }
379 0 : if (hasActiveAddVisualisation(&parent, VO_SHOW_LFLINKITEMS)) {
380 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Hide Link Items"), nullptr, ret, MID_HIDE_LFLINKITEMS);
381 : } else {
382 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Show Link Items"), nullptr, ret, MID_SHOW_LFLINKITEMS);
383 : }
384 0 : new FXMenuSeparator(ret);
385 0 : if (parent.getTrackedID() != getGlID()) {
386 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Start Tracking"), nullptr, ret, MID_START_TRACK);
387 : } else {
388 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Stop Tracking"), nullptr, ret, MID_STOP_TRACK);
389 : }
390 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Select Foes"), nullptr, ret, MID_SHOW_FOES);
391 0 : if (myVehicle.getPersons().size() + myVehicle.getContainers().size() > 0) {
392 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Select transported"), nullptr, ret, MID_SELECT_TRANSPORTED);
393 : }
394 0 : GUIDesigns::buildFXMenuCommand(ret, myVehicle.isStopped() ? TL("Abort stop") : TL("Stop"), nullptr, ret, MID_TOGGLE_STOP);
395 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Remove"), nullptr, ret, MID_REMOVE_OBJECT);
396 :
397 0 : new FXMenuSeparator(ret);
398 : //
399 0 : buildShowParamsPopupEntry(ret, false);
400 0 : buildShowTypeParamsPopupEntry(ret);
401 0 : buildPositionCopyEntry(ret, app);
402 0 : myPopup = ret;
403 0 : return ret;
404 : }
405 :
406 :
407 : void
408 0 : GUIBaseVehicle::removedPopupMenu() {
409 0 : myPopup = nullptr;
410 0 : }
411 :
412 :
413 : double
414 8161492 : GUIBaseVehicle::getExaggeration(const GUIVisualizationSettings& s) const {
415 8161492 : return (s.vehicleSize.getExaggeration(s, this) *
416 8161492 : s.vehicleScaler.getScheme().getColor(getScaleValue(s, s.vehicleScaler.getActive())));
417 : }
418 :
419 :
420 : Boundary
421 0 : GUIBaseVehicle::getCenteringBoundary() const {
422 0 : Boundary b;
423 0 : b.add(getVisualPosition(GUIGlobals::gSecondaryShape));
424 0 : b.grow(myVehicle.getVehicleType().getLength());
425 0 : return b;
426 0 : }
427 :
428 :
429 : const std::string
430 0 : GUIBaseVehicle::getOptionalName() const {
431 0 : return myVehicle.getParameter().getParameter("name", "");
432 : }
433 :
434 :
435 : void
436 8949371 : GUIBaseVehicle::drawOnPos(const GUIVisualizationSettings& s, const Position& pos, const double angle) const {
437 8949371 : GLHelper::pushName(getGlID());
438 8949371 : GLHelper::pushMatrix();
439 8949371 : Position p1 = pos;
440 8949371 : const double degAngle = RAD2DEG(angle + M_PI / 2.);
441 : const double length = getVType().getLength();
442 8949371 : if (s.trueZ) {
443 284 : glTranslated(p1.x(), p1.y(), p1.z() + 1);
444 : } else {
445 8949087 : glTranslated(p1.x(), p1.y(), getType());
446 : }
447 8949371 : glRotated(degAngle, 0, 0, 1);
448 8949371 : RGBColor col = setColor(s);
449 : // scale
450 8949371 : const double upscale = getExaggeration(s);
451 8949371 : const bool s2 = s.secondaryShape;
452 :
453 8949371 : if (upscale > 1 && s.laneWidthExaggeration > 1 && myVehicle.isOnRoad()) {
454 : // optionally shift according to edge exaggeration
455 0 : double offsetFromLeftBorder = myVehicle.getCurrentEdge()->getWidth() - myVehicle.getRightSideOnEdge() - myVehicle.getVehicleType().getWidth() / 2;
456 0 : glTranslated((s.laneWidthExaggeration - 1) * -offsetFromLeftBorder / 2, 0, 0);
457 : }
458 :
459 8949371 : double upscaleLength = MSTrainHelper::getUpscaleLength(upscale, length, getVType().getWidth(), s.vehicleQuality);
460 8949371 : glScaled(upscale, upscaleLength, 1);
461 : /*
462 : MSLaneChangeModel::DK2004 &m2 = static_cast<MSLaneChangeModel::DK2004&>(veh->getLaneChangeModel());
463 : if((m2.getState()&LCA_URGENT)!=0) {
464 : glColor3d(1, .4, .4);
465 : } else if((m2.getState()&LCA_SPEEDGAIN)!=0) {
466 : glColor3d(.4, .4, 1);
467 : } else {
468 : glColor3d(.4, 1, .4);
469 : }
470 : */
471 : // draw the vehicle
472 : bool drawCarriages = false;
473 8949371 : const double geometryFactor = (s.scaleLength ?
474 8949371 : ((myVehicle.getLane() != nullptr
475 8949371 : ? myVehicle.getLane()->getLengthGeometryFactor(s2)
476 787879 : : (myVehicle.getEdge()->getLanes().size() > 0 ? myVehicle.getEdge()->getLanes()[0]->getLengthGeometryFactor(s2) : 1)))
477 : : 1);
478 8949371 : double scaledLength = length * geometryFactor;
479 8949371 : if (col.alpha() != 0) {
480 8949371 : switch (s.vehicleQuality) {
481 8729189 : case 0:
482 8729189 : GUIBaseVehicleHelper::drawAction_drawVehicleAsTrianglePlus(getVType().getWidth(), scaledLength, drawReversed(s));
483 : break;
484 0 : case 1:
485 0 : GUIBaseVehicleHelper::drawAction_drawVehicleAsBoxPlus(getVType().getWidth(), scaledLength, drawReversed(s));
486 : break;
487 212007 : case 2:
488 212007 : drawCarriages = drawAction_drawVehicleAsPolyWithCarriagges(s, scaledLength);
489 : // draw flashing blue light for emergency vehicles
490 212007 : if (getVType().getGuiShape() == SUMOVehicleShape::EMERGENCY) {
491 0 : glTranslated(0, 0, .1);
492 0 : drawAction_drawVehicleBlueLight();
493 : }
494 : break;
495 8175 : case 3:
496 8175 : drawCarriages = drawAction_drawVehicleAsPolyWithCarriagges(s, scaledLength, true);
497 : break;
498 : case 4: {
499 : // do not scale circle radius by lengthGeometryFactor nor length and reduce the effect of width
500 0 : const double w = 1.8 * sqrt(getVType().getWidth() / 1.8);
501 0 : GUIBaseVehicleHelper::drawAction_drawVehicleAsCircle(w, s.scale * upscale);
502 : // display text at circle center
503 : scaledLength = 0;
504 : break;
505 : }
506 : default:
507 : break;
508 : }
509 8949371 : if (s.drawMinGap) {
510 0 : const double minGap = -getVType().getMinGap();
511 0 : glColor3d(0., 1., 0.);
512 0 : glBegin(GL_LINES);
513 0 : glVertex2d(0., 0);
514 0 : glVertex2d(0., minGap);
515 0 : glVertex2d(-.5, minGap);
516 0 : glVertex2d(.5, minGap);
517 0 : glEnd();
518 : }
519 0 : if (s.drawBrakeGap && !MSGlobals::gUseMesoSim
520 8949371 : && (!s.vehicleSize.constantSizeSelected || myVehicle.isSelected())) {
521 0 : const double brakeGap = -static_cast<MSVehicle&>(myVehicle).getCarFollowModel().brakeGap(myVehicle.getSpeed());
522 0 : glColor3d(1., 0., 0.);
523 0 : glBegin(GL_LINES);
524 0 : glVertex2d(0., 0);
525 0 : glVertex2d(0., brakeGap);
526 0 : glVertex2d(-.5, brakeGap);
527 0 : glVertex2d(.5, brakeGap);
528 0 : glEnd();
529 : }
530 8949371 : if (s.showBTRange) {
531 0 : MSVehicleDevice_BTreceiver* dev = static_cast<MSVehicleDevice_BTreceiver*>(myVehicle.getDevice(typeid(MSVehicleDevice_BTreceiver)));
532 : if (dev != nullptr) {
533 0 : glColor3d(1., 0., 0.);
534 0 : GLHelper::drawOutlineCircle(dev->getRange(), dev->getRange() - .2, 32);
535 : }
536 : }
537 : // draw the blinker and brakelights if wished
538 8949371 : if (s.showBlinker) {
539 8949371 : glTranslated(0, 0, .1);
540 8949371 : switch (getVType().getGuiShape()) {
541 : case SUMOVehicleShape::PEDESTRIAN:
542 : case SUMOVehicleShape::BICYCLE:
543 : case SUMOVehicleShape::SCOOTER:
544 : case SUMOVehicleShape::ANT:
545 : case SUMOVehicleShape::SHIP:
546 : case SUMOVehicleShape::RAIL:
547 : case SUMOVehicleShape::RAIL_CARGO:
548 : case SUMOVehicleShape::RAIL_CAR:
549 : case SUMOVehicleShape::AIRCRAFT:
550 : break;
551 514995 : case SUMOVehicleShape::MOTORCYCLE:
552 : case SUMOVehicleShape::MOPED:
553 514995 : drawAction_drawVehicleBlinker(scaledLength);
554 514995 : drawAction_drawVehicleBrakeLight(scaledLength, true);
555 : break;
556 7943605 : default:
557 : // only SUMOVehicleShape::RAIL_CAR has blinkers and brake lights but they are drawn along with the carriages
558 7943605 : if (!drawCarriages) {
559 7942212 : drawAction_drawVehicleBlinker(scaledLength);
560 7942212 : drawAction_drawVehicleBrakeLight(scaledLength);
561 : }
562 : break;
563 : }
564 : }
565 : // draw the wish to change the lane
566 : if (s.drawLaneChangePreference) {
567 : /*
568 : if(gSelected.isSelected(GLO_VEHICLE, veh->getGlID())) {
569 : MSLaneChangeModel::DK2004 &m = static_cast<MSLaneChangeModel::DK2004&>(veh->getLaneChangeModel());
570 : glColor3d(.5, .5, 1);
571 : glBegin(GL_LINES);
572 : glVertex2f(0, 0);
573 : glVertex2f(m.getChangeProbability(), .5);
574 : glEnd();
575 :
576 : glColor3d(1, 0, 0);
577 : glBegin(GL_LINES);
578 : glVertex2f(0.1, 0);
579 : glVertex2f(0.1, m.myMaxJam1);
580 : glEnd();
581 :
582 : glColor3d(0, 1, 0);
583 : glBegin(GL_LINES);
584 : glVertex2f(-0.1, 0);
585 : glVertex2f(-0.1, m.myTDist);
586 : glEnd();
587 : }
588 : */
589 : }
590 : }
591 9012503 : glTranslated(0, MIN2(scaledLength / 2, double(5)), -getType()); // drawing name at GLO_MAX fails unless translating z
592 8949371 : glScaled(1 / upscale, 1 / upscaleLength, 1);
593 8949371 : glRotated(-degAngle, 0, 0, 1);
594 8949371 : drawName(Position(0, 0), s.scale, s.vehicleName, s.angle);
595 8949371 : if (s.vehicleName.show(this) && myVehicle.getParameter().line != "") {
596 0 : glRotated(-s.angle, 0, 0, 1);
597 0 : glTranslated(0, 0.7 * s.vehicleName.scaledSize(s.scale), 0);
598 0 : glRotated(s.angle, 0, 0, 1);
599 0 : GLHelper::drawTextSettings(s.vehicleName, "line:" + myVehicle.getParameter().line, Position(0, 0), s.scale, s.angle);
600 : }
601 8949371 : if (s.vehicleValue.show(this)) {
602 0 : glRotated(-s.angle, 0, 0, 1);
603 0 : glTranslated(0, 0.7 * s.vehicleName.scaledSize(s.scale), 0);
604 0 : glRotated(s.angle, 0, 0, 1);
605 0 : const double value = getColorValue(s, s.vehicleColorer.getActive());
606 0 : GLHelper::drawTextSettings(s.vehicleValue, toString(value), Position(0, 0), s.scale, s.angle);
607 : }
608 8949371 : if (s.vehicleScaleValue.show(this)) {
609 0 : glRotated(-s.angle, 0, 0, 1);
610 0 : glTranslated(0, 0.7 * s.vehicleName.scaledSize(s.scale), 0);
611 0 : glRotated(s.angle, 0, 0, 1);
612 0 : const double value = getScaleValue(s, s.vehicleScaler.getActive());
613 0 : GLHelper::drawTextSettings(s.vehicleScaleValue, toString(value), Position(0, 0), s.scale, s.angle);
614 : }
615 8949371 : if (s.vehicleText.show(this)) {
616 : std::string error;
617 0 : std::string value = myVehicle.getPrefixedParameter(s.vehicleTextParam, error);
618 0 : if (value != "") {
619 0 : auto lines = StringTokenizer(value, StringTokenizer::NEWLINE).getVector();
620 0 : glRotated(-s.angle, 0, 0, 1);
621 0 : glTranslated(0, 0.7 * s.vehicleText.scaledSize(s.scale) * (double)lines.size(), 0);
622 0 : glRotated(s.angle, 0, 0, 1);
623 0 : for (std::string& line : lines) {
624 0 : GLHelper::drawTextSettings(s.vehicleText, line, Position(0, 0), s.scale, s.angle);
625 0 : glRotated(-s.angle, 0, 0, 1);
626 0 : glTranslated(0, -0.7 * s.vehicleText.scaledSize(s.scale), 0);
627 0 : glRotated(s.angle, 0, 0, 1);
628 : }
629 0 : }
630 : }
631 8949371 : if (s.showParkingInfo && myAdditionalVisualizations.size() != 0 && hasActiveAddVisualisation(
632 0 : myAdditionalVisualizations.begin()->first, VO_SHOW_ROUTE | VO_SHOW_FUTURE_ROUTE | VO_SHOW_ALL_ROUTES)) {
633 0 : glRotated(-s.angle, 0, 0, 1);
634 0 : glTranslated(0, 0.7 * s.vehicleName.scaledSize(s.scale), 0);
635 0 : glRotated(s.angle, 0, 0, 1);
636 0 : const double value = myVehicle.getNumberParkingReroutes();
637 0 : GLHelper::drawTextSettings(s.vehicleName, toString(value), Position(0, 0), s.scale, s.angle);
638 : }
639 :
640 8949371 : if (!drawCarriages) {
641 : mySeatPositions.clear();
642 : myContainerPositions.clear();
643 8945013 : int requiredSeats = getNumPassengers();
644 8945013 : int requiredContainerPositions = getNumContainers();
645 8945013 : const Position back = (p1 + Position(-scaledLength * upscaleLength, 0)).rotateAround2D(angle, p1);
646 8945013 : double extraOffset = scaledLength * 0.15;
647 8945013 : computeSeats(p1, back, SUMO_const_waitingPersonWidth, getVType().getPersonCapacity(), upscale, requiredSeats, mySeatPositions, extraOffset);
648 8945013 : computeSeats(p1, back, SUMO_const_waitingContainerWidth, getVType().getContainerCapacity(), upscale, requiredContainerPositions, myContainerPositions, extraOffset);
649 : }
650 :
651 8949371 : GLHelper::popMatrix();
652 8949371 : GLHelper::popName();
653 8949371 : drawAction_drawPersonsAndContainers(s);
654 8949371 : }
655 :
656 :
657 : void
658 8161721 : GUIBaseVehicle::drawGL(const GUIVisualizationSettings& s) const {
659 8161721 : drawOnPos(s, getVisualPosition(s.secondaryShape), getVisualAngle(s.secondaryShape));
660 8161721 : }
661 :
662 :
663 : void
664 3 : GUIBaseVehicle::drawGLAdditional(GUISUMOAbstractView* const parent, const GUIVisualizationSettings& s) const {
665 3 : if (!myVehicle.isOnRoad()) {
666 3 : drawGL(s);
667 : }
668 3 : GLHelper::pushName(getGlID());
669 3 : GLHelper::pushMatrix();
670 3 : glTranslated(0, 0, getType() - .1); // don't draw on top of other cars
671 3 : if (hasActiveAddVisualisation(parent, VO_SHOW_BEST_LANES)) {
672 0 : drawBestLanes();
673 : }
674 3 : bool noLoop = hasActiveAddVisualisation(parent, VO_SHOW_ROUTE_NOLOOP);
675 3 : if (hasActiveAddVisualisation(parent, VO_SHOW_ROUTE)) {
676 0 : drawRoute(s, 0, 0.25, false, noLoop);
677 : }
678 3 : if (hasActiveAddVisualisation(parent, VO_SHOW_FUTURE_ROUTE)) {
679 0 : drawRoute(s, 0, 0.25, true, noLoop);
680 : }
681 3 : if (hasActiveAddVisualisation(parent, VO_SHOW_ALL_ROUTES)) {
682 0 : if (myVehicle.getNumberReroutes() > 0) {
683 0 : const int noReroutePlus1 = myVehicle.getNumberReroutes() + 1;
684 0 : for (int i = noReroutePlus1 - 1; i >= 0; i--) {
685 0 : double darken = double(0.4) / double(noReroutePlus1) * double(i);
686 0 : drawRoute(s, i, darken);
687 : }
688 : } else {
689 0 : drawRoute(s, 0, 0.25, false, noLoop);
690 : }
691 : }
692 3 : if (hasActiveAddVisualisation(parent, VO_SHOW_LFLINKITEMS)) {
693 0 : drawAction_drawLinkItems(s);
694 : }
695 3 : GLHelper::popMatrix();
696 3 : GLHelper::popName();
697 3 : }
698 :
699 :
700 : void
701 0 : GUIBaseVehicle::drawLinkItem(const Position& pos, SUMOTime arrivalTime, SUMOTime leaveTime, double exagerate) {
702 0 : glTranslated(pos.x(), pos.y(), -.1);
703 0 : GLHelper::drawFilledCircle(1);
704 0 : std::string times = toString(STEPS2TIME(arrivalTime)) + "/" + toString(STEPS2TIME(leaveTime));
705 0 : GLHelper::drawText(times.c_str(), Position(), .1, 1.6 * exagerate, RGBColor::GREEN, 0);
706 0 : glTranslated(-pos.x(), -pos.y(), .1);
707 0 : }
708 :
709 :
710 : RGBColor
711 8949371 : GUIBaseVehicle::setColor(const GUIVisualizationSettings& s) const {
712 8949371 : RGBColor col;
713 : const GUIColorer& c = s.vehicleColorer;
714 8949371 : if (!setFunctionalColor(c.getActive(), &myVehicle, col)) {
715 5974706 : col = c.getScheme().getColor(getColorValue(s, c.getActive()));
716 : }
717 8949371 : GLHelper::setColor(col);
718 8949371 : return col;
719 : }
720 :
721 :
722 : bool
723 11214981 : GUIBaseVehicle::setFunctionalColor(int activeScheme, const MSBaseVehicle* veh, RGBColor& col) {
724 11214981 : switch (activeScheme) {
725 11034026 : case 0: {
726 : //test for emergency vehicle
727 11034026 : if (veh->getVehicleType().getGuiShape() == SUMOVehicleShape::EMERGENCY) {
728 67 : col = RGBColor::WHITE;
729 67 : return true;
730 : }
731 : //test for firebrigade
732 11033959 : if (veh->getVehicleType().getGuiShape() == SUMOVehicleShape::FIREBRIGADE) {
733 0 : col = RGBColor::RED;
734 0 : return true;
735 : }
736 : //test for police car
737 11033959 : if (veh->getVehicleType().getGuiShape() == SUMOVehicleShape::POLICE) {
738 0 : col = RGBColor::BLUE;
739 0 : return true;
740 : }
741 11033959 : if (veh->getParameter().wasSet(VEHPARS_COLOR_SET)) {
742 2509115 : col = veh->getParameter().color;
743 2509115 : return true;
744 : }
745 8524844 : if (veh->getVehicleType().wasSet(VTYPEPARS_COLOR_SET)) {
746 272592 : col = veh->getVehicleType().getColor();
747 272592 : return true;
748 : }
749 8252252 : if (&(veh->getRoute().getColor()) != &RGBColor::DEFAULT_COLOR) {
750 195423 : col = veh->getRoute().getColor();
751 195423 : return true;
752 : }
753 : return false;
754 : }
755 0 : case 2: {
756 0 : if (veh->getParameter().wasSet(VEHPARS_COLOR_SET)) {
757 0 : col = veh->getParameter().color;
758 0 : return true;
759 : }
760 : return false;
761 : }
762 0 : case 3: {
763 0 : if (veh->getVehicleType().wasSet(VTYPEPARS_COLOR_SET)) {
764 0 : col = veh->getVehicleType().getColor();
765 0 : return true;
766 : }
767 : return false;
768 : }
769 0 : case 4: {
770 0 : if (&(veh->getRoute().getColor()) != &RGBColor::DEFAULT_COLOR) {
771 0 : col = veh->getRoute().getColor();
772 0 : return true;
773 : }
774 : return false;
775 : }
776 0 : case 5: {
777 0 : Position p = veh->getRoute().getEdges()[0]->getLanes()[0]->getShape()[0];
778 0 : const Boundary& b = ((GUINet*) MSNet::getInstance())->getBoundary();
779 0 : Position center = b.getCenter();
780 0 : double hue = 180. + atan2(center.x() - p.x(), center.y() - p.y()) * 180. / M_PI;
781 0 : double sat = p.distanceTo(center) / center.distanceTo(Position(b.xmin(), b.ymin()));
782 0 : col = RGBColor::fromHSV(hue, sat, 1.);
783 : return true;
784 : }
785 0 : case 6: {
786 0 : Position p = veh->getRoute().getEdges().back()->getLanes()[0]->getShape()[-1];
787 0 : const Boundary& b = ((GUINet*) MSNet::getInstance())->getBoundary();
788 0 : Position center = b.getCenter();
789 0 : double hue = 180. + atan2(center.x() - p.x(), center.y() - p.y()) * 180. / M_PI;
790 0 : double sat = p.distanceTo(center) / center.distanceTo(Position(b.xmin(), b.ymin()));
791 0 : col = RGBColor::fromHSV(hue, sat, 1.);
792 : return true;
793 : }
794 0 : case 7: {
795 0 : Position pb = veh->getRoute().getEdges()[0]->getLanes()[0]->getShape()[0];
796 0 : Position pe = veh->getRoute().getEdges().back()->getLanes()[0]->getShape()[-1];
797 0 : const Boundary& b = ((GUINet*) MSNet::getInstance())->getBoundary();
798 0 : double hue = 180. + atan2(pb.x() - pe.x(), pb.y() - pe.y()) * 180. / M_PI;
799 0 : Position minp(b.xmin(), b.ymin());
800 0 : Position maxp(b.xmax(), b.ymax());
801 0 : double sat = pb.distanceTo(pe) / minp.distanceTo(maxp);
802 0 : col = RGBColor::fromHSV(hue, sat, 1.);
803 : return true;
804 : }
805 : case 35: { // color randomly (by pointer hash)
806 : std::hash<const MSBaseVehicle*> ptr_hash;
807 0 : const double hue = (double)(ptr_hash(veh) % 360); // [0-360]
808 0 : const double sat = (double)((ptr_hash(veh) / 360) % 67) / 100.0 + 0.33; // [0.33-1]
809 0 : col = RGBColor::fromHSV(hue, sat, 1.);
810 : return true;
811 : }
812 0 : case 36: { // color by angle
813 0 : double hue = GeomHelper::naviDegree(veh->getAngle());
814 0 : col = RGBColor::fromHSV(hue, 1., 1.);
815 0 : return true;
816 : }
817 : }
818 : return false;
819 : }
820 :
821 :
822 : double
823 8165850 : GUIBaseVehicle::getScaleValue(const GUIVisualizationSettings& s, int activeScheme) const {
824 8165850 : switch (activeScheme) {
825 : case 0: // uniform
826 : return 0;
827 0 : case 1: // selection
828 0 : return myVehicle.isSelected();
829 0 : case 2: // by speed
830 0 : if (myVehicle.isStopped()) {
831 0 : return myVehicle.isParking() ? -2 : -1;
832 : }
833 0 : return myVehicle.getSpeed();
834 0 : case 3:
835 0 : return myVehicle.getWaitingSeconds();
836 0 : case 4: {
837 0 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(&myVehicle);
838 0 : return (microVeh != nullptr ? microVeh->getAccumulatedWaitingSeconds() : 0);
839 : }
840 0 : case 5: {
841 0 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(&myVehicle);
842 0 : return (microVeh != nullptr ? microVeh->getLane()->getVehicleMaxSpeed(microVeh) : myVehicle.getEdge()->getVehicleMaxSpeed(&myVehicle));
843 : }
844 0 : case 6:
845 0 : return myVehicle.getNumberReroutes();
846 0 : case 7: {
847 0 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(&myVehicle);
848 : return (microVeh != nullptr
849 0 : ? (microVeh->getLaneChangeModel().isOpposite() ? -100 : microVeh->getBestLaneOffset())
850 0 : : 0);
851 : }
852 0 : case 8:
853 0 : return myVehicle.getAcceleration();
854 0 : case 9: {
855 0 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(&myVehicle);
856 0 : return (microVeh != nullptr ? microVeh->getTimeGapOnLane() : 0);
857 : }
858 0 : case 10:
859 0 : return STEPS2TIME(myVehicle.getDepartDelay());
860 0 : case 11:
861 0 : return myVehicle.getTimeLossSeconds();
862 0 : case 12:
863 0 : return myVehicle.getStopDelay();
864 0 : case 13:
865 0 : return myVehicle.getStopArrivalDelay();
866 : case 14: // by numerical param value
867 : std::string error;
868 0 : std::string val = myVehicle.getPrefixedParameter(s.vehicleScaleParam, error);
869 : try {
870 0 : if (val == "") {
871 : return 0;
872 : } else {
873 0 : return StringUtils::toDouble(val);
874 : }
875 0 : } catch (NumberFormatException&) {
876 : try {
877 0 : return StringUtils::toBool(val);
878 0 : } catch (BoolFormatException&) {
879 0 : WRITE_WARNINGF(TL("Vehicle parameter '%' key '%' is not a number for vehicle '%'."),
880 : myVehicle.getParameter().getParameter(s.vehicleScaleParam, "0"), s.vehicleScaleParam, myVehicle.getID());
881 : return -1;
882 0 : }
883 0 : }
884 : }
885 : return 0;
886 : }
887 :
888 :
889 : // ------------ Additional visualisations
890 : bool
891 18 : GUIBaseVehicle::hasActiveAddVisualisation(GUISUMOAbstractView* const parent, int which) const {
892 36 : return myAdditionalVisualizations.find(parent) != myAdditionalVisualizations.end() && (myAdditionalVisualizations.find(parent)->second & which) != 0;
893 : }
894 :
895 :
896 : void
897 0 : GUIBaseVehicle::addActiveAddVisualisation(GUISUMOAbstractView* const parent, int which) {
898 0 : if (myAdditionalVisualizations.find(parent) == myAdditionalVisualizations.end()) {
899 0 : myAdditionalVisualizations[parent] = 0;
900 : }
901 0 : myAdditionalVisualizations[parent] |= which;
902 0 : if (which != VO_TRACK) {
903 0 : parent->addAdditionalGLVisualisation(this);
904 : }
905 0 : }
906 :
907 :
908 : void
909 0 : GUIBaseVehicle::removeActiveAddVisualisation(GUISUMOAbstractView* const parent, int which) {
910 0 : myAdditionalVisualizations[parent] &= ~which;
911 0 : if (myAdditionalVisualizations[parent] == 0) {
912 : myAdditionalVisualizations.erase(parent);
913 : }
914 0 : parent->removeAdditionalGLVisualisation(this);
915 0 : }
916 :
917 :
918 : void
919 0 : GUIBaseVehicle::drawRoute(const GUIVisualizationSettings& s, int routeNo, double darken, bool future, bool noLoop) const {
920 0 : RGBColor vehColor = setColor(s);
921 0 : RGBColor darker = vehColor.changedBrightness((int)(darken * -255));
922 0 : if (darker == RGBColor::BLACK) {
923 0 : darker = vehColor.multiply(1 - darken);
924 : }
925 0 : GLHelper::setColor(darker);
926 0 : if (routeNo == 0) {
927 0 : drawRouteHelper(s, myVehicle.getRoutePtr(), future, noLoop, darker);
928 0 : return;
929 : }
930 0 : ConstMSRoutePtr route = myRoutes->getRoute(routeNo - 1); // only prior routes are stored
931 0 : if (route != nullptr) {
932 0 : drawRouteHelper(s, route, future, noLoop, darker);
933 : }
934 : }
935 :
936 :
937 : void
938 0 : GUIBaseVehicle::drawStopLabels(const GUIVisualizationSettings& s, bool noLoop, const RGBColor& col) const {
939 : // (vertical shift for repeated stops at the same position
940 : std::map<const MSLane*, int> repeat; // count repeated occurrences of the same position
941 0 : int stopIndex = 0;
942 0 : for (const MSStop& stop : myVehicle.getStops()) {
943 : double stopLanePos;
944 0 : if (stop.getSpeed() > 0) {
945 0 : stopLanePos = stop.reached ? stop.pars.endPos : stop.pars.startPos;
946 : } else {
947 0 : stopLanePos = stop.reached ? myVehicle.getPositionOnLane() : MAX2(0.0, stop.getEndPos(myVehicle));
948 : }
949 0 : if (stop.isOpposite && !stop.reached) {
950 0 : stopLanePos = stop.lane->getLength() - stopLanePos;
951 : }
952 0 : Position pos = stop.lane->geometryPositionAtOffset(stopLanePos);
953 0 : GLHelper::setColor(col);
954 0 : GLHelper::drawBoxLines(stop.lane->getShape().getOrthogonal(pos, 10, true, stop.lane->getWidth()), 0.1);
955 0 : std::string label = (stop.getSpeed() > 0
956 0 : ? (stop.reached ? "passing waypoint" : "waypoint ")
957 0 : : (stop.reached ? "stopped" : "stop "));
958 0 : if (!stop.reached) {
959 0 : label += toString(stopIndex);
960 : }
961 :
962 0 : if (stop.isOpposite) {
963 : label += " (opposite)";
964 : }
965 : #ifdef _DEBUG
966 : label += " (" + toString(stop.edge - myVehicle.getCurrentRouteEdge()) + "e)";
967 : #endif
968 0 : if (myVehicle.isStoppedTriggered()) {
969 : label += " triggered:";
970 0 : if (stop.triggered) {
971 : label += "person";
972 0 : if (stop.numExpectedPerson > 0) {
973 0 : label += "(" + toString(stop.numExpectedPerson) + ")";
974 : }
975 : }
976 0 : if (stop.containerTriggered) {
977 : label += "container";
978 0 : if (stop.numExpectedContainer > 0) {
979 0 : label += "(" + toString(stop.numExpectedContainer) + ")";
980 : }
981 : }
982 0 : if (stop.joinTriggered) {
983 : label += "join";
984 0 : if (stop.pars.join != "") {
985 0 : label += "(" + stop.pars.join + ")";
986 : }
987 : }
988 : }
989 0 : if (stop.pars.ended >= 0 && MSGlobals::gUseStopEnded) {
990 0 : label += " ended:" + time2string(stop.pars.ended);
991 0 : } else if (stop.pars.until >= 0) {
992 0 : label += " until:" + time2string(stop.pars.until);
993 : }
994 0 : if (stop.duration >= 0 || stop.pars.duration > 0) {
995 0 : if (STEPS2TIME(stop.duration) > 3600 * 24) {
996 : label += " duration:1day+";
997 : } else {
998 0 : label += " duration:" + time2string(stop.duration);
999 : }
1000 : }
1001 0 : if (stop.getSpeed() > 0) {
1002 0 : if (stop.skipOnDemand) {
1003 : label += " onDemand (skipped)";
1004 : } else {
1005 0 : label += " speed:" + toString(stop.getSpeed());
1006 : }
1007 : }
1008 0 : if (stop.pars.actType != "") {
1009 0 : label += " actType:" + stop.pars.actType;
1010 : }
1011 0 : const double nameSize = s.vehicleName.size / s.scale;
1012 0 : Position pos2 = pos - Position(0, nameSize * repeat[stop.lane]);
1013 0 : if (noLoop && repeat[stop.lane] > 0) {
1014 : break;
1015 : }
1016 0 : GLHelper::drawTextSettings(s.vehicleText, label, pos2, s.scale, s.angle, 1.0);
1017 0 : repeat[stop.lane]++;
1018 0 : stopIndex++;
1019 : }
1020 : // indicate arrivalPos if set
1021 0 : if (myVehicle.getParameter().wasSet(VEHPARS_ARRIVALPOS_SET) || myVehicle.getArrivalLane() >= 0) {
1022 0 : const int arrivalEdge = myVehicle.getParameter().arrivalEdge >= 0
1023 0 : ? myVehicle.getParameter().arrivalEdge
1024 0 : : (int)myVehicle.getRoute().getEdges().size() - 1;
1025 0 : const MSLane* arrivalLane = myVehicle.getRoute().getEdges()[arrivalEdge]->getLanes()[MAX2(0, myVehicle.getArrivalLane())];
1026 0 : Position pos = arrivalLane->geometryPositionAtOffset(myVehicle.getArrivalPos());
1027 0 : GLHelper::setColor(col);
1028 0 : GLHelper::drawBoxLines(arrivalLane->getShape().getOrthogonal(pos, 10, true, arrivalLane->getWidth() * 0.5, 90), 0.1);
1029 0 : GLHelper::drawBoxLines(arrivalLane->getShape().getOrthogonal(pos, 10, true, arrivalLane->getWidth() * 0.5, 270), 0.1);
1030 0 : GLHelper::drawTextSettings(s.vehicleText, "arrival", pos, s.scale, s.angle, 1.0);
1031 :
1032 : }
1033 0 : }
1034 :
1035 : void
1036 0 : GUIBaseVehicle::drawParkingInfo(const GUIVisualizationSettings& s) const {
1037 0 : if (s.showParkingInfo) {
1038 0 : const StoppingPlaceMemory* pm = myVehicle.getParkingMemory();
1039 0 : if (pm != nullptr) {
1040 0 : for (auto item : *pm) {
1041 0 : const GUIParkingArea* pa = dynamic_cast<const GUIParkingArea*>(item.first);
1042 0 : if (item.second.blockedAtTime >= 0) {
1043 0 : std::string seenAgo = time2string(SIMSTEP - item.second.blockedAtTime);
1044 : //if (item.second.blockedAtTime >= 0) {
1045 : // seenAgo += ", " + time2string(SIMSTEP - item.second.blockedAtTimeLocal);
1046 : //}
1047 0 : GLHelper::drawTextSettings(s.vehicleValue, seenAgo, pa->getSignPos(), s.scale, s.angle, 1.0);
1048 : }
1049 0 : if (item.second.score != "") {
1050 0 : const double dist = 0.4 * (s.vehicleText.scaledSize(s.scale) + s.vehicleValue.scaledSize(s.scale));
1051 : Position shift(0, -dist);
1052 0 : GLHelper::drawTextSettings(s.vehicleText, item.second.score, pa->getSignPos() + shift, s.scale, s.angle, 1.0);
1053 : }
1054 : }
1055 : }
1056 : }
1057 0 : }
1058 :
1059 : void
1060 0 : GUIBaseVehicle::drawChargingInfo(const GUIVisualizationSettings& s) const {
1061 0 : if (s.showChargingInfo) {
1062 0 : const StoppingPlaceMemory* pm = myVehicle.getChargingMemory();
1063 0 : if (pm != nullptr) {
1064 0 : for (auto item : *pm) {
1065 0 : const GUIChargingStation* cs = dynamic_cast<const GUIChargingStation*>(item.first);
1066 0 : if (item.second.blockedAtTime >= 0) {
1067 0 : std::string seenAgo = time2string(SIMSTEP - item.second.blockedAtTime);
1068 0 : GLHelper::drawTextSettings(s.vehicleValue, seenAgo, cs->getSignPos(), s.scale, s.angle, 1.0);
1069 : }
1070 0 : if (item.second.score != "") {
1071 0 : const double dist = 0.4 * (s.vehicleText.scaledSize(s.scale) + s.vehicleValue.scaledSize(s.scale));
1072 : Position shift(0, -dist);
1073 0 : GLHelper::drawTextSettings(s.vehicleText, item.second.score, cs->getSignPos() + shift, s.scale, s.angle, 1.0);
1074 : }
1075 : }
1076 : }
1077 : }
1078 0 : }
1079 :
1080 : const GUIBaseVehicle::Seat&
1081 214021 : GUIBaseVehicle::getSeatPosition(int personIndex) const {
1082 : /// if there are not enough seats in the vehicle people have to squeeze onto the last seat
1083 214021 : return mySeatPositions[MIN2(personIndex, (int)mySeatPositions.size() - 1)];
1084 : }
1085 :
1086 : const GUIBaseVehicle::Seat&
1087 5850 : GUIBaseVehicle::getContainerPosition(int containerIndex) const {
1088 : /// if there are not enough positions in the vehicle containers have to squeeze onto the last position
1089 5850 : return myContainerPositions[MIN2(containerIndex, (int)myContainerPositions.size() - 1)];
1090 : }
1091 :
1092 :
1093 : void
1094 8949371 : GUIBaseVehicle::drawAction_drawPersonsAndContainers(const GUIVisualizationSettings& s) const {
1095 8949371 : if (myVehicle.myPersonDevice != nullptr) {
1096 : const std::vector<MSTransportable*>& ps = myVehicle.myPersonDevice->getTransportables();
1097 : int personIndex = 0;
1098 222392 : for (std::vector<MSTransportable*>::const_iterator i = ps.begin(); i != ps.end(); ++i) {
1099 214021 : GUIPerson* person = dynamic_cast<GUIPerson*>(*i);
1100 : assert(person != 0);
1101 214021 : person->setPositionInVehicle(getSeatPosition(personIndex++));
1102 214021 : person->drawGL(s);
1103 : }
1104 : }
1105 8949371 : if (myVehicle.myContainerDevice != nullptr) {
1106 : const std::vector<MSTransportable*>& cs = myVehicle.myContainerDevice->getTransportables();
1107 : int containerIndex = 0;
1108 10996 : for (std::vector<MSTransportable*>::const_iterator i = cs.begin(); i != cs.end(); ++i) {
1109 5850 : GUIContainer* container = dynamic_cast<GUIContainer*>(*i);
1110 : assert(container != 0);
1111 5850 : container->setPositionInVehicle(getContainerPosition(containerIndex++));
1112 5850 : container->drawGL(s);
1113 : }
1114 : }
1115 : #ifdef DRAW_BOUNDING_BOX
1116 : if (!MSGlobals::gUseMesoSim) {
1117 : MSVehicle& microVeh = dynamic_cast<MSVehicle&>(myVehicle);
1118 : GLHelper::pushName(getGlID());
1119 : GLHelper::pushMatrix();
1120 : glTranslated(0, 0, getType());
1121 : PositionVector smallBB = microVeh.getBoundingPoly();
1122 : glColor3d(0.5, .8, 0);
1123 : GLHelper::drawBoxLines(smallBB, 0.3);
1124 : glTranslated(0, 0, 0.1);
1125 : PositionVector boundingBox = microVeh.getBoundingBox();
1126 : boundingBox.push_back(boundingBox.front());
1127 : glColor3d(1, 0, 0);
1128 : GLHelper::drawBoxLines(boundingBox, 0.15);
1129 : GLHelper::popMatrix();
1130 : GLHelper::popName();
1131 : }
1132 : #endif
1133 8949371 : }
1134 :
1135 : bool
1136 8936838 : GUIBaseVehicle::drawReversed(const GUIVisualizationSettings& s) const {
1137 8936838 : return myVehicle.isReversed() && s.drawReversed;
1138 : }
1139 :
1140 : bool
1141 220182 : GUIBaseVehicle::drawAction_drawVehicleAsPolyWithCarriagges(const GUIVisualizationSettings& s, double scaledLength, bool asImage) const {
1142 224540 : if (getVType().getParameter().carriageLength > 0 &&
1143 4358 : (!myVehicle.isParking() || myVehicle.getNextStop().parkingarea == nullptr || myVehicle.getNextStop().parkingarea->parkOnRoad())) {
1144 4358 : drawAction_drawCarriageClass(s, asImage);
1145 4358 : return true;
1146 : } else {
1147 232174 : if (asImage && GUIBaseVehicleHelper::drawAction_drawVehicleAsImage(
1148 215824 : s, getVType().getImgFile(), this, getVType().getWidth(), scaledLength)) {
1149 : return false;
1150 : }
1151 415298 : GUIBaseVehicleHelper::drawAction_drawVehicleAsPoly(s, getVType().getGuiShape(), getVType().getWidth(), scaledLength, -1, myVehicle.isStopped(), drawReversed(s));
1152 207649 : return false;
1153 : }
1154 : }
1155 :
1156 :
1157 : int
1158 8949371 : GUIBaseVehicle::getNumPassengers() const {
1159 8949371 : if (myVehicle.getPersonDevice() != nullptr) {
1160 8371 : return (int)myVehicle.getPersonDevice()->size();
1161 : }
1162 : return 0;
1163 : }
1164 :
1165 :
1166 : int
1167 8949371 : GUIBaseVehicle::getNumContainers() const {
1168 8949371 : if (myVehicle.getContainerDevice() != nullptr) {
1169 5146 : return (int)myVehicle.getContainerDevice()->size();
1170 : }
1171 : return 0;
1172 : }
1173 :
1174 : std::string
1175 0 : GUIBaseVehicle::getDeviceDescription() {
1176 : std::vector<std::string> devs;
1177 0 : for (MSDevice* d : myVehicle.getDevices()) {
1178 0 : devs.push_back(d->deviceName());
1179 : }
1180 0 : return joinToString(devs, " ");
1181 0 : }
1182 :
1183 :
1184 : void
1185 17912323 : GUIBaseVehicle::computeSeats(const Position& front, const Position& back, double seatOffset, int maxSeats, double exaggeration, int& requiredSeats, Seats& into, double extraOffset) const {
1186 17912323 : if (requiredSeats <= 0) {
1187 : return;
1188 : }
1189 : maxSeats = MAX2(maxSeats, 1); // compute at least one seat
1190 13353 : seatOffset *= exaggeration;
1191 13353 : const double vehWidth = getVType().getSeatingWidth() * exaggeration;
1192 : const double length = front.distanceTo2D(back);
1193 13353 : const int rowSize = MAX2(1, (int)floor(vehWidth / seatOffset));
1194 13353 : const double frontSeatPos = getVType().getFrontSeatPos() + extraOffset;
1195 13353 : const double rowOffset = MAX2(1.0, (length - frontSeatPos - 1)) / ceil((double)maxSeats / rowSize);
1196 13353 : const double sideOffset = (rowSize - 1) / 2.0 * seatOffset;
1197 13353 : double rowPos = frontSeatPos - rowOffset;
1198 : double angle = back.angleTo2D(front);
1199 13353 : const int fillDirection = MSGlobals::gLefthand ? -1 : 1;
1200 : //if (myVehicle.getID() == "v0") std::cout << SIMTIME << " seatOffset=" << seatOffset << " max=" << maxSeats << " ex=" << exaggeration << " req=" << requiredSeats << " rowSize=" << rowSize << " sideOffset=" << sideOffset << " front=" << front << " back=" << back << " a=" << angle << " da=" << RAD2DEG(angle) << "\n";
1201 231788 : for (int i = 0; requiredSeats > 0 && i < maxSeats; i++) {
1202 218435 : int seat = (i % rowSize);
1203 218435 : if (seat == 0) {
1204 81067 : rowPos += rowOffset;
1205 : }
1206 218435 : into.push_back(Seat(PositionVector::positionAtOffset2D(front, back, rowPos, (sideOffset - seat * seatOffset) * fillDirection), angle));
1207 218435 : requiredSeats--;
1208 : }
1209 : }
1210 :
1211 :
1212 : /****************************************************************************/
|