#include <config.h>
#include <utils/common/MsgHandler.h>
#include <utils/gui/globjects/GUIGlObject.h>
#include <utils/geom/PositionVector.h>
#include <utils/gui/div/GLHelper.h>
#include <utils/gui/div/GUIParameterTableWindow.h>
#include <utils/gui/globjects/GLIncludes.h>
#include <microsim/logging/FunctionBinding.h>
#include <microsim/logging/FuncBinding_IntParam.h>
#include <microsim/logging/CastingFunctionBinding_Param.h>
#include <microsim/MSLane.h>
#include <microsim/output/MSInductLoop.h>
#include "GUIEdge.h"
#include "Command_Hotkey_InductionLoop.h"
#include "GUIInductLoop.h"
GUIInductLoop::GUIInductLoop(const std::string& id, MSLane* const lane,
double position, double length,
std::string name, const std::string& vTypes,
const std::string& nextEdges,
int detectPersons, bool show) :
MSInductLoop(id, lane, position, length, name, vTypes, nextEdges, detectPersons, true),
myWrapper(nullptr),
myShow(show) {
}
GUIInductLoop::~GUIInductLoop() {}
GUIDetectorWrapper*
GUIInductLoop::buildDetectorGUIRepresentation() {
if (hasParameter("hotkey")) {
Command_Hotkey_InductionLoop::registerHotkey(getParameter("hotkey"), this);
}
myWrapper = new MyWrapper(*this, myPosition);
return myWrapper;
}
void
GUIInductLoop::setSpecialColor(const RGBColor* color) {
if (myWrapper != nullptr) {
myWrapper->setSpecialColor(color);
}
}
GUIInductLoop::MyWrapper::MyWrapper(GUIInductLoop& detector, double pos) :
GUIDetectorWrapper(GLO_E1DETECTOR, detector.getID(), GUIIconSubSys::getIcon(GUIIcon::E1)),
myDetector(detector), myPosition(pos),
myHaveLength(myPosition != detector.getEndPosition()),
mySpecialColor(nullptr) {
mySupportsOverride = true;
myFGPosition = detector.getLane()->geometryPositionAtOffset(pos);
myBoundary.add(myFGPosition.x() + (double) 5.5, myFGPosition.y() + (double) 5.5);
myBoundary.add(myFGPosition.x() - (double) 5.5, myFGPosition.y() - (double) 5.5);
myFGRotation = -detector.getLane()->getShape().rotationDegreeAtOffset(pos);
if (myHaveLength) {
const MSLane& lane = *detector.getLane();
const double endPos = detector.getEndPosition();
myFGShape = lane.getShape();
myFGShape = myFGShape.getSubpart(
lane.interpolateLanePosToGeometryPos(pos),
lane.interpolateLanePosToGeometryPos(endPos));
myFGShapeRotations.reserve(myFGShape.size() - 1);
myFGShapeLengths.reserve(myFGShape.size() - 1);
int e = (int) myFGShape.size() - 1;
for (int i = 0; i < e; ++i) {
const Position& f = myFGShape[i];
const Position& s = myFGShape[i + 1];
myFGShapeLengths.push_back(f.distanceTo(s));
myFGShapeRotations.push_back((double) atan2((s.x() - f.x()), (f.y() - s.y())) * (double) 180.0 / (double) PI);
}
myOutline.push_back(lane.geometryPositionAtOffset(pos, -1));
myOutline.push_back(lane.geometryPositionAtOffset(pos, 1));
myOutline.push_back(lane.geometryPositionAtOffset(endPos, 1));
myOutline.push_back(lane.geometryPositionAtOffset(endPos, -1));
myIndicators.push_back(lane.geometryPositionAtOffset(pos, -1.7));
myIndicators.push_back(lane.geometryPositionAtOffset(pos, 1.7));
myIndicators.push_back(lane.geometryPositionAtOffset(endPos, 1.7));
myIndicators.push_back(lane.geometryPositionAtOffset(endPos, -1.7));
}
}
GUIInductLoop::MyWrapper::~MyWrapper() {}
Boundary
GUIInductLoop::MyWrapper::getCenteringBoundary() const {
Boundary b(myBoundary);
b.grow(20);
return b;
}
GUIParameterTableWindow*
GUIInductLoop::MyWrapper::getParameterWindow(GUIMainWindow& app,
GUISUMOAbstractView& ) {
GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
ret->mkItem(TL("name"), false, myDetector.getName());
ret->mkItem(TL("position [m]"), false, myPosition);
if (myDetector.getEndPosition() != myPosition) {
ret->mkItem(TL("end position [m]"), false, myDetector.getEndPosition());
}
ret->mkItem(TL("lane"), false, myDetector.getLane()->getID());
if (myDetector.isTyped()) {
ret->mkItem(TL("vTypes"), false, toString(myDetector.getVehicleTypes()));
}
ret->mkItem(TL("entered vehicles [-]"), true,
new FuncBinding_IntParam<GUIInductLoop, double>(&myDetector, &GUIInductLoop::getEnteredNumber, 0));
ret->mkItem(TL("speed [m/s]"), true,
new FuncBinding_IntParam<GUIInductLoop, double>(&myDetector, &GUIInductLoop::getSpeed, 0));
ret->mkItem(TL("occupancy [%]"), true,
new FunctionBinding<GUIInductLoop, double>(&myDetector, &GUIInductLoop::getOccupancy));
ret->mkItem(TL("vehicle length [m]"), true,
new FuncBinding_IntParam<GUIInductLoop, double>(&myDetector, &GUIInductLoop::getVehicleLength, 0));
ret->mkItem(TL("empty time [s]"), true,
new FunctionBinding<GUIInductLoop, double>(&myDetector, &GUIInductLoop::getTimeSinceLastDetection));
ret->mkItem(TL("occupied time [s]"), true,
new FunctionBinding<GUIInductLoop, double>(&myDetector, &GUIInductLoop::getOccupancyTime));
ret->mkItem(TL("interval entered vehicles [#]"), true,
new CastingFunctionBinding_Param<GUIInductLoop, double, int, bool>(&myDetector, &GUIInductLoop::getIntervalVehicleNumber, false));
ret->mkItem(TL("interval speed [m/s]"), true,
new CastingFunctionBinding_Param<GUIInductLoop, double, double, bool>(&myDetector, &GUIInductLoop::getIntervalMeanSpeed, false));
ret->mkItem(TL("interval occupancy [%]"), true,
new CastingFunctionBinding_Param<GUIInductLoop, double, double, bool>(&myDetector, &GUIInductLoop::getIntervalOccupancy, false));
ret->mkItem(TL("last interval entered vehicles [#]"), true,
new CastingFunctionBinding_Param<GUIInductLoop, double, int, bool>(&myDetector, &GUIInductLoop::getIntervalVehicleNumber, true));
ret->mkItem(TL("last interval speed [m/s]"), true,
new CastingFunctionBinding_Param<GUIInductLoop, double, double, bool>(&myDetector, &GUIInductLoop::getIntervalMeanSpeed, true));
ret->mkItem(TL("last interval occupancy [%]"), true,
new CastingFunctionBinding_Param<GUIInductLoop, double, double, bool>(&myDetector, &GUIInductLoop::getIntervalOccupancy, true));
ret->closeBuilding(&myDetector);
return ret;
}
void
GUIInductLoop::MyWrapper::drawGL(const GUIVisualizationSettings& s) const {
if (!myDetector.isVisible()) {
return;
}
GLHelper::pushName(getGlID());
double width = (double) 2.0 * s.scale;
glLineWidth(1.0);
const double exaggeration = getExaggeration(s);
glColor3d(1, 1, 0);
if (myHaveLength) {
GLHelper::pushMatrix();
glTranslated(0, 0, GLO_JUNCTION + 0.4);
GLHelper::drawBoxLines(myFGShape, myFGShapeRotations, myFGShapeLengths, MIN2(1.0, exaggeration), 0, 0);
if (width * exaggeration > 1) {
setOutlineColor();
glTranslated(0, 0, .01);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBegin(GL_QUADS);
for (const Position& p : myOutline) {
glVertex2d(p.x(), p.y());
}
glEnd();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_LINES);
glVertex2d(myIndicators[0].x(), myIndicators[0].y());
glVertex2d(myIndicators[1].x(), myIndicators[1].y());
glEnd();
glBegin(GL_LINES);
glVertex2d(myIndicators[2].x(), myIndicators[2].y());
glVertex2d(myIndicators[3].x(), myIndicators[3].y());
glEnd();
if (mySpecialColor != nullptr && *mySpecialColor == RGBColor::ORANGE) {
glBegin(GL_LINES);
glVertex2d(myOutline[0].x(), myOutline[0].y());
glVertex2d(myOutline[2].x(), myOutline[2].y());
glEnd();
glBegin(GL_LINES);
glVertex2d(myOutline[1].x(), myOutline[1].y());
glVertex2d(myOutline[3].x(), myOutline[3].y());
glEnd();
}
}
GLHelper::popMatrix();
} else {
GLHelper::pushMatrix();
glTranslated(0, 0, GLO_JUNCTION + 0.4);
glTranslated(myFGPosition.x(), myFGPosition.y(), 0);
glRotated(myFGRotation, 0, 0, 1);
glScaled(exaggeration, exaggeration, 1);
glBegin(GL_QUADS);
glVertex2d(0 - 1.0, 2);
glVertex2d(-1.0, -2);
glVertex2d(1.0, -2);
glVertex2d(1.0, 2);
glEnd();
glTranslated(0, 0, .01);
setOutlineColor();
if (width * exaggeration > 1) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBegin(GL_QUADS);
glVertex2d(0 - 1.0, 2);
glVertex2d(-1.0, -2);
glVertex2d(1.0, -2);
glVertex2d(1.0, 2);
glEnd();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glRotated(90, 0, 0, -1);
glBegin(GL_LINES);
glVertex2d(0, 1.7);
glVertex2d(0, -1.7);
glEnd();
if (mySpecialColor != nullptr && *mySpecialColor == RGBColor::ORANGE) {
glBegin(GL_LINES);
glVertex2d(-1.0, 2);
glVertex2d(1.0, -2);
glEnd();
glBegin(GL_LINES);
glVertex2d(-1.0, -2);
glVertex2d(1.0, 2);
glEnd();
}
}
GLHelper::popMatrix();
}
drawName(getCenteringBoundary().getCenter(), s.scale, s.addName);
GLHelper::popName();
}
void
GUIInductLoop::MyWrapper::setOutlineColor() const {
if (haveOverride()) {
glColor3d(1, 0, 1);
} else if (mySpecialColor == nullptr) {
glColor3d(1, 1, 1);
} else {
GLHelper::setColor(*mySpecialColor);
}
}
bool
GUIInductLoop::MyWrapper::haveOverride() const {
return myDetector.getOverrideTime() >= 0;
}
void
GUIInductLoop::MyWrapper::toggleOverride() const {
if (haveOverride()) {
myDetector.overrideTimeSinceDetection(-1);
} else {
myDetector.overrideTimeSinceDetection(0);
}
}