#include <config.h>
#include <string>
#include <utils/common/MsgHandler.h>
#include <utils/geom/PositionVector.h>
#include <utils/geom/Boundary.h>
#include <utils/gui/div/GLHelper.h>
#include <utils/common/ToString.h>
#include <utils/common/Command.h>
#include <microsim/MSNet.h>
#include <microsim/MSLane.h>
#include <microsim/MSEdge.h>
#include <microsim/MSRoute.h>
#include <microsim/MSVehicle.h>
#include <guisim/GUINet.h>
#include <guisim/GUIEdge.h>
#include "GUITriggeredRerouter.h"
#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
#include <utils/gui/windows/GUIAppEnum.h>
#include <gui/GUIGlobals.h>
#include <utils/gui/div/GUIParameterTableWindow.h>
#include <gui/GUIApplicationWindow.h>
#include <microsim/logging/FunctionBinding.h>
#include <utils/gui/div/GUIGlobalSelection.h>
#include <utils/gui/globjects/GLIncludes.h>
#include <utils/gui/globjects/GLIncludes.h>
#include <utils/gui/div/GUIDesigns.h>
FXDEFMAP(GUITriggeredRerouter::GUITriggeredRerouterPopupMenu)
GUITriggeredRerouterPopupMenuMap[] = {
FXMAPFUNC(SEL_COMMAND, MID_MANIP, GUITriggeredRerouter::GUITriggeredRerouterPopupMenu::onCmdOpenManip),
};
FXIMPLEMENT(GUITriggeredRerouter::GUITriggeredRerouterPopupMenu, GUIGLObjectPopupMenu, GUITriggeredRerouterPopupMenuMap, ARRAYNUMBER(GUITriggeredRerouterPopupMenuMap))
FXDEFMAP(GUITriggeredRerouter::GUIManip_TriggeredRerouter) GUIManip_TriggeredRerouterMap[] = {
FXMAPFUNC(SEL_COMMAND, GUITriggeredRerouter::GUIManip_TriggeredRerouter::MID_USER_DEF, GUITriggeredRerouter::GUIManip_TriggeredRerouter::onCmdUserDef),
FXMAPFUNC(SEL_UPDATE, GUITriggeredRerouter::GUIManip_TriggeredRerouter::MID_USER_DEF, GUITriggeredRerouter::GUIManip_TriggeredRerouter::onUpdUserDef),
FXMAPFUNC(SEL_COMMAND, GUITriggeredRerouter::GUIManip_TriggeredRerouter::MID_OPTION, GUITriggeredRerouter::GUIManip_TriggeredRerouter::onCmdChangeOption),
FXMAPFUNC(SEL_COMMAND, GUITriggeredRerouter::GUIManip_TriggeredRerouter::MID_SHIFT_PROBS, GUITriggeredRerouter::GUIManip_TriggeredRerouter::onCmdShiftProbs),
FXMAPFUNC(SEL_COMMAND, GUITriggeredRerouter::GUIManip_TriggeredRerouter::MID_CLOSE, GUITriggeredRerouter::GUIManip_TriggeredRerouter::onCmdClose),
};
FXIMPLEMENT(GUITriggeredRerouter::GUIManip_TriggeredRerouter, GUIManipulator, GUIManip_TriggeredRerouterMap, ARRAYNUMBER(GUIManip_TriggeredRerouterMap))
GUITriggeredRerouter::GUIManip_TriggeredRerouter::GUIManip_TriggeredRerouter(
GUIMainWindow& app, const std::string& name, GUITriggeredRerouter& o) :
GUIManipulator(app, name, 0, 0), myParent(&app),
myChosenValue(0), myChosenTarget(myChosenValue, nullptr, MID_OPTION),
myUsageProbability(o.getProbability()), myUsageProbabilityTarget(myUsageProbability),
myObject(&o) {
myChosenTarget.setTarget(this);
FXVerticalFrame* f1 =
new FXVerticalFrame(this, LAYOUT_FILL_X | LAYOUT_FILL_Y, 0, 0, 0, 0, 0, 0, 0, 0);
FXGroupBox* gp = new FXGroupBox(f1, "Change Trigger Probability",
GROUPBOX_TITLE_LEFT | FRAME_SUNKEN | FRAME_RIDGE,
0, 0, 0, 0, 4, 4, 1, 1, 2, 0);
{
FXHorizontalFrame* gf1 =
new FXHorizontalFrame(gp, LAYOUT_TOP | LAYOUT_LEFT, 0, 0, 0, 0, 10, 10, 5, 5);
new FXRadioButton(gf1, "Default", &myChosenTarget, FXDataTarget::ID_OPTION + 0,
ICON_BEFORE_TEXT | LAYOUT_SIDE_TOP,
0, 0, 0, 0, 2, 2, 0, 0);
}
{
FXHorizontalFrame* gf12 =
new FXHorizontalFrame(gp, LAYOUT_TOP | LAYOUT_LEFT, 0, 0, 0, 0, 10, 10, 5, 5);
new FXRadioButton(gf12, "User Given: ", &myChosenTarget, FXDataTarget::ID_OPTION + 1,
ICON_BEFORE_TEXT | LAYOUT_SIDE_TOP | LAYOUT_CENTER_Y,
0, 0, 0, 0, 2, 2, 0, 0);
myUsageProbabilityDial =
new FXRealSpinner(gf12, 10, this, MID_USER_DEF,
LAYOUT_TOP | FRAME_SUNKEN | FRAME_THICK);
myUsageProbabilityDial->setIncrement(.1);
myUsageProbabilityDial->setRange(0, 1);
myUsageProbabilityDial->setValue(myObject->getUserProbability());
}
{
FXHorizontalFrame* gf13 =
new FXHorizontalFrame(gp, LAYOUT_TOP | LAYOUT_LEFT, 0, 0, 0, 0, 10, 10, 5, 5);
new FXRadioButton(gf13, "Off", &myChosenTarget, FXDataTarget::ID_OPTION + 2,
ICON_BEFORE_TEXT | LAYOUT_SIDE_TOP,
0, 0, 0, 0, 2, 2, 0, 0);
}
myChosenValue = myObject->inUserMode()
? myObject->getUserProbability() > 0
? 1 : 2
: 0;
FXGroupBox* gp2 = new FXGroupBox(f1, "Change Route Probability",
GROUPBOX_TITLE_LEFT | FRAME_SUNKEN | FRAME_RIDGE,
0, 0, 0, 0, 4, 4, 1, 1, 2, 0);
GUIDesigns::buildFXButton(gp2, "Shift", "", "", nullptr, this, MID_SHIFT_PROBS,
BUTTON_INITIAL | BUTTON_DEFAULT | FRAME_RAISED | FRAME_THICK | LAYOUT_TOP | LAYOUT_LEFT | LAYOUT_CENTER_X, 0, 0, 0, 0, 30, 30, 4, 4);
GUIDesigns::buildFXButton(f1, "Close", "", "", nullptr, this, MID_CLOSE,
BUTTON_INITIAL | BUTTON_DEFAULT | FRAME_RAISED | FRAME_THICK | LAYOUT_TOP | LAYOUT_LEFT | LAYOUT_CENTER_X, 0, 0, 0, 0, 30, 30, 4, 4);
}
GUITriggeredRerouter::GUIManip_TriggeredRerouter::~GUIManip_TriggeredRerouter() {}
long
GUITriggeredRerouter::GUIManip_TriggeredRerouter::onCmdClose(FXObject*, FXSelector, void*) {
destroy();
return 1;
}
long
GUITriggeredRerouter::GUIManip_TriggeredRerouter::onCmdUserDef(FXObject*, FXSelector, void*) {
myUsageProbability = (double)(myUsageProbabilityDial->getValue());
static_cast<GUITriggeredRerouter*>(myObject)->setUserUsageProbability(myUsageProbability);
static_cast<GUITriggeredRerouter*>(myObject)->setUserMode(true);
myParent->updateChildren();
return 1;
}
long
GUITriggeredRerouter::GUIManip_TriggeredRerouter::onUpdUserDef(FXObject* sender, FXSelector, void* ptr) {
sender->handle(this,
myChosenValue != 1 ? FXSEL(SEL_COMMAND, ID_DISABLE) : FXSEL(SEL_COMMAND, ID_ENABLE),
ptr);
myParent->updateChildren();
return 1;
}
long
GUITriggeredRerouter::GUIManip_TriggeredRerouter::onCmdChangeOption(FXObject*, FXSelector, void*) {
static_cast<GUITriggeredRerouter*>(myObject)->setUserUsageProbability(myUsageProbability);
switch (myChosenValue) {
case 0:
static_cast<GUITriggeredRerouter*>(myObject)->setUserMode(false);
break;
case 1:
static_cast<GUITriggeredRerouter*>(myObject)->setUserMode(true);
break;
case 2:
static_cast<GUITriggeredRerouter*>(myObject)->setUserUsageProbability(0);
static_cast<GUITriggeredRerouter*>(myObject)->setUserMode(true);
break;
default:
throw 1;
}
myParent->updateChildren();
return 1;
}
long
GUITriggeredRerouter::GUIManip_TriggeredRerouter::onCmdShiftProbs(FXObject*, FXSelector, void*) {
static_cast<GUITriggeredRerouter*>(myObject)->shiftProbs();
myParent->updateChildren();
return 1;
}
GUITriggeredRerouter::GUITriggeredRerouterPopupMenu::GUITriggeredRerouterPopupMenu(
GUIMainWindow& app, GUISUMOAbstractView& parent, GUIGlObject* o) :
GUIGLObjectPopupMenu(app, parent, o) {}
GUITriggeredRerouter::GUITriggeredRerouterPopupMenu::~GUITriggeredRerouterPopupMenu() {}
long
GUITriggeredRerouter::GUITriggeredRerouterPopupMenu::onCmdOpenManip(FXObject*,
FXSelector,
void*) {
static_cast<GUITriggeredRerouter*>(myObject)->openManipulator(
*myApplication, *myParent);
return 1;
}
GUITriggeredRerouter::GUITriggeredRerouter(const std::string& id, const MSEdgeVector& edges, double prob,
bool off, bool optional, SUMOTime timeThreshold, const std::string& vTypes, const Position& pos, const double radius, SUMORTree& rtree) :
MSTriggeredRerouter(id, edges, prob, off, optional, timeThreshold, vTypes, pos, radius),
GUIGlObject_AbstractAdd(GLO_REROUTER, id, GUIIconSubSys::getIcon(GUIIcon::REROUTER)),
myShiftProbDistIndex(0) {
for (MSEdgeVector::const_iterator it = edges.begin(); it != edges.end(); ++it) {
myEdgeVisualizations.push_back(new GUITriggeredRerouterEdge(dynamic_cast<GUIEdge*>(*it), this, REROUTER_TRIGGER_EDGE, -1, pos, radius));
rtree.addAdditionalGLObject(myEdgeVisualizations.back());
myBoundary.add(myEdgeVisualizations.back()->getCenteringBoundary());
if (pos != Position::INVALID) {
break;
}
}
}
GUITriggeredRerouter::~GUITriggeredRerouter() {
for (std::vector<GUITriggeredRerouterEdge*>::iterator it = myEdgeVisualizations.begin(); it != myEdgeVisualizations.end(); ++it) {
delete *it;
}
myEdgeVisualizations.clear();
}
void
GUITriggeredRerouter::myEndElement(int element) {
MSTriggeredRerouter::myEndElement(element);
if (element == SUMO_TAG_INTERVAL) {
const RerouteInterval& ri = myIntervals.back();
for (auto item : ri.getClosed()) {
const GUIEdge* edge = dynamic_cast<const GUIEdge*>(item.first);
myEdgeVisualizations.push_back(new GUITriggeredRerouterEdge(const_cast<GUIEdge*>(edge), this, REROUTER_CLOSED_EDGE));
dynamic_cast<GUINet*>(GUINet::getInstance())->getVisualisationSpeedUp().addAdditionalGLObject(myEdgeVisualizations.back());
myBoundary.add(myEdgeVisualizations.back()->getCenteringBoundary());
}
if (ri.routeProbs.getProbs().size() > 1) {
ConstMSRoutePtr route0 = ri.routeProbs.getVals()[0];
const MSEdge* lastEdge = nullptr;
int nextIndex = 0;
for (int i = 0; i < (int)route0->getEdges().size(); i++) {
const MSEdge* cand = route0->getEdges()[i];
for (ConstMSRoutePtr route : ri.routeProbs.getVals()) {
const MSEdge* nextEdge = i < (int)route->getEdges().size() ? route->getEdges()[i] : nullptr;
if (nextEdge != cand) {
cand = nullptr;
}
}
if (cand != nullptr) {
lastEdge = cand;
} else {
nextIndex = i;
break;
}
}
if (lastEdge != nullptr) {
double maxProb = ri.routeProbs.getProbs()[myShiftProbDistIndex];
for (int i = 0; i < (int)ri.routeProbs.getVals().size(); i++) {
const ConstMSEdgeVector& edges = ri.routeProbs.getVals()[i]->getEdges();
if (nextIndex < (int)edges.size()) {
GUIEdge* edge = dynamic_cast<GUIEdge*>(const_cast<MSEdge*>(edges[nextIndex]));
myEdgeVisualizations.push_back(new GUITriggeredRerouterEdge(edge, this, REROUTER_SWITCH_EDGE, i));
dynamic_cast<GUINet*>(GUINet::getInstance())->getVisualisationSpeedUp().addAdditionalGLObject(myEdgeVisualizations.back());
myBoundary.add(myEdgeVisualizations.back()->getCenteringBoundary());
}
double prob = ri.routeProbs.getProbs()[i];
if (prob > maxProb) {
maxProb = prob;
myShiftProbDistIndex = i;
}
}
}
}
}
}
GUIGLObjectPopupMenu*
GUITriggeredRerouter::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
GUIGLObjectPopupMenu* ret = new GUITriggeredRerouterPopupMenu(app, parent, this);
buildPopupHeader(ret, app);
buildCenterPopupEntry(ret);
buildShowManipulatorPopupEntry(ret, false);
buildNameCopyPopupEntry(ret);
buildSelectionPopupEntry(ret);
buildPositionCopyEntry(ret, app);
return ret;
}
GUIParameterTableWindow*
GUITriggeredRerouter::getParameterWindow(GUIMainWindow&,
GUISUMOAbstractView&) {
return nullptr;
}
void
GUITriggeredRerouter::drawGL(const GUIVisualizationSettings& s) const {
UNUSED_PARAMETER(s);
}
Boundary
GUITriggeredRerouter::getCenteringBoundary() const {
Boundary b(myBoundary);
b.grow(20);
return b;
}
double
GUITriggeredRerouter::getExaggeration(const GUIVisualizationSettings& s) const {
return s.addSize.getExaggeration(s, this);
}
GUIManipulator*
GUITriggeredRerouter::openManipulator(GUIMainWindow& app,
GUISUMOAbstractView&) {
GUIManip_TriggeredRerouter* gui = new GUIManip_TriggeredRerouter(app, getFullName(), *this);
gui->create();
gui->show(PLACEMENT_SCREEN);
return gui;
}
void
GUITriggeredRerouter::shiftProbs() {
const RerouteInterval* const ri = getCurrentReroute(MSNet::getInstance()->getCurrentTimeStep());
if (ri != nullptr && ri->routeProbs.getProbs().size() > 1) {
auto& rp = const_cast<RandomDistributor<ConstMSRoutePtr>&>(ri->routeProbs);
double prob = rp.getProbs()[myShiftProbDistIndex];
rp.add(rp.getVals()[myShiftProbDistIndex], -prob);
myShiftProbDistIndex = (myShiftProbDistIndex + 1) % rp.getProbs().size();
rp.add(rp.getVals()[myShiftProbDistIndex], prob);
for (auto rrEdge : myEdgeVisualizations) {
if (rrEdge->getRerouterEdgeType() == REROUTER_TRIGGER_EDGE) {
if (!MSGlobals::gUseMesoSim) {
for (MSLane* lane : rrEdge->getEdge()->getLanes()) {
for (const MSVehicle* veh : lane->getVehiclesSecure()) {
const_cast<MSVehicle*>(veh)->addReminder(this);
}
lane->releaseVehicles();
}
}
}
}
}
}
GUITriggeredRerouter::GUITriggeredRerouterEdge::GUITriggeredRerouterEdge(GUIEdge* edge, GUITriggeredRerouter* parent, RerouterEdgeType edgeType, int distIndex,
const Position& pos, const double radius) :
GUIGlObject(GLO_REROUTER_EDGE, parent->getID() + ":" + edge->getID(), GUIIconSubSys::getIcon(GUIIcon::REROUTER)),
myParent(parent),
myEdge(edge),
myEdgeType(edgeType),
myDistIndex(distIndex) {
UNUSED_PARAMETER(radius);
const std::vector<MSLane*>& lanes = edge->getLanes();
if (pos == Position::INVALID) {
for (const MSLane* lane : lanes) {
if ((lane->getPermissions() & ~SVC_PEDESTRIAN) == 0) {
continue;
}
const PositionVector& v = lane->getShape();
double lanePos;
double centerPos;
switch (edgeType) {
case REROUTER_TRIGGER_EDGE:
lanePos = MAX2(0.0, v.length() - 10);
centerPos = MIN2(lanePos + 3, v.length());
break;
case REROUTER_SWITCH_EDGE:
lanePos = 0;
centerPos = lanePos;
break;
default:
lanePos = MIN2(v.length(), 3.0);
centerPos = MIN2(lanePos + 3, v.length());
}
myFGPositions.push_back(v.positionAtOffset(lanePos));
myFGRotations.push_back(-v.rotationDegreeAtOffset(lanePos));
myBoundary.add(v.positionAtOffset(centerPos));
myHalfWidths.push_back(lane->getWidth() * 0.5 * 0.875);
}
} else {
myFGPositions.push_back(pos);
const PositionVector& v = lanes.front()->getShape();
myFGRotations.push_back(-v.rotationDegreeAtOffset(lanes.front()->getLength()));
myBoundary.add(myFGPositions.back());
myHalfWidths.push_back(SUMO_const_halfLaneWidth * 0.875);
}
}
GUITriggeredRerouter::GUITriggeredRerouterEdge::~GUITriggeredRerouterEdge() {}
GUIGLObjectPopupMenu*
GUITriggeredRerouter::GUITriggeredRerouterEdge::getPopUpMenu(GUIMainWindow& app,
GUISUMOAbstractView& parent) {
return myParent->getPopUpMenu(app, parent);
}
GUIParameterTableWindow*
GUITriggeredRerouter::GUITriggeredRerouterEdge::getParameterWindow(GUIMainWindow&,
GUISUMOAbstractView&) {
return nullptr;
}
void
GUITriggeredRerouter::GUITriggeredRerouterEdge::drawGL(const GUIVisualizationSettings& s) const {
const double exaggeration = getExaggeration(s);
if (s.scale * exaggeration >= 3) {
GLHelper::pushName(getGlID());
const double prob = myParent->getProbability();
if (myEdgeType == REROUTER_CLOSED_EDGE) {
const RerouteInterval* const ri =
myParent->getCurrentReroute(MSNet::getInstance()->getCurrentTimeStep());
if (ri != nullptr && prob > 0) {
const auto& closedEdges = ri->getClosed();
if (closedEdges.find(myEdge) != closedEdges.end()) {
const int noLanes = (int)myFGPositions.size();
for (int j = 0; j < noLanes; ++j) {
Position pos = myFGPositions[j];
double rot = myFGRotations[j];
GLHelper::pushMatrix();
glTranslated(pos.x(), pos.y(), 0);
glRotated(rot, 0, 0, 1);
glTranslated(0, -1.5, 0);
int noPoints = 9;
if (s.scale > 25) {
noPoints = (int)(9.0 + s.scale / 10.0);
if (noPoints > 36) {
noPoints = 36;
}
}
glTranslated(0, 0, getType());
glColor3d(0.7, 0, 0);
GLHelper::drawFilledCircle((double) 1.3, noPoints);
glTranslated(0, 0, .1);
glColor3d(1, 0, 0);
GLHelper::drawFilledCircle((double) 1.3, noPoints, 0, prob * 360);
glTranslated(0, 0, .1);
glColor3d(1, 1, 1);
glRotated(-90, 0, 0, 1);
glBegin(GL_TRIANGLES);
glVertex2d(0 - .3, -1.);
glVertex2d(0 - .3, 1.);
glVertex2d(0 + .3, 1.);
glVertex2d(0 + .3, -1.);
glVertex2d(0 - .3, -1.);
glVertex2d(0 + .3, 1.);
glEnd();
GLHelper::popMatrix();
}
}
}
} else if (myEdgeType == REROUTER_TRIGGER_EDGE) {
for (int i = 0; i < (int)myFGPositions.size(); ++i) {
const Position& pos = myFGPositions[i];
double rot = myFGRotations[i];
const double w = myHalfWidths[i];
GLHelper::pushMatrix();
glTranslated(pos.x(), pos.y(), 0);
glRotated(rot, 0, 0, 1);
glTranslated(0, -6, 0);
glTranslated(0, 0, getType());
glScaled(exaggeration, exaggeration, 1);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_TRIANGLES);
glColor3d(1, .8f, 0);
glVertex2d(0 - w, 0);
glVertex2d(0 - w, 6);
glVertex2d(0 + w, 6);
glVertex2d(0 + w, 0);
glVertex2d(0 - w, 0);
glVertex2d(0 + w, 6);
glEnd();
GLHelper::drawText("U", Position(0, 2), .1, 3 * (w / 1.4), RGBColor::BLACK, 180);
GLHelper::drawText((toString((int)(prob * 100)) + "%").c_str(), Position(0, 4), .1, 0.7, RGBColor::BLACK, 180);
GLHelper::popMatrix();
}
} else if (myEdgeType == REROUTER_SWITCH_EDGE) {
const RerouteInterval* const ri =
myParent->getCurrentReroute(MSNet::getInstance()->getCurrentTimeStep());
const double routeProb = ri != nullptr && prob > 0 ? ri->routeProbs.getProbs()[myDistIndex] / ri->routeProbs.getOverallProb() : 0;
if (routeProb > 0) {
for (int i = 0; i < (int)myFGPositions.size(); ++i) {
const Position& pos = myFGPositions[i];
double rot = myFGRotations[i];
const double w = myHalfWidths[i];
GLHelper::pushMatrix();
glTranslated(pos.x(), pos.y(), 0);
glRotated(rot, 0, 0, 1);
glTranslated(0, 0, getType());
glScaled(exaggeration, exaggeration, 1);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_TRIANGLES);
glColor3d(0, 1, 1);
glVertex2d(0 - 0.0, 0);
glVertex2d(0 - w, 6);
glVertex2d(0 + w, 6);
glVertex2d(0 + 0.0, 0);
glVertex2d(0 + w, 6);
glEnd();
GLHelper::drawText("P", Position(0, 3.5), .1, 2, RGBColor::BLACK, 180);
GLHelper::drawText((toString((int)(routeProb * 100)) + "%").c_str(), Position(0, 5), .1, 0.7, RGBColor::BLACK, 180);
GLHelper::popMatrix();
}
}
}
GLHelper::popName();
}
}
double
GUITriggeredRerouter::GUITriggeredRerouterEdge::getExaggeration(const GUIVisualizationSettings& s) const {
return s.addSize.getExaggeration(s, this);
}
Boundary
GUITriggeredRerouter::GUITriggeredRerouterEdge::getCenteringBoundary() const {
Boundary b(myBoundary);
b.grow(20);
return b;
}
void
GUITriggeredRerouter::GUITriggeredRerouterEdge::onLeftBtnPress(void* ) {
myParent->shiftProbs();
}