#include <config.h>
#include <cmath>
#include <vector>
#include <string>
#include <microsim/logging/CastingFunctionBinding.h>
#include <microsim/logging/FunctionBinding.h>
#include <microsim/MSLane.h>
#include <microsim/MSVehicleControl.h>
#include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
#include <microsim/devices/MSDevice_Vehroutes.h>
#include <utils/common/MsgHandler.h>
#include <utils/common/StringUtils.h>
#include <utils/vehicle/SUMOVehicleParameter.h>
#include <utils/geom/GeomHelper.h>
#include <utils/gui/images/GUITexturesHelper.h>
#include <utils/gui/windows/GUISUMOAbstractView.h>
#include <utils/gui/windows/GUIAppEnum.h>
#include <utils/gui/div/GUIParameterTableWindow.h>
#include <utils/gui/div/GUIGlobalSelection.h>
#include <utils/gui/div/GLHelper.h>
#include <utils/gui/div/GLObjectValuePassConnector.h>
#include <utils/geom/PositionVector.h>
#include <gui/GUIApplicationWindow.h>
#include <gui/GUIGlobals.h>
#include <utils/gui/globjects/GLIncludes.h>
#include <utils/gui/div/GUIDesigns.h>
#include "GUIContainer.h"
#include "GUINet.h"
#include "GUIEdge.h"
FXDEFMAP(GUIContainer::GUIContainerPopupMenu) GUIContainerPopupMenuMap[] = {
FXMAPFUNC(SEL_COMMAND, MID_START_TRACK, GUIContainer::GUIContainerPopupMenu::onCmdStartTrack),
FXMAPFUNC(SEL_COMMAND, MID_STOP_TRACK, GUIContainer::GUIContainerPopupMenu::onCmdStopTrack),
FXMAPFUNC(SEL_COMMAND, MID_SHOWPLAN, GUIContainer::GUIContainerPopupMenu::onCmdShowPlan),
};
FXIMPLEMENT(GUIContainer::GUIContainerPopupMenu, GUIGLObjectPopupMenu, GUIContainerPopupMenuMap, ARRAYNUMBER(GUIContainerPopupMenuMap))
#define WATER_WAY_OFFSET 6.0
GUIContainer::GUIContainerPopupMenu::GUIContainerPopupMenu(
GUIMainWindow& app, GUISUMOAbstractView& parent, GUIGlObject* o) :
GUIGLObjectPopupMenu(app, parent, o) {
}
GUIContainer::GUIContainerPopupMenu::~GUIContainerPopupMenu() {}
long
GUIContainer::GUIContainerPopupMenu::onCmdShowPlan(FXObject*, FXSelector, void*) {
GUIContainer* p = dynamic_cast<GUIContainer*>(myObject);
if (p == nullptr) {
return 1;
}
GUIParameterTableWindow* ret = new GUIParameterTableWindow(*myApplication, *p);
for (int stage = 1; stage < p->getNumStages(); stage++) {
ret->mkItem(toString(stage).c_str(), false, p->getStageSummary(stage));
}
Parameterised dummy;
ret->closeBuilding(&dummy);
return 1;
}
long
GUIContainer::GUIContainerPopupMenu::onCmdStartTrack(FXObject*, FXSelector, void*) {
assert(myObject->getType() == GLO_PERSON);
if (myParent->getTrackedID() != static_cast<GUIContainer*>(myObject)->getGlID()) {
myParent->startTrack(static_cast<GUIContainer*>(myObject)->getGlID());
}
return 1;
}
long
GUIContainer::GUIContainerPopupMenu::onCmdStopTrack(FXObject*, FXSelector, void*) {
assert(myObject->getType() == GLO_PERSON);
myParent->stopTrack();
return 1;
}
GUIContainer::GUIContainer(const SUMOVehicleParameter* pars, MSVehicleType* vtype, MSTransportable::MSTransportablePlan* plan) :
MSTransportable(pars, vtype, plan, false),
GUIGlObject(GLO_CONTAINER, pars->id, GUIIconSubSys::getIcon(GUIIcon::CONTAINER)) {
}
GUIContainer::~GUIContainer() {
}
GUIGLObjectPopupMenu*
GUIContainer::getPopUpMenu(GUIMainWindow& app,
GUISUMOAbstractView& parent) {
GUIGLObjectPopupMenu* ret = new GUIContainerPopupMenu(app, parent, this);
buildPopupHeader(ret, app);
buildCenterPopupEntry(ret);
buildNameCopyPopupEntry(ret);
buildSelectionPopupEntry(ret);
new FXMenuSeparator(ret);
if (parent.getTrackedID() != getGlID()) {
GUIDesigns::buildFXMenuCommand(ret, "Start Tracking", nullptr, ret, MID_START_TRACK);
} else {
GUIDesigns::buildFXMenuCommand(ret, "Stop Tracking", nullptr, ret, MID_STOP_TRACK);
}
buildShowParamsPopupEntry(ret);
buildShowTypeParamsPopupEntry(ret);
GUIDesigns::buildFXMenuCommand(ret, "Show Plan", GUIIconSubSys::getIcon(GUIIcon::APP_TABLE), ret, MID_SHOWPLAN);
new FXMenuSeparator(ret);
buildPositionCopyEntry(ret, app);
return ret;
}
GUIParameterTableWindow*
GUIContainer::getParameterWindow(GUIMainWindow& app,
GUISUMOAbstractView&) {
GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
ret->mkItem(TL("stage"), false, getCurrentStageDescription());
ret->mkItem(TL("stage index"), false, toString(getCurrentStageIndex()) + " of " + toString(getNumStages() - 1));
ret->mkItem(TL("start edge [id]"), false, getFromEdge()->getID());
ret->mkItem(TL("dest edge [id]"), false, getDestination()->getID());
ret->mkItem(TL("arrivalPos [m]"), false, toString(getCurrentStage()->getArrivalPos()));
ret->mkItem(TL("edge [id]"), false, getEdge()->getID());
ret->mkItem(TL("position [m]"), true, new FunctionBinding<GUIContainer, double>(this, &GUIContainer::getEdgePos));
ret->mkItem(TL("speed [m/s]"), true, new FunctionBinding<GUIContainer, double>(this, &GUIContainer::getSpeed));
ret->mkItem(TL("speed factor"), false, getChosenSpeedFactor());
ret->mkItem(TL("angle [degree]"), true, new FunctionBinding<GUIContainer, double>(this, &GUIContainer::getAngle));
ret->mkItem(TL("waiting time [s]"), true, new FunctionBinding<GUIContainer, double>(this, &GUIContainer::getWaitingSeconds));
ret->mkItem(TL("desired depart [s]"), false, time2string(getParameter().depart));
ret->closeBuilding(&getParameter());
return ret;
}
GUIParameterTableWindow*
GUIContainer::getTypeParameterWindow(GUIMainWindow& app, GUISUMOAbstractView&) {
GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this, "vType:" + myVType->getID());
ret->mkItem(TL("length"), false, myVType->getLength());
ret->mkItem(TL("width"), false, myVType->getWidth());
ret->mkItem(TL("height"), false, myVType->getHeight());
ret->mkItem(TL("minGap"), false, myVType->getMinGap());
ret->mkItem(TL("mass [kg]"), false, myVType->getMass());
ret->mkItem(TL("maximum speed [m/s]"), false, myVType->getMaxSpeed());
ret->closeBuilding(&(myVType->getParameter()));
return ret;
}
double
GUIContainer::getExaggeration(const GUIVisualizationSettings& s) const {
return s.containerSize.getExaggeration(s, this);
}
Boundary
GUIContainer::getCenteringBoundary() const {
Boundary b;
b.add(getPosition());
b.grow(20);
return b;
}
void
GUIContainer::drawGL(const GUIVisualizationSettings& s) const {
GLHelper::pushName(getGlID());
GLHelper::pushMatrix();
Position p1 = getPosition();
double angle = getAngle();
if (getCurrentStageType() == MSStageType::DRIVING && !isWaiting4Vehicle()) {
p1 = myPositionInVehicle.pos;
angle = myPositionInVehicle.angle;
}
glTranslated(p1.x(), p1.y(), getType());
glRotated(RAD2DEG(angle), 0, 0, 1);
setColor(s);
const double upscale = getExaggeration(s);
glScaled(upscale, upscale, 1);
switch (s.containerQuality) {
case 0:
case 1:
case 2:
drawAction_drawAsPoly(s);
break;
case 3:
default:
drawAction_drawAsImage(s);
break;
}
GLHelper::popMatrix();
drawName(p1, s.scale, s.containerName, s.angle);
GLHelper::popName();
}
void
GUIContainer::drawGLAdditional(GUISUMOAbstractView* const , const GUIVisualizationSettings& ) const {
GLHelper::pushName(getGlID());
GLHelper::pushMatrix();
GLHelper::popMatrix();
GLHelper::popName();
}
void
GUIContainer::setColor(const GUIVisualizationSettings& s) const {
const GUIColorer& c = s.containerColorer;
if (!setFunctionalColor(c.getActive())) {
GLHelper::setColor(c.getScheme().getColor(getColorValue(s, c.getActive())));
}
}
bool
GUIContainer::setFunctionalColor(int activeScheme) const {
switch (activeScheme) {
case 0: {
if (getParameter().wasSet(VEHPARS_COLOR_SET)) {
GLHelper::setColor(getParameter().color);
return true;
}
if (getVehicleType().wasSet(VTYPEPARS_COLOR_SET)) {
GLHelper::setColor(getVehicleType().getColor());
return true;
}
return false;
}
case 2: {
if (getParameter().wasSet(VEHPARS_COLOR_SET)) {
GLHelper::setColor(getParameter().color);
return true;
}
return false;
}
case 3: {
if (getVehicleType().wasSet(VTYPEPARS_COLOR_SET)) {
GLHelper::setColor(getVehicleType().getColor());
return true;
}
return false;
}
case 8: {
double hue = GeomHelper::naviDegree(getAngle());
GLHelper::setColor(RGBColor::fromHSV(hue, 1., 1.));
return true;
}
case 9: {
const double hue = (double)((long long int)this % 360);
const double sat = (double)(((long long int)this / 360) % 67) / 100. + 0.33;
GLHelper::setColor(RGBColor::fromHSV(hue, sat, 1.));
return true;
}
default:
return false;
}
}
double
GUIContainer::getColorValue(const GUIVisualizationSettings& , int activeScheme) const {
switch (activeScheme) {
case 4:
return getSpeed();
case 5:
if (isWaiting4Vehicle()) {
return 5;
} else {
return (double)getCurrentStageType();
}
case 6:
return getWaitingSeconds();
case 7:
return gSelected.isSelected(GLO_CONTAINER, getGlID());
}
return 0;
}
double
GUIContainer::getEdgePos() const {
FXMutexLock locker(myLock);
return MSTransportable::getEdgePos();
}
int
GUIContainer::getDirection() const {
FXMutexLock locker(myLock);
return MSTransportable::getDirection();
}
Position
GUIContainer::getPosition() const {
FXMutexLock locker(myLock);
if (getCurrentStageType() == MSStageType::WAITING && getEdge()->getPermissions() == SVC_SHIP) {
MSLane* lane = getEdge()->getLanes().front();
PositionVector laneShape = lane->getShape();
return laneShape.positionAtOffset2D(getEdgePos(), WATER_WAY_OFFSET);
}
return MSTransportable::getPosition();
}
double
GUIContainer::getAngle() const {
FXMutexLock locker(myLock);
return MSTransportable::getAngle();
}
double
GUIContainer::getWaitingSeconds() const {
FXMutexLock locker(myLock);
return MSTransportable::getWaitingSeconds();
}
double
GUIContainer::getSpeed() const {
FXMutexLock locker(myLock);
return MSTransportable::getSpeed();
}
void
GUIContainer::drawAction_drawAsPoly(const GUIVisualizationSettings& ) const {
glScaled(getVehicleType().getLength(), getVehicleType().getWidth(), 1);
glBegin(GL_QUADS);
glVertex2d(0, 0.5);
glVertex2d(0, -0.5);
glVertex2d(-1, -0.5);
glVertex2d(-1, 0.5);
glEnd();
GLHelper::setColor(GLHelper::getColor().changedBrightness(-30));
glTranslated(0, 0, .045);
glBegin(GL_QUADS);
glVertex2d(-0.1, 0.4);
glVertex2d(-0.1, -0.4);
glVertex2d(-0.9, -0.4);
glVertex2d(-0.9, 0.4);
glEnd();
}
void
GUIContainer::drawAction_drawAsImage(const GUIVisualizationSettings& s) const {
const std::string& file = getVehicleType().getImgFile();
if (file != "") {
int textureID = GUITexturesHelper::getTextureID(file);
if (textureID > 0) {
const double exaggeration = s.personSize.getExaggeration(s, this);
const double halfLength = getVehicleType().getLength() / 2.0 * exaggeration;
const double halfWidth = getVehicleType().getWidth() / 2.0 * exaggeration;
GUITexturesHelper::drawTexturedBox(textureID, -halfWidth, -halfLength, halfWidth, halfLength);
}
} else {
drawAction_drawAsPoly(s);
}
}
bool
GUIContainer::isSelected() const {
return gSelected.isSelected(GLO_CONTAINER, getGlID());
}