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 GUIJunctionWrapper.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @author Laura Bieker
19 : /// @author Andreas Gaubatz
20 : /// @date Mon, 1 Jul 2003
21 : ///
22 : // }
23 : /****************************************************************************/
24 : #include <config.h>
25 :
26 : #include <string>
27 : #include <utility>
28 : #include <microsim/MSLane.h>
29 : #include <microsim/MSEdge.h>
30 : #include <microsim/MSJunction.h>
31 : #include <utils/geom/Position.h>
32 : #include <utils/geom/GeomHelper.h>
33 : #include <microsim/MSNet.h>
34 : #include <microsim/MSInternalJunction.h>
35 : #include <microsim/traffic_lights/MSTrafficLightLogic.h>
36 : #include <microsim/traffic_lights/MSTLLogicControl.h>
37 : #include <gui/GUIApplicationWindow.h>
38 : #include <gui/GUIGlobals.h>
39 : #include <utils/gui/windows/GUIAppEnum.h>
40 : #include <utils/gui/windows/GUISUMOAbstractView.h>
41 : #include "GUIJunctionWrapper.h"
42 : #include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
43 : #include <utils/gui/div/GUIGlobalSelection.h>
44 : #include <utils/gui/div/GUIParameterTableWindow.h>
45 : #include <utils/gui/div/GLHelper.h>
46 : #include <utils/gui/globjects/GLIncludes.h>
47 :
48 : #include <osgview/GUIOSGHeader.h>
49 :
50 : // ===========================================================================
51 : // method definitions
52 : // ===========================================================================
53 93042 : GUIJunctionWrapper::GUIJunctionWrapper(MSJunction& junction, const std::string& tllID):
54 : GUIGlObject(GLO_JUNCTION, junction.getID(), GUIIconSubSys::getIcon(GUIIcon::JUNCTION)),
55 93042 : myJunction(junction),
56 186084 : myTesselation(junction.getID(), "", RGBColor::MAGENTA, junction.getShape(), false, true, 0),
57 93042 : myExaggeration(1),
58 186084 : myTLLID(tllID) {
59 93042 : if (myJunction.getShape().size() == 0) {
60 27386 : Position pos = myJunction.getPosition();
61 27386 : myBoundary = Boundary(pos.x() - 1., pos.y() - 1., pos.x() + 1., pos.y() + 1.);
62 : } else {
63 65656 : myBoundary = myJunction.getShape().getBoxBoundary();
64 : }
65 93042 : myMaxSize = MAX2(myBoundary.getWidth(), myBoundary.getHeight());
66 93042 : myIsInternal = myJunction.getType() == SumoXMLNodeType::INTERNAL;
67 93042 : myAmWaterway = myJunction.getIncoming().size() + myJunction.getOutgoing().size() > 0;
68 93042 : myAmRailway = myJunction.getIncoming().size() + myJunction.getOutgoing().size() > 0;
69 93042 : myAmAirway = myJunction.getIncoming().size() + myJunction.getOutgoing().size() > 0;
70 280334 : for (auto it = myJunction.getIncoming().begin(); it != myJunction.getIncoming().end() && (myAmWaterway || myAmRailway); ++it) {
71 187292 : if (!(*it)->isInternal()) {
72 62484 : if (!isWaterway((*it)->getPermissions())) {
73 62446 : myAmWaterway = false;
74 : }
75 62484 : if (!isRailway((*it)->getPermissions())) {
76 56932 : myAmRailway = false;
77 : }
78 62484 : if (!isAirway((*it)->getPermissions())) {
79 62484 : myAmAirway = false;
80 : }
81 : }
82 : }
83 107446 : for (auto it = myJunction.getOutgoing().begin(); it != myJunction.getOutgoing().end() && (myAmWaterway || myAmRailway); ++it) {
84 14404 : if (!(*it)->isInternal()) {
85 9906 : if (!isWaterway((*it)->getPermissions())) {
86 9873 : myAmWaterway = false;
87 : }
88 9906 : if (!isRailway((*it)->getPermissions())) {
89 4387 : myAmRailway = false;
90 : }
91 9906 : if (!isAirway((*it)->getPermissions())) {
92 9906 : myAmAirway = false;
93 : }
94 : }
95 : }
96 93042 : myTesselation.getShapeRef().closePolygon();
97 93042 : }
98 :
99 :
100 278721 : GUIJunctionWrapper::~GUIJunctionWrapper() {}
101 :
102 :
103 : GUIGLObjectPopupMenu*
104 0 : GUIJunctionWrapper::getPopUpMenu(GUIMainWindow& app,
105 : GUISUMOAbstractView& parent) {
106 0 : GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
107 0 : buildPopupHeader(ret, app);
108 0 : buildCenterPopupEntry(ret);
109 0 : buildNameCopyPopupEntry(ret);
110 0 : buildSelectionPopupEntry(ret);
111 0 : buildShowParamsPopupEntry(ret);
112 0 : buildPositionCopyEntry(ret, app);
113 0 : return ret;
114 : }
115 :
116 :
117 : GUIParameterTableWindow*
118 0 : GUIJunctionWrapper::getParameterWindow(GUIMainWindow& app, GUISUMOAbstractView&) {
119 0 : GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
120 : // add items
121 0 : ret->mkItem(TL("type"), false, toString(myJunction.getType()));
122 0 : ret->mkItem(TL("name"), false, myJunction.getName());
123 : // close building
124 0 : ret->closeBuilding(&myJunction);
125 0 : return ret;
126 : }
127 :
128 :
129 : double
130 6892471 : GUIJunctionWrapper::getExaggeration(const GUIVisualizationSettings& s) const {
131 6892471 : return s.junctionSize.getExaggeration(s, this, 4);
132 : }
133 :
134 :
135 : Boundary
136 0 : GUIJunctionWrapper::getCenteringBoundary() const {
137 0 : if (GUIGlobals::gSecondaryShape) {
138 0 : const Position& p = myJunction.getPosition(true);
139 0 : return Boundary(p.x() - 1, p.y() - 1, p.x() + 1, p.y() + 1);
140 : }
141 : Boundary b = myBoundary;
142 0 : b.grow(1);
143 : return b;
144 : }
145 :
146 : const std::string
147 0 : GUIJunctionWrapper::getOptionalName() const {
148 0 : return myJunction.getName();
149 : }
150 :
151 : void
152 10462958 : GUIJunctionWrapper::drawGL(const GUIVisualizationSettings& s) const {
153 10462958 : const bool s2 = s.secondaryShape;
154 10462958 : if (!myIsInternal && s.drawJunctionShape && !s2) {
155 : // check whether it is not too small
156 6892471 : const double exaggeration = getExaggeration(s);
157 6892471 : if (s.scale * exaggeration >= s.junctionSize.minSize) {
158 1527896 : GLHelper::pushMatrix();
159 1527896 : GLHelper::pushName(getGlID());
160 1527896 : const double colorValue = getColorValue(s, s.junctionColorer.getActive());
161 1527896 : const RGBColor color = s.junctionColorer.getScheme().getColor(colorValue);
162 1527896 : GLHelper::setColor(color);
163 :
164 : // recognize full transparency and simply don't draw
165 1527896 : if (color.alpha() != 0) {
166 1513092 : if ((exaggeration > 1 || myExaggeration > 1) && exaggeration != myExaggeration) {
167 0 : myExaggeration = exaggeration;
168 0 : myTesselation.setShape(myJunction.getShape());
169 0 : myTesselation.getShapeRef().closePolygon();
170 0 : myTesselation.getShapeRef().scaleRelative(exaggeration);
171 : myTesselation.myTesselation.clear();
172 : }
173 1513092 : glTranslated(0, 0, getType());
174 1513092 : if (s.scale * myMaxSize < 40.) {
175 1261440 : GLHelper::drawFilledPoly(myTesselation.getShape(), true);
176 : } else {
177 251652 : myTesselation.drawTesselation(myTesselation.getShape());
178 : }
179 : // make small junctions more visible when coloring by type
180 1513092 : if (myJunction.getType() == SumoXMLNodeType::RAIL_SIGNAL && s.junctionColorer.getActive() == 2) {
181 0 : glTranslated(myJunction.getPosition(s2).x(), myJunction.getPosition(s2).y(), getType() + 0.05);
182 0 : GLHelper::drawFilledCircle(2 * exaggeration, 12);
183 : }
184 : }
185 1527896 : GLHelper::popName();
186 1527896 : GLHelper::popMatrix();
187 1527895 : if (s.geometryIndices.show(this)) {
188 0 : GLHelper::debugVertices(myJunction.getShape(), s.geometryIndices, s.scale);
189 : }
190 : }
191 : }
192 10462957 : if (myIsInternal) {
193 3570487 : drawName(myJunction.getPosition(s2), s.scale, s.internalJunctionName, s.angle);
194 : } else {
195 6892470 : drawName(myJunction.getPosition(s2), s.scale, s.junctionID, s.angle);
196 6892470 : if (s.junctionName.show(this) && myJunction.getName() != "") {
197 0 : GLHelper::drawTextSettings(s.junctionName, myJunction.getName(), myJunction.getPosition(s2), s.scale, s.angle);
198 : }
199 6892470 : if ((s.tlsPhaseIndex.show(this) || s.tlsPhaseName.show(this)) && myTLLID != "") {
200 0 : const MSTrafficLightLogic* active = MSNet::getInstance()->getTLSControl().getActive(myTLLID);
201 0 : if (s.tlsPhaseIndex.show(this)) {
202 0 : const int index = active->getCurrentPhaseIndex();
203 0 : GLHelper::drawTextSettings(s.tlsPhaseIndex, toString(index), myJunction.getPosition(s2), s.scale, s.angle);
204 : }
205 0 : if (s.tlsPhaseName.show(this)) {
206 0 : const std::string& name = active->getCurrentPhaseDef().getName();
207 0 : if (name != "") {
208 0 : const Position offset = (s.tlsPhaseIndex.show(this) ?
209 0 : Position(0, 0.8 * s.tlsPhaseIndex.scaledSize(s.scale)).rotateAround2D(DEG2RAD(-s.angle), Position(0, 0))
210 : : Position(0, 0));
211 0 : GLHelper::drawTextSettings(s.tlsPhaseName, name, myJunction.getPosition(s2) - offset, s.scale, s.angle);
212 : }
213 : }
214 : }
215 : }
216 10462957 : }
217 :
218 :
219 : double
220 1664546 : GUIJunctionWrapper::getColorValue(const GUIVisualizationSettings& /* s */, int activeScheme) const {
221 1664546 : switch (activeScheme) {
222 1664546 : case 0:
223 1664546 : if (myAmWaterway) {
224 : return 1;
225 1664278 : } else if (myAmRailway && MSNet::getInstance()->hasInternalLinks()) {
226 : return 2;
227 1648146 : } else if (myAmAirway) {
228 : return 3;
229 : } else {
230 : return 0;
231 : }
232 0 : case 1:
233 0 : return gSelected.isSelected(getType(), getGlID()) ? 1 : 0;
234 0 : case 2:
235 0 : switch (myJunction.getType()) {
236 : case SumoXMLNodeType::TRAFFIC_LIGHT:
237 : return 0;
238 : case SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION:
239 : return 1;
240 : case SumoXMLNodeType::PRIORITY:
241 : return 2;
242 : case SumoXMLNodeType::PRIORITY_STOP:
243 : return 3;
244 : case SumoXMLNodeType::RIGHT_BEFORE_LEFT:
245 : return 4;
246 0 : case SumoXMLNodeType::ALLWAY_STOP:
247 0 : return 5;
248 0 : case SumoXMLNodeType::DISTRICT:
249 0 : return 6;
250 0 : case SumoXMLNodeType::NOJUNCTION:
251 0 : return 7;
252 : case SumoXMLNodeType::DEAD_END:
253 : case SumoXMLNodeType::DEAD_END_DEPRECATED:
254 : return 8;
255 : case SumoXMLNodeType::UNKNOWN:
256 : case SumoXMLNodeType::INTERNAL:
257 : assert(false);
258 : return 8;
259 0 : case SumoXMLNodeType::RAIL_SIGNAL:
260 0 : return 9;
261 0 : case SumoXMLNodeType::ZIPPER:
262 0 : return 10;
263 0 : case SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED:
264 0 : return 11;
265 0 : case SumoXMLNodeType::RAIL_CROSSING:
266 0 : return 12;
267 0 : case SumoXMLNodeType::LEFT_BEFORE_RIGHT:
268 0 : return 13;
269 : default:
270 : assert(false);
271 : return 0;
272 : }
273 0 : case 3:
274 0 : return myJunction.getPosition().z();
275 : default:
276 : assert(false);
277 : return 0;
278 : }
279 : }
280 :
281 : #ifdef HAVE_OSG
282 : void
283 136650 : GUIJunctionWrapper::updateColor(const GUIVisualizationSettings& s) {
284 136650 : const double colorValue = getColorValue(s, s.junctionColorer.getActive());
285 136650 : const RGBColor& col = s.junctionColorer.getScheme().getColor(colorValue);
286 136650 : osg::Vec4ubArray* colors = dynamic_cast<osg::Vec4ubArray*>(myGeom->getColorArray());
287 136650 : (*colors)[0].set(col.red(), col.green(), col.blue(), col.alpha());
288 136650 : myGeom->setColorArray(colors);
289 136650 : }
290 : #endif
291 :
292 :
293 : /****************************************************************************/
|