Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 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 1671402 : GUIGlObject::GUIGlObject(GUIGlObjectType type, const std::string& microsimID, FXIcon* icon) :
179 3342804 : myGlID(GUIGlObjectStorage::gIDStorage.registerObject(this)),
180 1671402 : myGLObjectType(type),
181 1671402 : myMicrosimID(microsimID),
182 3342804 : myIcon(icon) {
183 : // make sure that reserved GLO_ADDITIONALELEMENT isn't used
184 : assert(myGLObjectType != GLO_ADDITIONALELEMENT);
185 1671402 : myFullName = createFullName();
186 1671402 : GUIGlObjectStorage::gIDStorage.changeName(this, myFullName);
187 1671402 : }
188 : #ifdef _MSC_VER
189 : #pragma warning(pop)
190 : #endif
191 :
192 :
193 1669855 : GUIGlObject::~GUIGlObject() {
194 : // remove all paramWindow related with this object
195 1669855 : for (const auto& paramWindow : myParamWindows) {
196 0 : paramWindow->removeObject(this);
197 : }
198 : // remove object from GLObjectValuePassConnector and GUIGlObjectStorage
199 1669855 : GLObjectValuePassConnector<double>::removeObject(*this);
200 1669855 : GUIGlObjectStorage::gIDStorage.remove(getGlID());
201 1669855 : }
202 :
203 :
204 : std::string
205 0 : GUIGlObject::getParentName() const {
206 0 : return StringUtils::emptyString;
207 : }
208 :
209 :
210 : FXIcon*
211 0 : GUIGlObject::getGLIcon() const {
212 0 : return myIcon;
213 : }
214 :
215 :
216 : GUIParameterTableWindow*
217 0 : GUIGlObject::getTypeParameterWindow(GUIMainWindow& app, GUISUMOAbstractView& parent) {
218 : UNUSED_PARAMETER(&app);
219 : UNUSED_PARAMETER(&parent);
220 0 : return nullptr;
221 : }
222 :
223 :
224 : bool
225 0 : GUIGlObject::isGLObjectLocked() const {
226 : // by default unlocked
227 0 : return false;
228 : }
229 :
230 :
231 : void
232 0 : GUIGlObject::markAsFrontElement() {
233 : // by default nothing to do
234 0 : }
235 :
236 :
237 : void
238 0 : GUIGlObject::deleteGLObject() {
239 : // by default nothing to do
240 0 : }
241 :
242 :
243 : void
244 0 : GUIGlObject::selectGLObject() {
245 : // by default nothing to do
246 0 : }
247 :
248 :
249 : void
250 0 : GUIGlObject::updateGLObject() {
251 : // by default nothing to update
252 0 : }
253 :
254 :
255 : const std::string
256 0 : GUIGlObject::getOptionalName() const {
257 0 : return "";
258 : }
259 :
260 :
261 : void
262 0 : GUIGlObject::setMicrosimID(const std::string& newID) {
263 0 : myMicrosimID = newID;
264 0 : GUIGlObjectStorage::gIDStorage.changeName(this, createFullName());
265 0 : myFullName = createFullName();
266 0 : }
267 :
268 :
269 : void
270 0 : GUIGlObject::drawGLAdditional(GUISUMOAbstractView* const parent, const GUIVisualizationSettings& s) const {
271 : UNUSED_PARAMETER(&s);
272 : UNUSED_PARAMETER(parent);
273 0 : }
274 :
275 : #ifdef HAVE_OSG
276 :
277 : osg::Node*
278 0 : GUIGlObject::getNode() const {
279 0 : return myOSGNode;
280 : }
281 :
282 :
283 : void
284 43915 : GUIGlObject::setNode(osg::Node* node) {
285 43915 : myOSGNode = node;
286 43915 : }
287 :
288 : #endif
289 :
290 : void
291 0 : GUIGlObject::buildPopUpMenuCommonOptions(GUIGLObjectPopupMenu* ret, GUIMainWindow& app, GUISUMOAbstractView* parent,
292 : const SumoXMLTag tag, const bool selected, bool addSeparator) {
293 : // build header
294 0 : buildPopupHeader(ret, app);
295 : // build menu command for center button and copy cursor position to clipboard
296 0 : buildCenterPopupEntry(ret);
297 : // build menu commands for names
298 0 : GUIDesigns::buildFXMenuCommand(ret, TLF("Copy % name to clipboard", toString(tag)), nullptr, ret, MID_COPY_NAME);
299 0 : GUIDesigns::buildFXMenuCommand(ret, TLF("Copy % typed name to clipboard", toString(tag)), nullptr, ret, MID_COPY_TYPED_NAME);
300 0 : new FXMenuSeparator(ret);
301 0 : if (selected) {
302 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Remove from Selected"), GUIIconSubSys::getIcon(GUIIcon::FLAG_MINUS), parent, MID_REMOVESELECT);
303 : } else {
304 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Add to Selected"), GUIIconSubSys::getIcon(GUIIcon::FLAG_PLUS), parent, MID_ADDSELECT);
305 : }
306 0 : new FXMenuSeparator(ret);
307 0 : buildShowParamsPopupEntry(ret, true);
308 0 : buildPositionCopyEntry(ret, app, addSeparator);
309 0 : }
310 :
311 :
312 : void
313 0 : GUIGlObject::buildPopupHeader(GUIGLObjectPopupMenu* ret, GUIMainWindow& app, bool addSeparator) {
314 0 : new MFXMenuHeader(ret, app.getBoldFont(), getFullName().c_str(), myIcon, nullptr, 0);
315 0 : if (OptionsCont::getOptions().getBool("gui-testing")) {
316 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Copy test coordinates to clipboard"), nullptr, ret, MID_COPY_TEST_COORDINATES);
317 : }
318 0 : if (addSeparator) {
319 0 : new FXMenuSeparator(ret);
320 : }
321 0 : }
322 :
323 :
324 : void
325 0 : GUIGlObject::buildCenterPopupEntry(GUIGLObjectPopupMenu* ret, bool addSeparator) {
326 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Center"), GUIIconSubSys::getIcon(GUIIcon::RECENTERVIEW), ret, MID_CENTER);
327 0 : if (addSeparator) {
328 0 : new FXMenuSeparator(ret);
329 : }
330 0 : }
331 :
332 :
333 : void
334 0 : GUIGlObject::buildNameCopyPopupEntry(GUIGLObjectPopupMenu* ret, bool addSeparator) {
335 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Copy name to clipboard"), nullptr, ret, MID_COPY_NAME);
336 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Copy typed name to clipboard"), nullptr, ret, MID_COPY_TYPED_NAME);
337 0 : if (addSeparator) {
338 0 : new FXMenuSeparator(ret);
339 : }
340 0 : }
341 :
342 :
343 : void
344 0 : GUIGlObject::buildSelectionPopupEntry(GUIGLObjectPopupMenu* ret, bool addSeparator) {
345 0 : if (gSelected.isSelected(getType(), getGlID())) {
346 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Remove From Selected"), GUIIconSubSys::getIcon(GUIIcon::FLAG_MINUS), ret, MID_REMOVESELECT);
347 : } else {
348 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Add to Selected"), GUIIconSubSys::getIcon(GUIIcon::FLAG_PLUS), ret, MID_ADDSELECT);
349 : }
350 0 : if (addSeparator) {
351 0 : new FXMenuSeparator(ret);
352 : }
353 0 : }
354 :
355 :
356 : void
357 0 : GUIGlObject::buildShowParamsPopupEntry(GUIGLObjectPopupMenu* ret, bool addSeparator) {
358 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Show Parameter"), GUIIconSubSys::getIcon(GUIIcon::APP_TABLE), ret, MID_SHOWPARS);
359 0 : if (addSeparator) {
360 0 : new FXMenuSeparator(ret);
361 : }
362 0 : }
363 :
364 :
365 : void
366 0 : GUIGlObject::buildShowTypeParamsPopupEntry(GUIGLObjectPopupMenu* ret, bool addSeparator) {
367 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Show Type Parameter"), GUIIconSubSys::getIcon(GUIIcon::APP_TABLE), ret, MID_SHOWTYPEPARS);
368 0 : if (addSeparator) {
369 0 : new FXMenuSeparator(ret);
370 : }
371 0 : }
372 :
373 :
374 : void
375 0 : GUIGlObject::buildPositionCopyEntry(GUIGLObjectPopupMenu* ret, const GUIMainWindow& app, bool addSeparator) const {
376 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Copy cursor position to clipboard"), nullptr, ret, MID_COPY_CURSOR_POSITION);
377 0 : if (GeoConvHelper::getFinal().usingGeoProjection()) {
378 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Copy cursor geo-position to clipboard"), nullptr, ret, MID_COPY_CURSOR_GEOPOSITION);
379 : // create menu pane for edge operations
380 0 : FXMenuPane* showCursorGeoPositionPane = new FXMenuPane(ret);
381 0 : ret->insertMenuPaneChild(showCursorGeoPositionPane);
382 0 : new FXMenuCascade(ret, TL("Show cursor geo-position in "), nullptr, showCursorGeoPositionPane);
383 0 : for (const auto& mapper : app.getOnlineMaps()) {
384 0 : if (mapper.first == "GeoHack") {
385 0 : GUIDesigns::buildFXMenuCommand(showCursorGeoPositionPane, mapper.first, GUIIconSubSys::getIcon(GUIIcon::GEOHACK), ret, MID_SHOW_GEOPOSITION_ONLINE);
386 0 : } else if (mapper.first == "Google Maps") {
387 0 : GUIDesigns::buildFXMenuCommand(showCursorGeoPositionPane, mapper.first, GUIIconSubSys::getIcon(GUIIcon::GOOGLEMAPS), ret, MID_SHOW_GEOPOSITION_ONLINE);
388 0 : } else if (mapper.first == "OSM") {
389 0 : GUIDesigns::buildFXMenuCommand(showCursorGeoPositionPane, mapper.first, GUIIconSubSys::getIcon(GUIIcon::OSM), ret, MID_SHOW_GEOPOSITION_ONLINE);
390 : } else {
391 0 : GUIDesigns::buildFXMenuCommand(showCursorGeoPositionPane, mapper.first, nullptr, ret, MID_SHOW_GEOPOSITION_ONLINE);
392 : }
393 : }
394 : }
395 0 : if (addSeparator) {
396 0 : new FXMenuSeparator(ret);
397 : }
398 0 : }
399 :
400 :
401 : void
402 0 : GUIGlObject::buildShowManipulatorPopupEntry(GUIGLObjectPopupMenu* ret, bool addSeparator) {
403 0 : GUIDesigns::buildFXMenuCommand(ret, TL("Open Manipulator..."), GUIIconSubSys::getIcon(GUIIcon::MANIP), ret, MID_MANIP);
404 0 : if (addSeparator) {
405 0 : new FXMenuSeparator(ret);
406 : }
407 0 : }
408 :
409 :
410 : void
411 0 : GUIGlObject::addParameterTable(GUIParameterTableWindow* t) {
412 : myParamWindows.insert(t);
413 0 : }
414 :
415 :
416 : void
417 0 : GUIGlObject::removeParameterTable(GUIParameterTableWindow* t) {
418 : std::set<GUIParameterTableWindow*>::iterator i = myParamWindows.find(t);
419 0 : if (i != myParamWindows.end()) {
420 : myParamWindows.erase(i);
421 : }
422 0 : }
423 :
424 :
425 : void
426 0 : GUIGlObject::buildShapePopupOptions(GUIMainWindow& app, GUIGLObjectPopupMenu* ret, const std::string& type) {
427 : assert(ret);
428 : // build header (<tag>:<ID>
429 0 : buildPopupHeader(ret, app, false);
430 : // build center
431 0 : buildCenterPopupEntry(ret);
432 : // build copy name
433 0 : buildNameCopyPopupEntry(ret);
434 : // build select/unselect
435 0 : buildSelectionPopupEntry(ret);
436 : // build show parameters
437 0 : buildShowParamsPopupEntry(ret, false);
438 : // build copy cursor position to clipboard
439 0 : buildPositionCopyEntry(ret, app);
440 : // only show type if isn't empty
441 0 : if (type != "") {
442 0 : GUIDesigns::buildFXMenuCommand(ret, TLF("type: %", type).c_str(), nullptr, nullptr, 0);
443 0 : new FXMenuSeparator(ret);
444 : }
445 0 : }
446 :
447 :
448 : void
449 0 : GUIGlObject::buildAdditionalsPopupOptions(GUIMainWindow& app, GUIGLObjectPopupMenu* ret, const std::string& type) {
450 : assert(ret);
451 : // build header (<tag>:<ID>
452 0 : buildPopupHeader(ret, app, false);
453 : // build center
454 0 : buildCenterPopupEntry(ret);
455 : // build copy name
456 0 : buildNameCopyPopupEntry(ret);
457 : // build select/unselect
458 0 : buildSelectionPopupEntry(ret);
459 : // build show parameters
460 0 : buildShowParamsPopupEntry(ret, false);
461 : // build copy cursor position to clipboard
462 0 : buildPositionCopyEntry(ret, app);
463 : // only show type if isn't empty
464 0 : if (type != "") {
465 0 : GUIDesigns::buildFXMenuCommand(ret, TLF("type: %", type).c_str(), nullptr, nullptr, 0);
466 0 : new FXMenuSeparator(ret);
467 : }
468 0 : }
469 :
470 :
471 : std::string
472 1671402 : GUIGlObject::createFullName() const {
473 3342804 : return TypeNames.getString(myGLObjectType) + ":" + getMicrosimID();
474 : }
475 :
476 :
477 : void
478 23553776 : GUIGlObject::drawName(const Position& pos, const double scale, const GUIVisualizationTextSettings& settings, const double angle, bool forceShow) const {
479 23553776 : if (settings.show(this) || forceShow) {
480 0 : GLHelper::drawTextSettings(settings, getMicrosimID(), pos, scale, angle);
481 : }
482 23553776 : }
483 :
484 :
485 : /****************************************************************************/
|