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    GUITriggeredRerouter.cpp
11 /// @author  Daniel Krajzewicz
12 /// @author  Jakob Erdmann
13 /// @author  Michael Behrisch
14 /// @date    Mon, 25.07.2005
15 /// @version $Id$
16 ///
17 // Reroutes vehicles passing an edge (gui version)
18 /****************************************************************************/
19 
20 
21 // ===========================================================================
22 // included modules
23 // ===========================================================================
24 #include <config.h>
25 
26 #include <string>
27 #include <utils/common/MsgHandler.h>
28 #include <utils/geom/PositionVector.h>
29 #include <utils/geom/Boundary.h>
30 #include <utils/gui/div/GLHelper.h>
31 #include <utils/common/ToString.h>
32 #include <utils/common/Command.h>
33 #include <microsim/MSNet.h>
34 #include <microsim/MSLane.h>
35 #include <microsim/MSEdge.h>
36 #include <guisim/GUINet.h>
37 #include <guisim/GUIEdge.h>
38 #include "GUITriggeredRerouter.h"
39 #include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
40 #include <utils/gui/windows/GUIAppEnum.h>
41 #include <gui/GUIGlobals.h>
42 #include <utils/gui/div/GUIParameterTableWindow.h>
43 #include <gui/GUIApplicationWindow.h>
44 #include <microsim/logging/FunctionBinding.h>
45 #include <utils/gui/div/GUIGlobalSelection.h>
46 #include <utils/gui/globjects/GLIncludes.h>
47 
48 
49 // ===========================================================================
50 // FOX callback mapping
51 // ===========================================================================
52 /* -------------------------------------------------------------------------
53  * GUITriggeredRerouter::GUITriggeredRerouterPopupMenu - mapping
54  * ----------------------------------------------------------------------- */
55 FXDEFMAP(GUITriggeredRerouter::GUITriggeredRerouterPopupMenu)
56 GUITriggeredRerouterPopupMenuMap[] = {
57     FXMAPFUNC(SEL_COMMAND,  MID_MANIP,         GUITriggeredRerouter::GUITriggeredRerouterPopupMenu::onCmdOpenManip),
58 
59 };
60 
61 // Object implementation
62 FXIMPLEMENT(GUITriggeredRerouter::GUITriggeredRerouterPopupMenu, GUIGLObjectPopupMenu, GUITriggeredRerouterPopupMenuMap, ARRAYNUMBER(GUITriggeredRerouterPopupMenuMap))
63 
64 
65 /* -------------------------------------------------------------------------
66  * GUITriggeredRerouter::GUIManip_TriggeredRerouter - mapping
67  * ----------------------------------------------------------------------- */
68 FXDEFMAP(GUITriggeredRerouter::GUIManip_TriggeredRerouter) GUIManip_TriggeredRerouterMap[] = {
69     FXMAPFUNC(SEL_COMMAND,  GUITriggeredRerouter::GUIManip_TriggeredRerouter::MID_USER_DEF, GUITriggeredRerouter::GUIManip_TriggeredRerouter::onCmdUserDef),
70     FXMAPFUNC(SEL_UPDATE,   GUITriggeredRerouter::GUIManip_TriggeredRerouter::MID_USER_DEF, GUITriggeredRerouter::GUIManip_TriggeredRerouter::onUpdUserDef),
71     FXMAPFUNC(SEL_COMMAND,  GUITriggeredRerouter::GUIManip_TriggeredRerouter::MID_OPTION,   GUITriggeredRerouter::GUIManip_TriggeredRerouter::onCmdChangeOption),
72     FXMAPFUNC(SEL_COMMAND,  GUITriggeredRerouter::GUIManip_TriggeredRerouter::MID_CLOSE,    GUITriggeredRerouter::GUIManip_TriggeredRerouter::onCmdClose),
73 };
74 
FXIMPLEMENT(GUITriggeredRerouter::GUIManip_TriggeredRerouter,GUIManipulator,GUIManip_TriggeredRerouterMap,ARRAYNUMBER (GUIManip_TriggeredRerouterMap))75 FXIMPLEMENT(GUITriggeredRerouter::GUIManip_TriggeredRerouter, GUIManipulator, GUIManip_TriggeredRerouterMap, ARRAYNUMBER(GUIManip_TriggeredRerouterMap))
76 
77 
78 // ===========================================================================
79 // method definitions
80 // ===========================================================================
81 /* -------------------------------------------------------------------------
82  * GUITriggeredRerouter::GUIManip_TriggeredRerouter - methods
83  * ----------------------------------------------------------------------- */
84 GUITriggeredRerouter::GUIManip_TriggeredRerouter::GUIManip_TriggeredRerouter(
85     GUIMainWindow& app,
86     const std::string& name, GUITriggeredRerouter& o,
87     int /*xpos*/, int /*ypos*/)
88     : GUIManipulator(app, name, 0, 0), myParent(&app),
89       myChosenValue(0), myChosenTarget(myChosenValue, nullptr, MID_OPTION),
90       myUsageProbability(o.getProbability()), myUsageProbabilityTarget(myUsageProbability),
91       myObject(&o) {
92     myChosenTarget.setTarget(this);
93     FXVerticalFrame* f1 =
94         new FXVerticalFrame(this, LAYOUT_FILL_X | LAYOUT_FILL_Y, 0, 0, 0, 0, 0, 0, 0, 0);
95 
96     FXGroupBox* gp = new FXGroupBox(f1, "Change Probability",
97                                     GROUPBOX_TITLE_LEFT | FRAME_SUNKEN | FRAME_RIDGE,
98                                     0, 0, 0, 0,  4, 4, 1, 1, 2, 0);
99     {
100         // default
101         FXHorizontalFrame* gf1 =
102             new FXHorizontalFrame(gp, LAYOUT_TOP | LAYOUT_LEFT, 0, 0, 0, 0, 10, 10, 5, 5);
103         new FXRadioButton(gf1, "Default", &myChosenTarget, FXDataTarget::ID_OPTION + 0,
104                           ICON_BEFORE_TEXT | LAYOUT_SIDE_TOP,
105                           0, 0, 0, 0,   2, 2, 0, 0);
106     }
107     {
108         // free
109         FXHorizontalFrame* gf12 =
110             new FXHorizontalFrame(gp, LAYOUT_TOP | LAYOUT_LEFT, 0, 0, 0, 0, 10, 10, 5, 5);
111         new FXRadioButton(gf12, "User Given: ", &myChosenTarget, FXDataTarget::ID_OPTION + 1,
112                           ICON_BEFORE_TEXT | LAYOUT_SIDE_TOP | LAYOUT_CENTER_Y,
113                           0, 0, 0, 0,   2, 2, 0, 0);
114         myUsageProbabilityDial =
115             new FXRealSpinner(gf12, 10, this, MID_USER_DEF,
116                               LAYOUT_TOP | FRAME_SUNKEN | FRAME_THICK);
117         //myUsageProbabilityDial->setFormatString("%.2f");
118         //myUsageProbabilityDial->setIncrements(.1, .1, .1);
119         myUsageProbabilityDial->setIncrement(.1);
120         myUsageProbabilityDial->setRange(0, 1);
121         myUsageProbabilityDial->setValue(myObject->getUserProbability());
122     }
123     {
124         // off
125         FXHorizontalFrame* gf13 =
126             new FXHorizontalFrame(gp, LAYOUT_TOP | LAYOUT_LEFT, 0, 0, 0, 0, 10, 10, 5, 5);
127         new FXRadioButton(gf13, "Off", &myChosenTarget, FXDataTarget::ID_OPTION + 2,
128                           ICON_BEFORE_TEXT | LAYOUT_SIDE_TOP,
129                           0, 0, 0, 0,   2, 2, 0, 0);
130     }
131     myChosenValue = myObject->inUserMode()
132                     ? myObject->getUserProbability() > 0
133                     ? 1 : 2
134                     : 0;
135     new FXButton(f1, "Close", nullptr, this, MID_CLOSE,
136                  BUTTON_INITIAL | BUTTON_DEFAULT | FRAME_RAISED | FRAME_THICK | LAYOUT_TOP | LAYOUT_LEFT | LAYOUT_CENTER_X, 0, 0, 0, 0, 30, 30, 4, 4);
137 }
138 
139 
~GUIManip_TriggeredRerouter()140 GUITriggeredRerouter::GUIManip_TriggeredRerouter::~GUIManip_TriggeredRerouter() {}
141 
142 
143 long
onCmdClose(FXObject *,FXSelector,void *)144 GUITriggeredRerouter::GUIManip_TriggeredRerouter::onCmdClose(FXObject*, FXSelector, void*) {
145     destroy();
146     return 1;
147 }
148 
149 
150 long
onCmdUserDef(FXObject *,FXSelector,void *)151 GUITriggeredRerouter::GUIManip_TriggeredRerouter::onCmdUserDef(FXObject*, FXSelector, void*) {
152     myUsageProbability = (double)(myUsageProbabilityDial->getValue());
153     static_cast<GUITriggeredRerouter*>(myObject)->setUserUsageProbability(myUsageProbability);
154     static_cast<GUITriggeredRerouter*>(myObject)->setUserMode(true);
155     myParent->updateChildren();
156     return 1;
157 }
158 
159 
160 long
onUpdUserDef(FXObject * sender,FXSelector,void * ptr)161 GUITriggeredRerouter::GUIManip_TriggeredRerouter::onUpdUserDef(FXObject* sender, FXSelector, void* ptr) {
162     sender->handle(this,
163                    myChosenValue != 1 ? FXSEL(SEL_COMMAND, ID_DISABLE) : FXSEL(SEL_COMMAND, ID_ENABLE),
164                    ptr);
165     myParent->updateChildren();
166     return 1;
167 }
168 
169 
170 long
onCmdChangeOption(FXObject *,FXSelector,void *)171 GUITriggeredRerouter::GUIManip_TriggeredRerouter::onCmdChangeOption(FXObject*, FXSelector, void*) {
172     static_cast<GUITriggeredRerouter*>(myObject)->setUserUsageProbability(myUsageProbability);
173     switch (myChosenValue) {
174         case 0:
175             static_cast<GUITriggeredRerouter*>(myObject)->setUserMode(false);
176             break;
177         case 1:
178             static_cast<GUITriggeredRerouter*>(myObject)->setUserMode(true);
179             break;
180         case 2:
181             static_cast<GUITriggeredRerouter*>(myObject)->setUserUsageProbability(0);
182             static_cast<GUITriggeredRerouter*>(myObject)->setUserMode(true);
183             break;
184         default:
185             throw 1;
186     }
187     myParent->updateChildren();
188     return 1;
189 }
190 
191 
192 /* -------------------------------------------------------------------------
193  * GUITriggeredRerouter::GUITriggeredRerouterPopupMenu - methods
194  * ----------------------------------------------------------------------- */
GUITriggeredRerouterPopupMenu(GUIMainWindow & app,GUISUMOAbstractView & parent,GUIGlObject & o)195 GUITriggeredRerouter::GUITriggeredRerouterPopupMenu::GUITriggeredRerouterPopupMenu(
196     GUIMainWindow& app, GUISUMOAbstractView& parent,
197     GUIGlObject& o)
198     : GUIGLObjectPopupMenu(app, parent, o) {}
199 
200 
~GUITriggeredRerouterPopupMenu()201 GUITriggeredRerouter::GUITriggeredRerouterPopupMenu::~GUITriggeredRerouterPopupMenu() {}
202 
203 
204 long
onCmdOpenManip(FXObject *,FXSelector,void *)205 GUITriggeredRerouter::GUITriggeredRerouterPopupMenu::onCmdOpenManip(FXObject*,
206         FXSelector,
207         void*) {
208     static_cast<GUITriggeredRerouter*>(myObject)->openManipulator(
209         *myApplication, *myParent);
210     return 1;
211 }
212 
213 // -------------------------------------------------------------------------
214 // GUITriggeredRerouter - methods
215 // -------------------------------------------------------------------------
216 
GUITriggeredRerouter(const std::string & id,const MSEdgeVector & edges,double prob,const std::string & aXMLFilename,bool off,SUMOTime timeThreshold,const std::string & vTypes,SUMORTree & rtree)217 GUITriggeredRerouter::GUITriggeredRerouter(const std::string& id, const MSEdgeVector& edges, double prob,
218         const std::string& aXMLFilename, bool off, SUMOTime timeThreshold, const std::string& vTypes, SUMORTree& rtree) :
219     MSTriggeredRerouter(id, edges, prob, aXMLFilename, off, timeThreshold, vTypes),
220     GUIGlObject_AbstractAdd(GLO_REROUTER, id) {
221     // add visualisation objects for edges which trigger the rerouter
222     for (MSEdgeVector::const_iterator it = edges.begin(); it != edges.end(); ++it) {
223         myEdgeVisualizations.push_back(new GUITriggeredRerouterEdge(dynamic_cast<GUIEdge*>(*it), this, false));
224         rtree.addAdditionalGLObject(myEdgeVisualizations.back());
225         myBoundary.add(myEdgeVisualizations.back()->getCenteringBoundary());
226     }
227 }
228 
229 
~GUITriggeredRerouter()230 GUITriggeredRerouter::~GUITriggeredRerouter() {
231     for (std::vector<GUITriggeredRerouterEdge*>::iterator it = myEdgeVisualizations.begin(); it != myEdgeVisualizations.end(); ++it) {
232         delete *it;
233     }
234     myEdgeVisualizations.clear();
235 }
236 
237 
238 void
myEndElement(int element)239 GUITriggeredRerouter::myEndElement(int element) {
240     MSTriggeredRerouter::myEndElement(element);
241     if (element == SUMO_TAG_INTERVAL) {
242         // add visualisation objects for closed edges
243         const RerouteInterval& ri = myIntervals.back();
244         for (MSEdgeVector::const_iterator it = ri.closed.begin(); it != ri.closed.end(); ++it) {
245             myEdgeVisualizations.push_back(new GUITriggeredRerouterEdge(dynamic_cast<GUIEdge*>(*it), this, true));
246             dynamic_cast<GUINet*>(GUINet::getInstance())->getVisualisationSpeedUp().addAdditionalGLObject(myEdgeVisualizations.back());
247             myBoundary.add(myEdgeVisualizations.back()->getCenteringBoundary());
248         }
249     }
250 }
251 
252 
253 GUIGLObjectPopupMenu*
getPopUpMenu(GUIMainWindow & app,GUISUMOAbstractView & parent)254 GUITriggeredRerouter::getPopUpMenu(GUIMainWindow& app,
255                                    GUISUMOAbstractView& parent) {
256     GUIGLObjectPopupMenu* ret = new GUITriggeredRerouterPopupMenu(app, parent, *this);
257     buildPopupHeader(ret, app);
258     buildCenterPopupEntry(ret);
259     buildShowManipulatorPopupEntry(ret, false);
260     buildNameCopyPopupEntry(ret);
261     buildSelectionPopupEntry(ret);
262     buildPositionCopyEntry(ret, false);
263     return ret;
264 }
265 
266 
267 GUIParameterTableWindow*
getParameterWindow(GUIMainWindow &,GUISUMOAbstractView &)268 GUITriggeredRerouter::getParameterWindow(GUIMainWindow&,
269         GUISUMOAbstractView&) {
270     return nullptr;
271 }
272 
273 
274 void
drawGL(const GUIVisualizationSettings & s) const275 GUITriggeredRerouter::drawGL(const GUIVisualizationSettings& s) const {
276     UNUSED_PARAMETER(s);
277 }
278 
279 
280 Boundary
getCenteringBoundary() const281 GUITriggeredRerouter::getCenteringBoundary() const {
282     Boundary b(myBoundary);
283     b.grow(20);
284     return b;
285 }
286 
287 
288 
289 GUIManipulator*
openManipulator(GUIMainWindow & app,GUISUMOAbstractView &)290 GUITriggeredRerouter::openManipulator(GUIMainWindow& app,
291                                       GUISUMOAbstractView&) {
292     GUIManip_TriggeredRerouter* gui =
293         new GUIManip_TriggeredRerouter(app, getFullName(), *this, 0, 0);
294     gui->create();
295     gui->show();
296     return gui;
297 }
298 
299 
300 /* -------------------------------------------------------------------------
301  * GUITriggeredRerouterEdge - methods
302  * ----------------------------------------------------------------------- */
GUITriggeredRerouterEdge(GUIEdge * edge,GUITriggeredRerouter * parent,bool closed)303 GUITriggeredRerouter::GUITriggeredRerouterEdge::GUITriggeredRerouterEdge(GUIEdge* edge, GUITriggeredRerouter* parent, bool closed) :
304     GUIGlObject(GLO_REROUTER_EDGE, parent->getID() + ":" + edge->getID()),
305     myParent(parent),
306     myEdge(edge),
307     myAmClosedEdge(closed) {
308     const std::vector<MSLane*>& lanes = edge->getLanes();
309     myFGPositions.reserve(lanes.size());
310     myFGRotations.reserve(lanes.size());
311     for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
312         const PositionVector& v = (*i)->getShape();
313         const double pos = closed ? 3 : v.length() - (double) 6.;
314         myFGPositions.push_back((*i)->geometryPositionAtOffset(pos));
315         myFGRotations.push_back(-v.rotationDegreeAtOffset(pos));
316         myBoundary.add(myFGPositions.back());
317     }
318 }
319 
320 
~GUITriggeredRerouterEdge()321 GUITriggeredRerouter::GUITriggeredRerouterEdge::~GUITriggeredRerouterEdge() {}
322 
323 
324 GUIGLObjectPopupMenu*
getPopUpMenu(GUIMainWindow & app,GUISUMOAbstractView & parent)325 GUITriggeredRerouter::GUITriggeredRerouterEdge::getPopUpMenu(GUIMainWindow& app,
326         GUISUMOAbstractView& parent) {
327     return myParent->getPopUpMenu(app, parent);
328 }
329 
330 
331 GUIParameterTableWindow*
getParameterWindow(GUIMainWindow &,GUISUMOAbstractView &)332 GUITriggeredRerouter::GUITriggeredRerouterEdge::getParameterWindow(GUIMainWindow&,
333         GUISUMOAbstractView&) {
334     return nullptr;
335 }
336 
337 
338 void
drawGL(const GUIVisualizationSettings & s) const339 GUITriggeredRerouter::GUITriggeredRerouterEdge::drawGL(const GUIVisualizationSettings& s) const {
340     const double exaggeration = s.addSize.getExaggeration(s, this);
341     if (s.scale * exaggeration >= 3) {
342         glPushName(getGlID());
343         const double prob = myParent->getProbability();
344         if (myAmClosedEdge) {
345             // draw closing symbol onto all lanes
346             const RerouteInterval* const ri =
347                 myParent->getCurrentReroute(MSNet::getInstance()->getCurrentTimeStep());
348             if (ri != nullptr && prob > 0) {
349                 // draw only if the edge is closed at this time
350                 if (std::find(ri->closed.begin(), ri->closed.end(), myEdge) != ri->closed.end()) {
351                     const int noLanes = (int)myFGPositions.size();
352                     for (int j = 0; j < noLanes; ++j) {
353                         Position pos = myFGPositions[j];
354                         double rot = myFGRotations[j];
355                         glPushMatrix();
356                         glTranslated(pos.x(), pos.y(), 0);
357                         glRotated(rot, 0, 0, 1);
358                         glTranslated(0, -1.5, 0);
359                         int noPoints = 9;
360                         if (s.scale > 25) {
361                             noPoints = (int)(9.0 + s.scale / 10.0);
362                             if (noPoints > 36) {
363                                 noPoints = 36;
364                             }
365                         }
366                         glTranslated(0, 0, getType());
367                         //glScaled(exaggeration, exaggeration, 1);
368                         glColor3d(0.7, 0, 0);
369                         GLHelper::drawFilledCircle((double) 1.3, noPoints);
370                         glTranslated(0, 0, .1);
371                         glColor3d(1, 0, 0);
372                         GLHelper::drawFilledCircle((double) 1.3, noPoints, 0, prob * 360);
373                         glTranslated(0, 0, .1);
374                         glColor3d(1, 1, 1);
375                         glRotated(-90, 0, 0, 1);
376                         glBegin(GL_TRIANGLES);
377                         glVertex2d(0 - .3, -1.);
378                         glVertex2d(0 - .3, 1.);
379                         glVertex2d(0 + .3, 1.);
380                         glVertex2d(0 + .3, -1.);
381                         glVertex2d(0 - .3, -1.);
382                         glVertex2d(0 + .3, 1.);
383                         glEnd();
384                         glPopMatrix();
385                     }
386                 }
387             }
388 
389         } else {
390             // draw rerouter symbol onto all lanes
391             for (int i = 0; i < (int)myFGPositions.size(); ++i) {
392                 const Position& pos = myFGPositions[i];
393                 double rot = myFGRotations[i];
394                 glPushMatrix();
395                 glTranslated(pos.x(), pos.y(), 0);
396                 glRotated(rot, 0, 0, 1);
397                 glTranslated(0, 0, getType());
398                 glScaled(exaggeration, exaggeration, 1);
399                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
400 
401                 glBegin(GL_TRIANGLES);
402                 glColor3d(1, .8f, 0);
403                 // base
404                 glVertex2d(0 - 1.4, 0);
405                 glVertex2d(0 - 1.4, 6);
406                 glVertex2d(0 + 1.4, 6);
407                 glVertex2d(0 + 1.4, 0);
408                 glVertex2d(0 - 1.4, 0);
409                 glVertex2d(0 + 1.4, 6);
410                 glEnd();
411 
412                 // draw "U"
413                 GLHelper::drawText("U", Position(0, 2), .1, 3, RGBColor::BLACK, 180);
414 
415                 // draw Probability
416                 GLHelper::drawText((toString((int)(prob * 100)) + "%").c_str(), Position(0, 4), .1, 0.7, RGBColor::BLACK, 180);
417 
418                 glPopMatrix();
419             }
420         }
421         glPopName();
422     }
423 }
424 
425 
426 Boundary
getCenteringBoundary() const427 GUITriggeredRerouter::GUITriggeredRerouterEdge::getCenteringBoundary() const {
428     Boundary b(myBoundary);
429     b.grow(20);
430     return b;
431 }
432 
433 
434 /****************************************************************************/
435 
436