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 GUIContainer.cpp
15 : /// @author Melanie Weber
16 : /// @author Andreas Kendziorra
17 : /// @date Wed, 01.08.2014
18 : ///
19 : // A MSContainer extended by some values for usage within the gui
20 : /****************************************************************************/
21 : #include <config.h>
22 :
23 : #include <cmath>
24 : #include <vector>
25 : #include <string>
26 : #include <microsim/logging/CastingFunctionBinding.h>
27 : #include <microsim/logging/FunctionBinding.h>
28 : #include <microsim/MSLane.h>
29 : #include <microsim/MSVehicleControl.h>
30 : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
31 : #include <microsim/devices/MSDevice_Vehroutes.h>
32 : #include <utils/common/MsgHandler.h>
33 : #include <utils/common/StringUtils.h>
34 : #include <utils/vehicle/SUMOVehicleParameter.h>
35 : #include <utils/geom/GeomHelper.h>
36 : #include <utils/gui/images/GUITexturesHelper.h>
37 : #include <utils/gui/windows/GUISUMOAbstractView.h>
38 : #include <utils/gui/windows/GUIAppEnum.h>
39 : #include <utils/gui/div/GUIParameterTableWindow.h>
40 : #include <utils/gui/div/GUIGlobalSelection.h>
41 : #include <utils/gui/div/GLHelper.h>
42 : #include <utils/gui/div/GLObjectValuePassConnector.h>
43 : #include <utils/geom/PositionVector.h>
44 : #include <gui/GUIApplicationWindow.h>
45 : #include <gui/GUIGlobals.h>
46 : #include <utils/gui/globjects/GLIncludes.h>
47 : #include <utils/gui/div/GUIDesigns.h>
48 :
49 : #include "GUIContainer.h"
50 : #include "GUINet.h"
51 : #include "GUIEdge.h"
52 :
53 : //#define GUIContainer_DEBUG_DRAW_WALKING_AREA_SHAPE
54 :
55 : // ===========================================================================
56 : // FOX callback mapping
57 : // ===========================================================================
58 : FXDEFMAP(GUIContainer::GUIContainerPopupMenu) GUIContainerPopupMenuMap[] = {
59 : FXMAPFUNC(SEL_COMMAND, MID_START_TRACK, GUIContainer::GUIContainerPopupMenu::onCmdStartTrack),
60 : FXMAPFUNC(SEL_COMMAND, MID_STOP_TRACK, GUIContainer::GUIContainerPopupMenu::onCmdStopTrack),
61 : FXMAPFUNC(SEL_COMMAND, MID_SHOWPLAN, GUIContainer::GUIContainerPopupMenu::onCmdShowPlan),
62 : };
63 :
64 : // Object implementation
65 0 : FXIMPLEMENT(GUIContainer::GUIContainerPopupMenu, GUIGLObjectPopupMenu, GUIContainerPopupMenuMap, ARRAYNUMBER(GUIContainerPopupMenuMap))
66 :
67 : #define WATER_WAY_OFFSET 6.0
68 :
69 : // ===========================================================================
70 : // method definitions
71 : // ===========================================================================
72 : /* -------------------------------------------------------------------------
73 : * GUIContainer::GUIContainerPopupMenu - methods
74 : * ----------------------------------------------------------------------- */
75 0 : GUIContainer::GUIContainerPopupMenu::GUIContainerPopupMenu(
76 0 : GUIMainWindow& app, GUISUMOAbstractView& parent, GUIGlObject& o)
77 0 : : GUIGLObjectPopupMenu(app, parent, o) {
78 0 : }
79 :
80 :
81 0 : GUIContainer::GUIContainerPopupMenu::~GUIContainerPopupMenu() {}
82 :
83 :
84 : long
85 0 : GUIContainer::GUIContainerPopupMenu::onCmdShowPlan(FXObject*, FXSelector, void*) {
86 0 : GUIContainer* p = dynamic_cast<GUIContainer*>(myObject);
87 0 : if (p == nullptr) {
88 : return 1;
89 : }
90 0 : GUIParameterTableWindow* ret = new GUIParameterTableWindow(*myApplication, *p);
91 : // add items
92 0 : for (int stage = 1; stage < p->getNumStages(); stage++) {
93 0 : ret->mkItem(toString(stage).c_str(), false, p->getStageSummary(stage));
94 : }
95 : // close building (use an object that is not Parameterised as argument)
96 0 : Parameterised dummy;
97 0 : ret->closeBuilding(&dummy);
98 : return 1;
99 0 : }
100 :
101 :
102 : long
103 0 : GUIContainer::GUIContainerPopupMenu::onCmdStartTrack(FXObject*, FXSelector, void*) {
104 : assert(myObject->getType() == GLO_PERSON);
105 0 : if (myParent->getTrackedID() != static_cast<GUIContainer*>(myObject)->getGlID()) {
106 0 : myParent->startTrack(static_cast<GUIContainer*>(myObject)->getGlID());
107 : }
108 0 : return 1;
109 : }
110 :
111 : long
112 0 : GUIContainer::GUIContainerPopupMenu::onCmdStopTrack(FXObject*, FXSelector, void*) {
113 : assert(myObject->getType() == GLO_PERSON);
114 0 : myParent->stopTrack();
115 0 : return 1;
116 : }
117 :
118 :
119 :
120 :
121 : /* -------------------------------------------------------------------------
122 : * GUIContainer - methods
123 : * ----------------------------------------------------------------------- */
124 422 : GUIContainer::GUIContainer(const SUMOVehicleParameter* pars, MSVehicleType* vtype, MSTransportable::MSTransportablePlan* plan) :
125 : MSTransportable(pars, vtype, plan, false),
126 422 : GUIGlObject(GLO_CONTAINER, pars->id, GUIIconSubSys::getIcon(GUIIcon::CONTAINER)) {
127 422 : }
128 :
129 :
130 844 : GUIContainer::~GUIContainer() {
131 1266 : }
132 :
133 :
134 : GUIGLObjectPopupMenu*
135 0 : GUIContainer::getPopUpMenu(GUIMainWindow& app,
136 : GUISUMOAbstractView& parent) {
137 0 : GUIGLObjectPopupMenu* ret = new GUIContainerPopupMenu(app, parent, *this);
138 0 : buildPopupHeader(ret, app);
139 0 : buildCenterPopupEntry(ret);
140 0 : buildNameCopyPopupEntry(ret);
141 0 : buildSelectionPopupEntry(ret);
142 0 : new FXMenuSeparator(ret);
143 0 : if (parent.getTrackedID() != getGlID()) {
144 0 : GUIDesigns::buildFXMenuCommand(ret, "Start Tracking", nullptr, ret, MID_START_TRACK);
145 : } else {
146 0 : GUIDesigns::buildFXMenuCommand(ret, "Stop Tracking", nullptr, ret, MID_STOP_TRACK);
147 : }
148 : //
149 :
150 0 : buildShowParamsPopupEntry(ret);
151 0 : buildShowTypeParamsPopupEntry(ret);
152 0 : GUIDesigns::buildFXMenuCommand(ret, "Show Plan", GUIIconSubSys::getIcon(GUIIcon::APP_TABLE), ret, MID_SHOWPLAN);
153 0 : new FXMenuSeparator(ret);
154 0 : buildPositionCopyEntry(ret, app);
155 0 : return ret;
156 : }
157 :
158 :
159 : GUIParameterTableWindow*
160 0 : GUIContainer::getParameterWindow(GUIMainWindow& app,
161 : GUISUMOAbstractView&) {
162 0 : GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
163 : // add items
164 0 : ret->mkItem(TL("stage"), false, getCurrentStageDescription());
165 : // there is always the "start" stage which we do not count here because it is not strictly part of the plan
166 0 : ret->mkItem(TL("stage index"), false, toString(getCurrentStageIndex()) + " of " + toString(getNumStages() - 1));
167 0 : ret->mkItem(TL("start edge [id]"), false, getFromEdge()->getID());
168 0 : ret->mkItem(TL("dest edge [id]"), false, getDestination()->getID());
169 0 : ret->mkItem(TL("arrivalPos [m]"), false, toString(getCurrentStage()->getArrivalPos()));
170 0 : ret->mkItem(TL("edge [id]"), false, getEdge()->getID());
171 0 : ret->mkItem(TL("position [m]"), true, new FunctionBinding<GUIContainer, double>(this, &GUIContainer::getEdgePos));
172 0 : ret->mkItem(TL("speed [m/s]"), true, new FunctionBinding<GUIContainer, double>(this, &GUIContainer::getSpeed));
173 0 : ret->mkItem(TL("speed factor"), false, getChosenSpeedFactor());
174 0 : ret->mkItem(TL("angle [degree]"), true, new FunctionBinding<GUIContainer, double>(this, &GUIContainer::getAngle));
175 0 : ret->mkItem(TL("waiting time [s]"), true, new FunctionBinding<GUIContainer, double>(this, &GUIContainer::getWaitingSeconds));
176 0 : ret->mkItem(TL("desired depart [s]"), false, time2string(getParameter().depart));
177 : // close building
178 0 : ret->closeBuilding(&getParameter());
179 0 : return ret;
180 : }
181 :
182 :
183 : GUIParameterTableWindow*
184 0 : GUIContainer::getTypeParameterWindow(GUIMainWindow& app, GUISUMOAbstractView&) {
185 0 : GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this, "vType:" + myVType->getID());
186 0 : ret->mkItem(TL("length"), false, myVType->getLength());
187 0 : ret->mkItem(TL("width"), false, myVType->getWidth());
188 0 : ret->mkItem(TL("height"), false, myVType->getHeight());
189 0 : ret->mkItem(TL("minGap"), false, myVType->getMinGap());
190 0 : ret->mkItem(TL("mass [kg]"), false, myVType->getMass());
191 0 : ret->mkItem(TL("maximum speed [m/s]"), false, myVType->getMaxSpeed());
192 0 : ret->closeBuilding(&(myVType->getParameter()));
193 0 : return ret;
194 : }
195 :
196 :
197 : double
198 22127 : GUIContainer::getExaggeration(const GUIVisualizationSettings& s) const {
199 22127 : return s.containerSize.getExaggeration(s, this);
200 : }
201 :
202 :
203 : Boundary
204 0 : GUIContainer::getCenteringBoundary() const {
205 0 : Boundary b;
206 : // ensure that the vehicle is drawn, otherwise myPositionInVehicle will not be updated
207 0 : b.add(getPosition());
208 0 : b.grow(20);
209 0 : return b;
210 0 : }
211 :
212 :
213 : void
214 22127 : GUIContainer::drawGL(const GUIVisualizationSettings& s) const {
215 22127 : GLHelper::pushName(getGlID());
216 22127 : GLHelper::pushMatrix();
217 22127 : Position p1 = getPosition();
218 22127 : double angle = getAngle();
219 44079 : if (getCurrentStageType() == MSStageType::DRIVING && !isWaiting4Vehicle()) {
220 5850 : p1 = myPositionInVehicle.pos;
221 5850 : angle = myPositionInVehicle.angle;
222 : }
223 22127 : glTranslated(p1.x(), p1.y(), getType());
224 22127 : glRotated(RAD2DEG(angle), 0, 0, 1);
225 : // set container color
226 22127 : setColor(s);
227 : // scale
228 22127 : const double upscale = getExaggeration(s);
229 22127 : glScaled(upscale, upscale, 1);
230 22127 : switch (s.containerQuality) {
231 22127 : case 0:
232 : case 1:
233 : case 2:
234 22127 : drawAction_drawAsPoly(s);
235 : break;
236 0 : case 3:
237 : default:
238 0 : drawAction_drawAsImage(s);
239 : break;
240 : }
241 22127 : GLHelper::popMatrix();
242 :
243 22127 : drawName(p1, s.scale, s.containerName, s.angle);
244 22127 : GLHelper::popName();
245 22127 : }
246 :
247 :
248 : void
249 0 : GUIContainer::drawGLAdditional(GUISUMOAbstractView* const /* parent */, const GUIVisualizationSettings& /* s */) const {
250 0 : GLHelper::pushName(getGlID());
251 0 : GLHelper::pushMatrix();
252 : /*
253 : glTranslated(0, 0, getType() - .1); // don't draw on top of other cars
254 : if (hasActiveAddVisualisation(parent, VO_SHOW_BEST_LANES)) {
255 : drawBestLanes();
256 : }
257 : if (hasActiveAddVisualisation(parent, VO_SHOW_ROUTE)) {
258 : drawRoute(s, 0, 0.25);
259 : }
260 : if (hasActiveAddVisualisation(parent, VO_SHOW_ALL_ROUTES)) {
261 : if (getNumberReroutes() > 0) {
262 : const int noReroutePlus1 = getNumberReroutes() + 1;
263 : for (int i = noReroutePlus1 - 1; i >= 0; i--) {
264 : double darken = double(0.4) / double(noReroutePlus1) * double(i);
265 : drawRoute(s, i, darken);
266 : }
267 : } else {
268 : drawRoute(s, 0, 0.25);
269 : }
270 : }
271 : if (hasActiveAddVisualisation(parent, VO_SHOW_LFLINKITEMS)) {
272 : for (DriveItemVector::const_iterator i = myLFLinkLanes.begin(); i != myLFLinkLanes.end(); ++i) {
273 : if((*i).myLink==0) {
274 : continue;
275 : }
276 : MSLink* link = (*i).myLink;
277 : MSLane *via = link->getViaLane();
278 : if (via == 0) {
279 : via = link->getLane();
280 : }
281 : if (via != 0) {
282 : Position p = via->getShape()[0];
283 : if((*i).mySetRequest) {
284 : glColor3f(0, 1, 0);
285 : } else {
286 : glColor3f(1, 0, 0);
287 : }
288 : glTranslated(p.x(), p.y(), -.1);
289 : GLHelper::drawFilledCircle(1);
290 : glTranslated(-p.x(), -p.y(), .1);
291 : }
292 : }
293 : }
294 : */
295 0 : GLHelper::popMatrix();
296 0 : GLHelper::popName();
297 0 : }
298 :
299 :
300 :
301 :
302 : void
303 22127 : GUIContainer::setColor(const GUIVisualizationSettings& s) const {
304 : const GUIColorer& c = s.containerColorer;
305 22127 : if (!setFunctionalColor(c.getActive())) {
306 19413 : GLHelper::setColor(c.getScheme().getColor(getColorValue(s, c.getActive())));
307 : }
308 22127 : }
309 :
310 :
311 : bool
312 22127 : GUIContainer::setFunctionalColor(int activeScheme) const {
313 22127 : switch (activeScheme) {
314 22127 : case 0: {
315 22127 : if (getParameter().wasSet(VEHPARS_COLOR_SET)) {
316 2712 : GLHelper::setColor(getParameter().color);
317 2712 : return true;
318 : }
319 19415 : if (getVehicleType().wasSet(VTYPEPARS_COLOR_SET)) {
320 2 : GLHelper::setColor(getVehicleType().getColor());
321 2 : return true;
322 : }
323 : return false;
324 : }
325 0 : case 2: {
326 0 : if (getParameter().wasSet(VEHPARS_COLOR_SET)) {
327 0 : GLHelper::setColor(getParameter().color);
328 0 : return true;
329 : }
330 : return false;
331 : }
332 0 : case 3: {
333 0 : if (getVehicleType().wasSet(VTYPEPARS_COLOR_SET)) {
334 0 : GLHelper::setColor(getVehicleType().getColor());
335 0 : return true;
336 : }
337 : return false;
338 : }
339 0 : case 8: { // color by angle
340 0 : double hue = GeomHelper::naviDegree(getAngle());
341 0 : GLHelper::setColor(RGBColor::fromHSV(hue, 1., 1.));
342 0 : return true;
343 : }
344 0 : case 9: { // color randomly (by pointer)
345 0 : const double hue = (double)((long long int)this % 360); // [0-360]
346 0 : const double sat = (double)(((long long int)this / 360) % 67) / 100. + 0.33; // [0.33-1]
347 0 : GLHelper::setColor(RGBColor::fromHSV(hue, sat, 1.));
348 0 : return true;
349 : }
350 : default:
351 : return false;
352 : }
353 : }
354 :
355 :
356 : double
357 19413 : GUIContainer::getColorValue(const GUIVisualizationSettings& /* s */, int activeScheme) const {
358 19413 : switch (activeScheme) {
359 0 : case 4:
360 0 : return getSpeed();
361 0 : case 5:
362 0 : if (isWaiting4Vehicle()) {
363 : return 5;
364 : } else {
365 0 : return (double)getCurrentStageType();
366 : }
367 0 : case 6:
368 0 : return getWaitingSeconds();
369 0 : case 7:
370 0 : return gSelected.isSelected(GLO_CONTAINER, getGlID());
371 : }
372 : return 0;
373 : }
374 :
375 :
376 : double
377 4885 : GUIContainer::getEdgePos() const {
378 4885 : FXMutexLock locker(myLock);
379 9770 : return MSTransportable::getEdgePos();
380 : }
381 :
382 : int
383 0 : GUIContainer::getDirection() const {
384 0 : FXMutexLock locker(myLock);
385 0 : return MSTransportable::getDirection();
386 : }
387 :
388 :
389 : Position
390 24291 : GUIContainer::getPosition() const {
391 24291 : FXMutexLock locker(myLock);
392 24291 : if (getCurrentStageType() == MSStageType::WAITING && getEdge()->getPermissions() == SVC_SHIP) {
393 0 : MSLane* lane = getEdge()->getLanes().front(); //the most right lane of the water way
394 : PositionVector laneShape = lane->getShape();
395 0 : return laneShape.positionAtOffset2D(getEdgePos(), WATER_WAY_OFFSET);
396 0 : }
397 24291 : return MSTransportable::getPosition();
398 : }
399 :
400 :
401 : double
402 24605 : GUIContainer::getAngle() const {
403 24605 : FXMutexLock locker(myLock);
404 49210 : return MSTransportable::getAngle();
405 : }
406 :
407 :
408 : double
409 0 : GUIContainer::getWaitingSeconds() const {
410 0 : FXMutexLock locker(myLock);
411 0 : return MSTransportable::getWaitingSeconds();
412 : }
413 :
414 :
415 : double
416 2164 : GUIContainer::getSpeed() const {
417 2164 : FXMutexLock locker(myLock);
418 4328 : return MSTransportable::getSpeed();
419 : }
420 :
421 :
422 : void
423 22127 : GUIContainer::drawAction_drawAsPoly(const GUIVisualizationSettings& /* s */) const {
424 : // draw pedestrian shape
425 22127 : glScaled(getVehicleType().getLength(), getVehicleType().getWidth(), 1);
426 22127 : glBegin(GL_QUADS);
427 22127 : glVertex2d(0, 0.5);
428 22127 : glVertex2d(0, -0.5);
429 22127 : glVertex2d(-1, -0.5);
430 22127 : glVertex2d(-1, 0.5);
431 22127 : glEnd();
432 22127 : GLHelper::setColor(GLHelper::getColor().changedBrightness(-30));
433 22127 : glTranslated(0, 0, .045);
434 22127 : glBegin(GL_QUADS);
435 22127 : glVertex2d(-0.1, 0.4);
436 22127 : glVertex2d(-0.1, -0.4);
437 22127 : glVertex2d(-0.9, -0.4);
438 22127 : glVertex2d(-0.9, 0.4);
439 22127 : glEnd();
440 22127 : }
441 :
442 :
443 : void
444 0 : GUIContainer::drawAction_drawAsImage(const GUIVisualizationSettings& s) const {
445 0 : const std::string& file = getVehicleType().getImgFile();
446 0 : if (file != "") {
447 : // @todo invent an option for controlling whether images should be rotated or not
448 : //if (getVehicleType().getGuiShape() == SVS_CONTAINER) {
449 : // glRotated(RAD2DEG(getAngle() + M_PI / 2.), 0, 0, 1);
450 : //}
451 0 : int textureID = GUITexturesHelper::getTextureID(file);
452 0 : if (textureID > 0) {
453 0 : const double exaggeration = s.personSize.getExaggeration(s, this);
454 0 : const double halfLength = getVehicleType().getLength() / 2.0 * exaggeration;
455 0 : const double halfWidth = getVehicleType().getWidth() / 2.0 * exaggeration;
456 0 : GUITexturesHelper::drawTexturedBox(textureID, -halfWidth, -halfLength, halfWidth, halfLength);
457 : }
458 : } else {
459 : // fallback if no image is defined
460 0 : drawAction_drawAsPoly(s);
461 : }
462 0 : }
463 :
464 : bool
465 0 : GUIContainer::isSelected() const {
466 0 : return gSelected.isSelected(GLO_CONTAINER, getGlID());
467 : }
468 :
469 : /****************************************************************************/
|