Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file GUIGlObject.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @author Laura Bieker
19 : /// @date Sept 2002
20 : ///
21 : // Base class for all objects that may be displayed within the openGL-gui
22 : /****************************************************************************/
23 : #include <config.h>
24 :
25 : #include <string>
26 : #include <stack>
27 : #include <utils/common/MsgHandler.h>
28 : #include <utils/common/ToString.h>
29 : #include <utils/geom/GeoConvHelper.h>
30 : #include <utils/gui/windows/GUISUMOAbstractView.h>
31 : #include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
32 : #include <utils/gui/div/GUIParameterTableWindow.h>
33 : #include <utils/foxtools/MFXMenuHeader.h>
34 : #include <utils/gui/images/GUIIconSubSys.h>
35 : #include <utils/gui/windows/GUIAppEnum.h>
36 : #include <utils/gui/windows/GUIMainWindow.h>
37 : #include <utils/gui/div/GUIGlobalSelection.h>
38 : #include <utils/gui/div/GLHelper.h>
39 : #include <utils/gui/div/GLObjectValuePassConnector.h>
40 : #include <utils/gui/div/GUIDesigns.h>
41 : #include <utils/geom/GeomHelper.h>
42 : #include <utils/gui/div/GUIGlobalViewObjectsHandler.h>
43 : #include <utils/options/OptionsCont.h>
44 :
45 : #include "GUIGlObject.h"
46 : #include "GUIGlObjectStorage.h"
47 :
48 : // ===========================================================================
49 : // static members
50 : // ===========================================================================
51 :
52 : StringBijection<GUIGlObjectType>::Entry GUIGlObject::GUIGlObjectTypeNamesInitializer[] = {
53 : {"network", GLO_NETWORK},
54 : //
55 : {"networkElement", GLO_NETWORKELEMENT},
56 : {"edge", GLO_EDGE},
57 : {"lane", GLO_LANE},
58 : {"junction", GLO_JUNCTION},
59 : {"connection", GLO_CONNECTION},
60 : {"crossing", GLO_CROSSING},
61 : {"walkingArea", GLO_WALKINGAREA},
62 : {"tlLogic", GLO_TLLOGIC},
63 : {"edgeType", GLO_EDGETYPE},
64 : {"laneType", GLO_LANETYPE},
65 : //
66 : {"parentChildLine", GLO_PARENTCHILDLINE},
67 : //
68 : {"additional", GLO_ADDITIONALELEMENT},
69 : {"stoppingPlace", GLO_STOPPING_PLACE},
70 : {"busStop", GLO_BUS_STOP},
71 : {"trainStop", GLO_TRAIN_STOP},
72 : {"access", GLO_ACCESS},
73 : {"taz", GLO_TAZ},
74 : {"containerStop", GLO_CONTAINER_STOP},
75 : {"chargingStation", GLO_CHARGING_STATION},
76 : {"parkingArea", GLO_PARKING_AREA},
77 : {"stoppingPlaceLast", GLO_STOPPING_PLACE_LAST},
78 : {"parkingSpace", GLO_PARKING_SPACE},
79 : {"e1Detector", GLO_E1DETECTOR},
80 : {"e1DetectorME", GLO_E1DETECTOR_ME},
81 : {"e1DetectorInstant", GLO_E1DETECTOR_INSTANT},
82 : {"e2Detector", GLO_E2DETECTOR},
83 : {"e3Detector", GLO_E3DETECTOR},
84 : {"entryExitDetector", GLO_DET_ENTRYEXIT},
85 : {"entryDetector", GLO_DET_ENTRY},
86 : {"exitDetector", GLO_DET_EXIT},
87 : {"rerouter", GLO_REROUTER},
88 : {"rerouterInterval", GLO_REROUTER_INTERVAL},
89 : {"closingreroute", GLO_REROUTER_CLOSINGREROUTE},
90 : {"closingLaneReroute", GLO_REROUTER_CLOSINGLANEREROUTE},
91 : {"parkingAreaReroute", GLO_REROUTER_PARKINGAREAREROUTE},
92 : {"destProbReroute", GLO_REROUTER_DESTPROBREROUTE},
93 : {"routeProbReroute", GLO_REROUTER_ROUTEPROBREROUTE},
94 : {"rerouterEdge", GLO_REROUTER_EDGE},
95 : {"variableSpeedSign", GLO_VSS},
96 : {"variableSpeedSignStep", GLO_VSS_STEP},
97 : {"calibrator", GLO_CALIBRATOR},
98 : {"calibratorFlow", GLO_CALIBRATOR_FLOW},
99 : {"routeProbe", GLO_ROUTEPROBE},
100 : {"vaporizer", GLO_VAPORIZER},
101 : {"wire", GLO_WIRE},
102 : {"overheadWireSegment", GLO_OVERHEAD_WIRE_SEGMENT},
103 : {"tractionsubstation", GLO_TRACTIONSUBSTATION},
104 : {"additionalLast", GLO_ADDITIONALELEMENT_LAST},
105 : //
106 : {"laneArrows", GLO_LANEARROWS},
107 : //
108 : {"shape", GLO_SHAPE},
109 : {"polygon", GLO_POLYGON},
110 : {"poi", GLO_POI},
111 : {"jupedsim.walkable_area", GLO_JPS_WALKABLEAREA},
112 : {"jupedsim.obstacle", GLO_JPS_OBSTACLE},
113 : {"shapeLast", GLO_SHAPE_LAST},
114 : //
115 : {"routeElement", GLO_ROUTEELEMENT},
116 : {"vType", GLO_VTYPE},
117 : {"vTypeRef", GLO_VTYPE_REF},
118 : {"vTypeDistribution", GLO_VTYPE_DISTRIBUTION},
119 : //
120 : {"route", GLO_ROUTE},
121 : {"routeEmbedded", GLO_ROUTE_EMBEDDED},
122 : {"routeRef", GLO_ROUTE_REF},
123 : {"routeDistribution", GLO_ROUTE_DISTRIBUTION},
124 : //
125 : {"ride", GLO_RIDE},
126 : {"walk", GLO_WALK},
127 : {"personTrip", GLO_PERSONTRIP},
128 : {"transport", GLO_TRANSPORT},
129 : {"tranship", GLO_TRANSHIP},
130 : //
131 : {"stop", GLO_STOP},
132 : {"stopPlan", GLO_STOP_PLAN},
133 : //
134 : {"vehicle", GLO_VEHICLE},
135 : {"trip", GLO_TRIP},
136 : {"flow", GLO_FLOW},
137 : {"routeFlow", GLO_ROUTEFLOW},
138 : //
139 : {"container", GLO_CONTAINER},
140 : {"containerFlow", GLO_CONTAINERFLOW},
141 : //
142 : {"person", GLO_PERSON},
143 : {"personFlow", GLO_PERSONFLOW},
144 : //
145 : {"edgeData", GLO_EDGEDATA},
146 : {"edgeRelData", GLO_EDGERELDATA},
147 : {"TAZRelData", GLO_TAZRELDATA},
148 : {"meanData", GLO_MEANDATA},
149 : {"dataSet", GLO_DATASET},
150 : {"dataInterval", GLO_DATAINTERVAL},
151 : //
152 : {"lockIcon", GLO_LOCKICON},
153 : {"textName", GLO_TEXTNAME},
154 : {"frontElement", GLO_FRONTELEMENT},
155 : {"geometryPoint", GLO_GEOMETRYPOINT},
156 : {"dottedContour", GLO_DOTTEDCONTOUR},
157 : {"vehicleLabels", GLO_VEHICLELABELS},
158 : {"temporalShape", GLO_TEMPORALSHAPE},
159 : {"rectangleSelection", GLO_RECTANGLESELECTION},
160 : {"testElement", GLO_TESTELEMENT},
161 : //
162 : {"undefined", GLO_MAX}
163 : };
164 :
165 :
166 : StringBijection<GUIGlObjectType> GUIGlObject::TypeNames(GUIGlObjectTypeNamesInitializer, GLO_MAX);
167 : const GUIGlID GUIGlObject::INVALID_ID = 0;
168 : const double GUIGlObject::INVALID_PRIORITY(-std::numeric_limits<double>::max());
169 :
170 :
171 : // ===========================================================================
172 : // method definitions
173 : // ===========================================================================
174 : #ifdef _MSC_VER
175 : #pragma warning(push)
176 : #pragma warning(disable: 4355) // mask warning about "this" in initializers
177 : #endif
178 1893049 : GUIGlObject::GUIGlObject(GUIGlObjectType type, const std::string& microsimID, FXIcon* icon) :
179 3786098 : myGlID(GUIGlObjectStorage::gIDStorage.registerObject(this)),
180 1893049 : myGLObjectType(type),
181 1893049 : myMicrosimID(microsimID),
182 3786098 : myIcon(icon) {
183 : // make sure that reserved GLO_ADDITIONALELEMENT isn't used
184 : assert(myGLObjectType != GLO_ADDITIONALELEMENT);
185 1893049 : myFullName = createFullName();
186 1893049 : GUIGlObjectStorage::gIDStorage.changeName(this, myFullName);
187 1893049 : }
188 : #ifdef _MSC_VER
189 : #pragma warning(pop)
190 : #endif
191 :
192 :
193 1890816 : GUIGlObject::~GUIGlObject() {
194 1890816 : cleanupOnDestruction();
195 1890816 : GUIGlObjectStorage::gIDStorage.remove(getGlID());
196 1890816 : }
197 :
198 :
199 : void
200 2832167 : GUIGlObject::cleanupOnDestruction() {
201 : // remove all paramWindow related with this object
202 2832167 : for (const auto& paramWindow : myParamWindows) {
203 0 : paramWindow->removeObject(this);
204 : }
205 : // remove object from GLObjectValuePassConnector and GUIGlObjectStorage
206 2832167 : GLObjectValuePassConnector<double>::removeObject(*this);
207 2832167 : }
208 :
209 :
210 : std::string
211 0 : GUIGlObject::getParentName() const {
212 0 : return StringUtils::emptyString;
213 : }
214 :
215 :
216 : FXIcon*
217 0 : GUIGlObject::getGLIcon() const {
218 0 : return myIcon;
219 : }
220 :
221 :
222 : GUIParameterTableWindow*
223 0 : GUIGlObject::getTypeParameterWindow(GUIMainWindow& app, GUISUMOAbstractView& parent) {
224 : UNUSED_PARAMETER(&app);
225 : UNUSED_PARAMETER(&parent);
226 0 : return nullptr;
227 : }
228 :
229 :
230 : bool
231 0 : GUIGlObject::isGLObjectLocked() const {
232 : // by default unlocked
233 0 : return false;
234 : }
235 :
236 :
237 : void
238 0 : GUIGlObject::markAsFrontElement() {
239 : // by default nothing to do
240 0 : }
241 :
242 :
243 : void
244 0 : GUIGlObject::deleteGLObject() {
245 : // by default nothing to do
246 0 : }
247 :
248 :
249 : void
250 0 : GUIGlObject::selectGLObject() {
251 : // by default nothing to do
252 0 : }
253 :
254 :
255 : void
256 0 : GUIGlObject::updateGLObject() {
257 : // by default nothing to update
258 0 : }
259 :
260 :
261 : const std::string
262 0 : GUIGlObject::getOptionalName() const {
263 0 : return "";
264 : }
265 :
266 :
267 : void
268 0 : GUIGlObject::setMicrosimID(const std::string& newID) {
269 0 : myMicrosimID = newID;
270 0 : GUIGlObjectStorage::gIDStorage.changeName(this, createFullName());
271 0 : myFullName = createFullName();
272 0 : }
273 :
274 :
275 : void
276 0 : GUIGlObject::drawGLAdditional(GUISUMOAbstractView* const parent, const GUIVisualizationSettings& s) const {
277 : UNUSED_PARAMETER(&s);
278 : UNUSED_PARAMETER(parent);
279 0 : }
280 :
281 : #ifdef HAVE_OSG
282 :
283 : osg::Node*
284 0 : GUIGlObject::getNode() const {
285 0 : return myOSGNode;
286 : }
287 :
288 :
289 : void
290 44567 : GUIGlObject::setNode(osg::Node* node) {
291 44567 : myOSGNode = node;
292 44567 : }
293 :
294 : #endif
295 :
296 : void
297 0 : GUIGlObject::buildPopUpMenuCommonOptions(GUIGLObjectPopupMenu* ret, GUIMainWindow& app, GUISUMOAbstractView* parent,
298 : const SumoXMLTag tag, const bool selected, bool addSeparator) {
299 : // build header
300 0 : buildPopupHeader(ret, app);
301 : // build menu command for center button and copy cursor position to clipboard
302 0 : buildCenterPopupEntry(ret);
303 : // build menu commands for names
304 0 : GUIDesigns::buildFXMenuCommand(ret, TLF("Copy % name to clipboard", toString(tag)), nullptr, ret, MID_COPY_NAME);
305 0 : GUIDesigns::buildFXMenuCommand(ret, TLF("Copy % typed name to clipboard", toString(tag)), nullptr, ret, MID_COPY_TYPED_NAME);
306 0 : new FXMenuSeparator(ret);
307 0 : if (selected) {
308 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Remove from Selected"), GUIIconSubSys::getIcon(GUIIcon::FLAG_MINUS), parent, MID_REMOVESELECT);
309 : } else {
310 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Add to Selected"), GUIIconSubSys::getIcon(GUIIcon::FLAG_PLUS), parent, MID_ADDSELECT);
311 : }
312 0 : new FXMenuSeparator(ret);
313 0 : buildShowParamsPopupEntry(ret, true);
314 0 : buildPositionCopyEntry(ret, app, addSeparator);
315 0 : }
316 :
317 :
318 : void
319 0 : GUIGlObject::buildPopupHeader(GUIGLObjectPopupMenu* ret, GUIMainWindow& app, bool addSeparator) {
320 0 : new MFXMenuHeader(ret, app.getBoldFont(), getFullName().c_str(), myIcon, nullptr, 0);
321 0 : if (OptionsCont::getOptions().getBool("gui-testing")) {
322 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Copy test coordinates to clipboard"), nullptr, ret, MID_COPY_TEST_COORDINATES);
323 : }
324 0 : if (addSeparator) {
325 0 : new FXMenuSeparator(ret);
326 : }
327 0 : }
328 :
329 :
330 : void
331 0 : GUIGlObject::buildCenterPopupEntry(GUIGLObjectPopupMenu* ret, bool addSeparator) {
332 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Center"), GUIIconSubSys::getIcon(GUIIcon::RECENTERVIEW), ret, MID_CENTER);
333 0 : if (addSeparator) {
334 0 : new FXMenuSeparator(ret);
335 : }
336 0 : }
337 :
338 :
339 : void
340 0 : GUIGlObject::buildNameCopyPopupEntry(GUIGLObjectPopupMenu* ret, bool addSeparator) {
341 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Copy name to clipboard"), nullptr, ret, MID_COPY_NAME);
342 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Copy typed name to clipboard"), nullptr, ret, MID_COPY_TYPED_NAME);
343 0 : if (addSeparator) {
344 0 : new FXMenuSeparator(ret);
345 : }
346 0 : }
347 :
348 :
349 : void
350 0 : GUIGlObject::buildSelectionPopupEntry(GUIGLObjectPopupMenu* ret, bool addSeparator) {
351 0 : if (gSelected.isSelected(getType(), getGlID())) {
352 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Remove From Selected"), GUIIconSubSys::getIcon(GUIIcon::FLAG_MINUS), ret, MID_REMOVESELECT);
353 : } else {
354 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Add to Selected"), GUIIconSubSys::getIcon(GUIIcon::FLAG_PLUS), ret, MID_ADDSELECT);
355 : }
356 0 : if (addSeparator) {
357 0 : new FXMenuSeparator(ret);
358 : }
359 0 : }
360 :
361 :
362 : void
363 0 : GUIGlObject::buildShowParamsPopupEntry(GUIGLObjectPopupMenu* ret, bool addSeparator) {
364 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Show Parameter"), GUIIconSubSys::getIcon(GUIIcon::APP_TABLE), ret, MID_SHOWPARS);
365 0 : if (addSeparator) {
366 0 : new FXMenuSeparator(ret);
367 : }
368 0 : }
369 :
370 :
371 : void
372 0 : GUIGlObject::buildShowTypeParamsPopupEntry(GUIGLObjectPopupMenu* ret, bool addSeparator) {
373 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Show Type Parameter"), GUIIconSubSys::getIcon(GUIIcon::APP_TABLE), ret, MID_SHOWTYPEPARS);
374 0 : if (addSeparator) {
375 0 : new FXMenuSeparator(ret);
376 : }
377 0 : }
378 :
379 :
380 : void
381 0 : GUIGlObject::buildPositionCopyEntry(GUIGLObjectPopupMenu* ret, const GUIMainWindow& app, bool addSeparator) const {
382 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Copy cursor position to clipboard"), nullptr, ret, MID_COPY_CURSOR_POSITION);
383 0 : if (GeoConvHelper::getFinal().usingGeoProjection()) {
384 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Copy cursor geo-position to clipboard"), nullptr, ret, MID_COPY_CURSOR_GEOPOSITION);
385 : // create menu pane for edge operations
386 0 : FXMenuPane* showCursorGeoPositionPane = new FXMenuPane(ret);
387 0 : ret->insertMenuPaneChild(showCursorGeoPositionPane);
388 0 : new FXMenuCascade(ret, TL("Show cursor geo-position in "), nullptr, showCursorGeoPositionPane);
389 0 : for (const auto& mapper : app.getOnlineMaps()) {
390 0 : if (mapper.first == "GeoHack") {
391 0 : GUIDesigns::buildFXMenuCommand(showCursorGeoPositionPane, mapper.first, GUIIconSubSys::getIcon(GUIIcon::GEOHACK), ret, MID_SHOW_GEOPOSITION_ONLINE);
392 0 : } else if (mapper.first == "Google Maps") {
393 0 : GUIDesigns::buildFXMenuCommand(showCursorGeoPositionPane, mapper.first, GUIIconSubSys::getIcon(GUIIcon::GOOGLEMAPS), ret, MID_SHOW_GEOPOSITION_ONLINE);
394 0 : } else if (mapper.first == "OSM") {
395 0 : GUIDesigns::buildFXMenuCommand(showCursorGeoPositionPane, mapper.first, GUIIconSubSys::getIcon(GUIIcon::OSM), ret, MID_SHOW_GEOPOSITION_ONLINE);
396 : } else {
397 0 : GUIDesigns::buildFXMenuCommand(showCursorGeoPositionPane, mapper.first, nullptr, ret, MID_SHOW_GEOPOSITION_ONLINE);
398 : }
399 : }
400 : }
401 0 : if (addSeparator) {
402 0 : new FXMenuSeparator(ret);
403 : }
404 0 : }
405 :
406 :
407 : void
408 0 : GUIGlObject::buildShowManipulatorPopupEntry(GUIGLObjectPopupMenu* ret, bool addSeparator) {
409 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Open Manipulator..."), GUIIconSubSys::getIcon(GUIIcon::MANIP), ret, MID_MANIP);
410 0 : if (addSeparator) {
411 0 : new FXMenuSeparator(ret);
412 : }
413 0 : }
414 :
415 :
416 : void
417 0 : GUIGlObject::addParameterTable(GUIParameterTableWindow* t) {
418 : myParamWindows.insert(t);
419 0 : }
420 :
421 :
422 : void
423 0 : GUIGlObject::removeParameterTable(GUIParameterTableWindow* t) {
424 : std::set<GUIParameterTableWindow*>::iterator i = myParamWindows.find(t);
425 0 : if (i != myParamWindows.end()) {
426 : myParamWindows.erase(i);
427 : }
428 0 : }
429 :
430 :
431 : void
432 0 : GUIGlObject::buildShapePopupOptions(GUIMainWindow& app, GUIGLObjectPopupMenu* ret, const std::string& type) {
433 : assert(ret);
434 : // build header (<tag>:<ID>
435 0 : buildPopupHeader(ret, app, false);
436 : // build center
437 0 : buildCenterPopupEntry(ret);
438 : // build copy name
439 0 : buildNameCopyPopupEntry(ret);
440 : // build select/unselect
441 0 : buildSelectionPopupEntry(ret);
442 : // build show parameters
443 0 : buildShowParamsPopupEntry(ret, false);
444 : // build copy cursor position to clipboard
445 0 : buildPositionCopyEntry(ret, app);
446 : // only show type if isn't empty
447 0 : if (type != "") {
448 0 : GUIDesigns::buildFXMenuCommand(ret, TLF("type: %", type).c_str(), nullptr, nullptr, 0);
449 0 : new FXMenuSeparator(ret);
450 : }
451 0 : }
452 :
453 :
454 : void
455 0 : GUIGlObject::buildAdditionalsPopupOptions(GUIMainWindow& app, GUIGLObjectPopupMenu* ret, const std::string& type) {
456 : assert(ret);
457 : // build header (<tag>:<ID>
458 0 : buildPopupHeader(ret, app, false);
459 : // build center
460 0 : buildCenterPopupEntry(ret);
461 : // build copy name
462 0 : buildNameCopyPopupEntry(ret);
463 : // build select/unselect
464 0 : buildSelectionPopupEntry(ret);
465 : // build show parameters
466 0 : buildShowParamsPopupEntry(ret, false);
467 : // build copy cursor position to clipboard
468 0 : buildPositionCopyEntry(ret, app);
469 : // only show type if isn't empty
470 0 : if (type != "") {
471 0 : GUIDesigns::buildFXMenuCommand(ret, TLF("type: %", type).c_str(), nullptr, nullptr, 0);
472 0 : new FXMenuSeparator(ret);
473 : }
474 0 : }
475 :
476 :
477 : std::string
478 1893049 : GUIGlObject::createFullName() const {
479 3786098 : return TypeNames.getString(myGLObjectType) + ":" + getMicrosimID();
480 : }
481 :
482 :
483 : void
484 31921110 : GUIGlObject::drawName(const Position& pos, const double scale, const GUIVisualizationTextSettings& settings, const double angle, bool forceShow) const {
485 31921110 : if (settings.show(this) || forceShow) {
486 0 : GLHelper::drawTextSettings(settings, getMicrosimID(), pos, scale, angle);
487 : }
488 31921110 : }
489 :
490 :
491 : /****************************************************************************/
|