1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file    GUIJunctionWrapper.cpp
11 /// @author  Daniel Krajzewicz
12 /// @author  Jakob Erdmann
13 /// @author  Michael Behrisch
14 /// @author  Laura Bieker
15 /// @author  Andreas Gaubatz
16 /// @date    Mon, 1 Jul 2003
17 /// @version $Id$
18 ///
19 // }
20 /****************************************************************************/
21 
22 
23 // ===========================================================================
24 // included modules
25 // ===========================================================================
26 #include <config.h>
27 
28 #include <string>
29 #include <utility>
30 #ifdef HAVE_OSG
31 #include <osg/Geometry>
32 #endif
33 #include <microsim/MSLane.h>
34 #include <microsim/MSEdge.h>
35 #include <microsim/MSJunction.h>
36 #include <utils/geom/Position.h>
37 #include <utils/geom/GeomHelper.h>
38 #include <microsim/MSNet.h>
39 #include <microsim/MSInternalJunction.h>
40 #include <microsim/traffic_lights/MSTrafficLightLogic.h>
41 #include <microsim/traffic_lights/MSTLLogicControl.h>
42 #include <gui/GUIApplicationWindow.h>
43 #include <gui/GUIGlobals.h>
44 #include <utils/gui/windows/GUIAppEnum.h>
45 #include <utils/gui/windows/GUISUMOAbstractView.h>
46 #include "GUIJunctionWrapper.h"
47 #include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
48 #include <utils/gui/div/GUIGlobalSelection.h>
49 #include <utils/gui/div/GUIParameterTableWindow.h>
50 #include <utils/gui/div/GLHelper.h>
51 #include <utils/gui/globjects/GLIncludes.h>
52 
53 //#define GUIJunctionWrapper_DEBUG_DRAW_NODE_SHAPE_VERTICES
54 
55 // ===========================================================================
56 // method definitions
57 // ===========================================================================
GUIJunctionWrapper(MSJunction & junction,const std::string & tllID)58 GUIJunctionWrapper::GUIJunctionWrapper(MSJunction& junction, const std::string& tllID):
59     GUIGlObject(GLO_JUNCTION, junction.getID()),
60     myJunction(junction),
61     myTLLID(tllID) {
62     if (myJunction.getShape().size() == 0) {
63         Position pos = myJunction.getPosition();
64         myBoundary = Boundary(pos.x() - 1., pos.y() - 1., pos.x() + 1., pos.y() + 1.);
65     } else {
66         myBoundary = myJunction.getShape().getBoxBoundary();
67     }
68     myMaxSize = MAX2(myBoundary.getWidth(), myBoundary.getHeight());
69     myIsInternal = myJunction.getType() == NODETYPE_INTERNAL;
70     myAmWaterway = myJunction.getIncoming().size() + myJunction.getOutgoing().size() > 0;
71     myAmRailway = myJunction.getIncoming().size() + myJunction.getOutgoing().size() > 0;
72     for (auto it = myJunction.getIncoming().begin(); it != myJunction.getIncoming().end() && (myAmWaterway || myAmRailway); ++it) {
73         if (!(*it)->isInternal()) {
74             if (!isWaterway((*it)->getPermissions())) {
75                 myAmWaterway = false;
76             }
77             if (!isRailway((*it)->getPermissions())) {
78                 myAmRailway = false;
79             }
80         }
81     }
82     for (auto it = myJunction.getOutgoing().begin(); it != myJunction.getOutgoing().end() && (myAmWaterway || myAmRailway); ++it) {
83         if (!(*it)->isInternal()) {
84             if (!isWaterway((*it)->getPermissions())) {
85                 myAmWaterway = false;
86             }
87             if (!isRailway((*it)->getPermissions())) {
88                 myAmRailway = false;
89             }
90         }
91     }
92 }
93 
94 
~GUIJunctionWrapper()95 GUIJunctionWrapper::~GUIJunctionWrapper() {}
96 
97 
98 GUIGLObjectPopupMenu*
getPopUpMenu(GUIMainWindow & app,GUISUMOAbstractView & parent)99 GUIJunctionWrapper::getPopUpMenu(GUIMainWindow& app,
100                                  GUISUMOAbstractView& parent) {
101     GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, *this);
102     buildPopupHeader(ret, app);
103     buildCenterPopupEntry(ret);
104     buildNameCopyPopupEntry(ret);
105     buildSelectionPopupEntry(ret);
106     buildShowParamsPopupEntry(ret);
107     buildPositionCopyEntry(ret, false);
108     return ret;
109 }
110 
111 
112 GUIParameterTableWindow*
getParameterWindow(GUIMainWindow & app,GUISUMOAbstractView &)113 GUIJunctionWrapper::getParameterWindow(GUIMainWindow& app, GUISUMOAbstractView&) {
114     GUIParameterTableWindow* ret =
115         new GUIParameterTableWindow(app, *this, 12 + (int)myJunction.getParametersMap().size());
116     // add items
117     ret->mkItem("type", false, toString(myJunction.getType()));
118     // close building
119     ret->closeBuilding(&myJunction);
120     return ret;
121 }
122 
123 
124 Boundary
getCenteringBoundary() const125 GUIJunctionWrapper::getCenteringBoundary() const {
126     Boundary b = myBoundary;
127     b.grow(1);
128     return b;
129 }
130 
131 
132 void
drawGL(const GUIVisualizationSettings & s) const133 GUIJunctionWrapper::drawGL(const GUIVisualizationSettings& s) const {
134     if (!myIsInternal && s.drawJunctionShape) {
135         // check whether it is not too small
136         const double exaggeration = s.junctionSize.getExaggeration(s, this, 4);
137         if (s.scale * exaggeration >= s.junctionSize.minSize) {
138             glPushMatrix();
139             glPushName(getGlID());
140             const double colorValue = getColorValue(s);
141             const RGBColor color = s.junctionColorer.getScheme().getColor(colorValue);
142             GLHelper::setColor(color);
143 
144             // recognize full transparency and simply don't draw
145             if (color.alpha() != 0) {
146                 PositionVector shape = myJunction.getShape();
147                 shape.closePolygon();
148                 if (exaggeration > 1) {
149                     shape.scaleRelative(exaggeration);
150                 }
151                 glTranslated(0, 0, getType());
152                 if (s.scale * myMaxSize < 40.) {
153                     GLHelper::drawFilledPoly(shape, true);
154                 } else {
155                     GLHelper::drawFilledPolyTesselated(shape, true);
156                 }
157 #ifdef GUIJunctionWrapper_DEBUG_DRAW_NODE_SHAPE_VERTICES
158                 GLHelper::debugVertices(shape, 80 / s.scale);
159 #endif
160                 // make small junctions more visible when coloring by type
161                 if (myJunction.getType() == NODETYPE_RAIL_SIGNAL && s.junctionColorer.getActive() == 2) {
162                     glTranslated(myJunction.getPosition().x(), myJunction.getPosition().y(), getType() + 0.05);
163                     GLHelper::drawFilledCircle(2 * exaggeration, 12);
164                 }
165             }
166             glPopName();
167             glPopMatrix();
168         }
169     }
170     if (myIsInternal) {
171         drawName(myJunction.getPosition(), s.scale, s.internalJunctionName, s.angle);
172     } else {
173         drawName(myJunction.getPosition(), s.scale, s.junctionName, s.angle);
174         if (s.tlsPhaseIndex.show && myTLLID != "") {
175             const MSTrafficLightLogic* active = MSNet::getInstance()->getTLSControl().getActive(myTLLID);
176             const int index = active->getCurrentPhaseIndex();
177             const std::string& name = active->getCurrentPhaseDef().getName();
178             GLHelper::drawTextSettings(s.tlsPhaseIndex, toString(index), myJunction.getPosition(), s.scale, s.angle);
179             if (name != "") {
180                 const Position offset = Position(0, 0.8 * s.tlsPhaseIndex.scaledSize(s.scale)).rotateAround2D(DEG2RAD(-s.angle), Position(0, 0));
181                 GLHelper::drawTextSettings(s.tlsPhaseIndex, name, myJunction.getPosition() - offset, s.scale, s.angle);
182             }
183         }
184     }
185 }
186 
187 
188 double
getColorValue(const GUIVisualizationSettings & s) const189 GUIJunctionWrapper::getColorValue(const GUIVisualizationSettings& s) const {
190     switch (s.junctionColorer.getActive()) {
191         case 0:
192             if (myAmWaterway) {
193                 return 1;
194             } else if (myAmRailway && MSNet::getInstance()->hasInternalLinks()) {
195                 return 2;
196             } else {
197                 return 0;
198             }
199         case 1:
200             return gSelected.isSelected(getType(), getGlID()) ? 1 : 0;
201         case 2:
202             switch (myJunction.getType()) {
203                 case NODETYPE_TRAFFIC_LIGHT:
204                     return 0;
205                 case NODETYPE_TRAFFIC_LIGHT_NOJUNCTION:
206                     return 1;
207                 case NODETYPE_PRIORITY:
208                     return 2;
209                 case NODETYPE_PRIORITY_STOP:
210                     return 3;
211                 case NODETYPE_RIGHT_BEFORE_LEFT:
212                     return 4;
213                 case NODETYPE_ALLWAY_STOP:
214                     return 5;
215                 case NODETYPE_DISTRICT:
216                     return 6;
217                 case NODETYPE_NOJUNCTION:
218                     return 7;
219                 case NODETYPE_DEAD_END:
220                 case NODETYPE_DEAD_END_DEPRECATED:
221                     return 8;
222                 case NODETYPE_UNKNOWN:
223                 case NODETYPE_INTERNAL:
224                     assert(false);
225                     return 8;
226                 case NODETYPE_RAIL_SIGNAL:
227                     return 9;
228                 case NODETYPE_ZIPPER:
229                     return 10;
230                 case NODETYPE_TRAFFIC_LIGHT_RIGHT_ON_RED:
231                     return 11;
232                 case NODETYPE_RAIL_CROSSING:
233                     return 12;
234             }
235         case 3:
236             return myJunction.getPosition().z();
237         default:
238             assert(false);
239             return 0;
240     }
241 }
242 
243 #ifdef HAVE_OSG
244 void
updateColor(const GUIVisualizationSettings & s)245 GUIJunctionWrapper::updateColor(const GUIVisualizationSettings& s) {
246     const double colorValue = getColorValue(s);
247     const RGBColor& col = s.junctionColorer.getScheme().getColor(colorValue);
248     osg::Vec4ubArray* colors = dynamic_cast<osg::Vec4ubArray*>(myGeom->getColorArray());
249     (*colors)[0].set(col.red(), col.green(), col.blue(), col.alpha());
250     myGeom->setColorArray(colors);
251 }
252 #endif
253 
254 
255 /****************************************************************************/
256 
257