#include <config.h>
#ifdef HAVE_OSG
#include <cmath>
#include <fxkeys.h>
#include <iostream>
#include <limits>
#include <utility>
#include <foreign/rtree/SUMORTree.h>
#include <gui/GUIApplicationWindow.h>
#include <gui/GUISUMOViewParent.h>
#include <gui/GUIViewTraffic.h>
#include <guisim/GUIEdge.h>
#include <guisim/GUIJunctionWrapper.h>
#include <guisim/GUILane.h>
#include <guisim/GUINet.h>
#include <guisim/GUIPerson.h>
#include <guisim/GUIVehicle.h>
#include <microsim/MSEdge.h>
#include <microsim/MSEdgeControl.h>
#include <microsim/MSLane.h>
#include <microsim/MSNet.h>
#include <microsim/MSVehicleControl.h>
#include <microsim/traffic_lights/MSSimpleTrafficLightLogic.h>
#include <microsim/traffic_lights/MSTLLogicControl.h>
#include <microsim/transportables/MSTransportableControl.h>
#include <utils/common/FileHelpers.h>
#include <utils/common/MsgHandler.h>
#include <utils/common/RGBColor.h>
#include <utils/common/StringUtils.h>
#include <utils/foxtools/MFXCheckableButton.h>
#include <utils/foxtools/MFXImageHelper.h>
#include <utils/geom/GeoConvHelper.h>
#include <utils/geom/PositionVector.h>
#include <utils/gui/div/GLHelper.h>
#include <utils/gui/div/GUIDesigns.h>
#include <utils/gui/div/GUIGlobalSelection.h>
#include <utils/gui/globjects/GLIncludes.h>
#include <utils/gui/globjects/GUIGlObjectStorage.h>
#include <utils/gui/images/GUIIconSubSys.h>
#include <utils/gui/images/GUITexturesHelper.h>
#include <utils/gui/settings/GUICompleteSchemeStorage.h>
#include <utils/gui/windows/GUIAppEnum.h>
#include <utils/gui/windows/GUIDialog_EditViewport.h>
#include <utils/gui/windows/GUIDialog_ViewSettings.h>
#include <utils/gui/windows/GUIPerspectiveChanger.h>
#include <utils/gui/windows/GUISUMOAbstractView.h>
#include "GUIOSGBuilder.h"
#include "GUIOSGPerspectiveChanger.h"
#include "GUIOSGView.h"
FXDEFMAP(GUIOSGView) GUIOSGView_Map[] = {
FXMAPFUNC(SEL_CHORE, MID_CHORE, GUIOSGView::onIdle),
};
FXIMPLEMENT(GUIOSGView, GUISUMOAbstractView, GUIOSGView_Map, ARRAYNUMBER(GUIOSGView_Map))
std::ostream&
operator<<(std::ostream& os, const osg::Vec3d& v) {
return os << v.x() << "," << v.y() << "," << v.z();
}
GUIOSGView::Command_TLSChange::Command_TLSChange(const MSLink* const link, osg::Switch* switchNode)
: myLink(link), mySwitch(switchNode), myLastState(LINKSTATE_TL_OFF_NOSIGNAL) {
execute();
}
GUIOSGView::Command_TLSChange::~Command_TLSChange() {}
void
GUIOSGView::Command_TLSChange::execute() {
switch (myLink->getState()) {
case LINKSTATE_TL_GREEN_MAJOR:
case LINKSTATE_TL_GREEN_MINOR:
mySwitch->setSingleChildOn(0);
break;
case LINKSTATE_TL_YELLOW_MAJOR:
case LINKSTATE_TL_YELLOW_MINOR:
mySwitch->setSingleChildOn(1);
break;
case LINKSTATE_TL_RED:
case LINKSTATE_STOP:
mySwitch->setSingleChildOn(2);
break;
case LINKSTATE_TL_REDYELLOW:
mySwitch->setSingleChildOn(3);
break;
case LINKSTATE_TL_OFF_BLINKING:
case LINKSTATE_TL_OFF_NOSIGNAL:
mySwitch->setSingleChildOn(3);
break;
default:
mySwitch->setAllChildrenOff();
}
myLastState = myLink->getState();
}
GUIOSGView::GUIOSGView(
FXComposite* p,
GUIMainWindow& app,
GUISUMOViewParent* parent,
GUINet& net, FXGLVisual* glVis,
FXGLCanvas* share) :
GUISUMOAbstractView(p, app, parent, net.getVisualisationSpeedUp(), glVis, share),
myTracked(0), myLastUpdate(-1),
myOSGNormalizedCursorX(0.), myOSGNormalizedCursorY(0.) {
if (myChanger != nullptr) {
delete (myChanger);
}
int w = getWidth();
int h = getHeight();
myAdapter = new FXOSGAdapter(this, new FXCursor(parent->getApp(), CURSOR_CROSS));
myViewer = new osgViewer::Viewer();
myCameraManipulator = new GUIOSGManipulator(this);
myChanger = new GUIOSGPerspectiveChanger(*this, *myGrid);
const char* sumoPath = getenv("SUMO_HOME");
if (sumoPath != 0) {
std::string newPath = std::string(sumoPath) + "/data/3D";
if (FileHelpers::isReadable(newPath)) {
osgDB::FilePathList path = osgDB::Registry::instance()->getDataFilePathList();
path.push_back(newPath);
osgDB::Registry::instance()->setDataFilePathList(path);
}
}
myGreenLight = osgDB::readNodeFile("tlg.obj");
myYellowLight = osgDB::readNodeFile("tly.obj");
myRedLight = osgDB::readNodeFile("tlr.obj");
myRedYellowLight = osgDB::readNodeFile("tlu.obj");
myPoleBase = osgDB::readNodeFile("poleBase.obj");
if (myGreenLight == 0 || myYellowLight == 0 || myRedLight == 0 || myRedYellowLight == 0 || myPoleBase == 0) {
WRITE_ERROR(TL("Could not load traffic light files."));
}
double left, right, bottom, top, zNear, zFar;
myViewer->getCamera()->getProjectionMatrixAsFrustum(left, right, bottom, top, zNear, zFar);
myRoot = GUIOSGBuilder::buildOSGScene(myGreenLight, myYellowLight, myRedLight, myRedYellowLight, myPoleBase);
myPlane = new osg::MatrixTransform();
myPlane->setCullCallback(new ExcludeFromNearFarComputationCallback());
myPlane->addChild(GUIOSGBuilder::buildPlane((float)(zFar - zNear)));
myPlane->addUpdateCallback(new PlaneMoverCallback(myViewer->getCamera()));
myRoot->addChild(myPlane);
osgViewer::StatsHandler* statsHandler = new osgViewer::StatsHandler();
statsHandler->setKeyEventTogglesOnScreenStats(osgGA::GUIEventAdapter::KEY_I);
myViewer->addEventHandler(statsHandler);
myViewer->setSceneData(myRoot);
myViewer->setCameraManipulator(myCameraManipulator);
myViewer->setKeyEventSetsDone(0);
myViewer->getCamera()->setGraphicsContext(myAdapter);
myViewer->getCamera()->setViewport(0, 0, w, h);
myViewer->getCamera()->setNearFarRatio(0.005);
myViewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
myViewer->addEventHandler(new PickHandler(this));
osg::Vec3d lookFrom, lookAt, up;
myCameraManipulator->getHomePosition(lookFrom, lookAt, up);
lookFrom = lookAt + osg::Z_AXIS;
up = osg::Y_AXIS;
myCameraManipulator->setHomePosition(lookFrom, lookAt, up);
myViewer->home();
recenterView();
myViewer->home();
getApp()->addChore(this, MID_CHORE);
myTextNode = new osg::Geode();
myText = new osgText::Text;
myText->setCharacterSizeMode(osgText::Text::SCREEN_COORDS);
myText->setShaderTechnique(osgText::NO_TEXT_SHADER);
osgText::Font* font = osgText::readFontFile("arial.ttf");
if (font != nullptr) {
myText->setFont(font);
}
myText->setCharacterSize(16.f);
myTextNode->addDrawable(myText);
myText->setAlignment(osgText::TextBase::AlignmentType::LEFT_TOP);
myText->setDrawMode(osgText::TextBase::DrawModeMask::FILLEDBOUNDINGBOX | osgText::TextBase::DrawModeMask::TEXT);
myText->setBoundingBoxColor(osg::Vec4(0.0f, 0.0f, 0.2f, 0.5f));
myText->setBoundingBoxMargin(2.0f);
myHUD = new osg::Camera;
myHUD->setProjectionMatrixAsOrtho2D(0, 800, 0, 800);
myHUD->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
myHUD->setViewMatrix(osg::Matrix::identity());
myHUD->setClearMask(GL_DEPTH_BUFFER_BIT);
myHUD->setRenderOrder(osg::Camera::POST_RENDER);
myHUD->setAllowEventFocus(false);
myHUD->setGraphicsContext(myAdapter);
myHUD->addChild(myTextNode);
myHUD->setViewport(0, 0, w, h);
myViewer->addSlave(myHUD, false);
myCameraManipulator->updateHUDText();
adoptViewSettings();
osgUtil::Optimizer optimizer;
optimizer.optimize(myRoot);
}
GUIOSGView::~GUIOSGView() {
getApp()->removeChore(this, MID_CHORE);
myViewer->setDone(true);
myViewer = 0;
myRoot = 0;
myAdapter = 0;
myCameraManipulator = 0;
myHUD = 0;
myText = 0;
myTextNode = 0;
myGreenLight = 0;
myYellowLight = 0;
myRedLight = 0;
myRedYellowLight = 0;
myPoleBase = 0;
}
void
GUIOSGView::adoptViewSettings() {
osg::Light* globalLight = myViewer->getLight();
globalLight->setAmbient(toOSGColorVector(myVisualizationSettings->ambient3DLight));
globalLight->setDiffuse(toOSGColorVector(myVisualizationSettings->diffuse3DLight));
myViewer->getCamera()->setClearColor(toOSGColorVector(myVisualizationSettings->skyColor));
osg::Geode* planeGeode = dynamic_cast<osg::Geode*>(myPlane->getChild(0));
osg::Geometry* planeGeom = dynamic_cast<osg::Geometry*>(planeGeode->getChild(0));
osg::Vec4ubArray* colors = dynamic_cast<osg::Vec4ubArray*>(planeGeom->getColorArray());
(*colors)[0].set(myVisualizationSettings->backgroundColor.red(),
myVisualizationSettings->backgroundColor.green(),
myVisualizationSettings->backgroundColor.blue(),
myVisualizationSettings->backgroundColor.alpha());
planeGeom->setColorArray(colors);
unsigned int cullMask = 0xFFFFFFFF;
if (!myVisualizationSettings->show3DTLSDomes) {
cullMask &= ~(unsigned int)NODESET_TLSDOMES;
}
if (!myVisualizationSettings->show3DTLSLinkMarkers) {
cullMask &= ~(unsigned int)NODESET_TLSLINKMARKERS;
}
if (!myVisualizationSettings->generate3DTLSModels) {
cullMask &= ~(unsigned int)NODESET_TLSMODELS;
}
myViewer->getCamera()->setCullMask(cullMask);
unsigned int hudCullMask = (myVisualizationSettings->show3DHeadUpDisplay) ? 0xFFFFFFFF : 0;
myHUD->setCullMask(hudCullMask);
}
Position
GUIOSGView::getPositionInformation() const {
Position pos;
getPositionAtCursor(myOSGNormalizedCursorX, myOSGNormalizedCursorY, pos);
return pos;
}
bool
GUIOSGView::is3DView() const {
return true;
}
void
GUIOSGView::buildViewToolBars(GUIGlChildWindow* v) {
{
const std::vector<std::string>& names = gSchemeStorage.getNames();
for (std::vector<std::string>::const_iterator i = names.begin(); i != names.end(); ++i) {
v->getColoringSchemesCombo()->appendIconItem(i->c_str());
if ((*i) == myVisualizationSettings->name) {
v->getColoringSchemesCombo()->setCurrentItem(v->getColoringSchemesCombo()->getNumItems() - 1);
}
}
}
GUIDesigns::buildFXButton(v->getLocatorPopup(),
"Locate Junction", "Locate a junction within the network.", "",
GUIIconSubSys::getIcon(GUIIcon::LOCATEJUNCTION), v, MID_HOTKEY_SHIFT_J_LOCATEJUNCTION,
GUIDesignButtonPopup);
GUIDesigns::buildFXButton(v->getLocatorPopup(),
"Locate Street", "Locate a street within the network.", "",
GUIIconSubSys::getIcon(GUIIcon::LOCATEEDGE), v, MID_HOTKEY_SHIFT_E_LOCATEEDGE,
GUIDesignButtonPopup);
GUIDesigns::buildFXButton(v->getLocatorPopup(),
"Locate Vehicle", "Locate a vehicle within the network.", "",
GUIIconSubSys::getIcon(GUIIcon::LOCATEVEHICLE), v, MID_HOTKEY_SHIFT_V_LOCATEVEHICLE,
GUIDesignButtonPopup);
GUIDesigns::buildFXButton(v->getLocatorPopup(),
"Locate Person", "Locate a person within the network.", "",
GUIIconSubSys::getIcon(GUIIcon::LOCATEPERSON), v, MID_HOTKEY_SHIFT_P_LOCATEPERSON,
GUIDesignButtonPopup);
GUIDesigns::buildFXButton(v->getLocatorPopup(),
"Locate Container", "Locate a container within the network.", "",
GUIIconSubSys::getIcon(GUIIcon::LOCATECONTAINER), v, MID_HOTKEY_SHIFT_C_LOCATECONTAINER,
GUIDesignButtonPopup);
GUIDesigns::buildFXButton(v->getLocatorPopup(),
"Locate TLS", "Locate a tls within the network.", "",
GUIIconSubSys::getIcon(GUIIcon::LOCATETLS), v, MID_HOTKEY_SHIFT_T_LOCATETLS,
GUIDesignButtonPopup);
GUIDesigns::buildFXButton(v->getLocatorPopup(),
"Locate Additional", "Locate an additional structure within the network.", "",
GUIIconSubSys::getIcon(GUIIcon::LOCATEADD), v, MID_HOTKEY_SHIFT_A_LOCATEADDITIONAL,
GUIDesignButtonPopup);
GUIDesigns::buildFXButton(v->getLocatorPopup(),
"Locate POI", "Locate a POI within the network.", "",
GUIIconSubSys::getIcon(GUIIcon::LOCATEPOI), v, MID_HOTKEY_SHIFT_O_LOCATEPOI,
GUIDesignButtonPopup);
GUIDesigns::buildFXButton(v->getLocatorPopup(),
"Locate Polygon", "Locate a Polygon within the network.", "",
GUIIconSubSys::getIcon(GUIIcon::LOCATEPOLY), v, MID_HOTKEY_SHIFT_L_LOCATEPOLY,
GUIDesignButtonPopup);
}
void
GUIOSGView::resize(int w, int h) {
GUISUMOAbstractView::resize(w, h);
updateHUDPosition(w, h);
}
void
GUIOSGView::position(int x, int y, int w, int h) {
GUISUMOAbstractView::position(x, y, w, h);
updateHUDPosition(w, h);
}
void
GUIOSGView::updateHUDPosition(int w, int h) {
myHUD->setProjectionMatrixAsOrtho2D(0, w, 0, h);
myText->setPosition(osg::Vec3d(0., static_cast<double>(height), 0.));
}
void
GUIOSGView::updateHUDText(const std::string text) {
myText->setText(text, osgText::String::ENCODING_UTF8);
}
void
GUIOSGView::recenterView() {
stopTrack();
Position center = myGrid->getCenter();
double radius = std::max(myGrid->xmax() - myGrid->xmin(), myGrid->ymax() - myGrid->ymin());
myChanger->centerTo(center, radius);
}
bool
GUIOSGView::setColorScheme(const std::string& name) {
if (!gSchemeStorage.contains(name)) {
return false;
}
if (myGUIDialogViewSettings != 0) {
if (myGUIDialogViewSettings->getCurrentScheme() != name) {
myGUIDialogViewSettings->setCurrentScheme(name);
}
}
myVisualizationSettings = &gSchemeStorage.get(name.c_str());
myVisualizationSettings->gaming = myApp->isGaming();
adoptViewSettings();
update();
return true;
}
long
GUIOSGView::onPaint(FXObject*, FXSelector, void*) {
if (!isEnabled()) {
return 1;
}
myDecalsLockMutex.lock();
for (GUISUMOAbstractView::Decal& d : myDecals) {
if (!d.initialised && d.filename.length() > 0) {
if (d.filename.length() == 6 && d.filename.substr(0, 5) == "light") {
GUIOSGBuilder::buildLight(d, *myRoot);
} else if (d.filename.length() > 3 && d.filename.substr(0, 3) == "tl:") {
const int linkStringIdx = (int)d.filename.find(':', 3);
GUINet* net = (GUINet*) MSNet::getInstance();
try {
const std::string tlLogic = d.filename.substr(3, linkStringIdx - 3);
MSTLLogicControl::TLSLogicVariants& vars = net->getTLSControl().get(tlLogic);
const int linkIdx = StringUtils::toInt(d.filename.substr(linkStringIdx + 1));
if (linkIdx < 0 || linkIdx >= static_cast<int>(vars.getActive()->getLinks().size())) {
throw NumberFormatException("");
}
const MSLink* const link = vars.getActive()->getLinksAt(linkIdx)[0];
osg::Group* tlNode = GUIOSGBuilder::getTrafficLight(d, vars, link, myGreenLight, myYellowLight, myRedLight, myRedYellowLight, myPoleBase, true, 0.5);
tlNode->setName("tlLogic:" + tlLogic);
myRoot->addChild(tlNode);
} catch (NumberFormatException&) {
WRITE_ERRORF(TL("Invalid link index in '%'."), d.filename);
} catch (InvalidArgument&) {
WRITE_ERRORF(TL("Unknown traffic light in '%'."), d.filename);
}
} else {
GUIOSGBuilder::buildDecal(d, *myRoot);
}
d.initialised = true;
}
}
myDecalsLockMutex.unlock();
for (auto& item : myVehicles) {
item.second.active = false;
}
GUINet* net = static_cast<GUINet*>(MSNet::getInstance());
for (const MSEdge* e : net->getEdgeControl().getEdges()) {
for (const MSLane* l : e->getLanes()) {
const MSLane::VehCont& vehicles = l->getVehiclesSecure();
for (MSVehicle* msVeh : vehicles) {
GUIVehicle* veh = static_cast<GUIVehicle*>(msVeh);
if (!(veh->isOnRoad() || veh->isParking() || veh->wasRemoteControlled())) {
continue;
}
auto itVeh = myVehicles.find(veh);
if (itVeh == myVehicles.end()) {
myVehicles[veh] = GUIOSGBuilder::buildMovable(veh->getVehicleType());
myRoot->addChild(myVehicles[veh].pos);
myVehicles[veh].pos->setName("vehicle:" + veh->getID());
veh->setNode(myVehicles[veh].pos);
} else {
itVeh->second.active = true;
}
osg::PositionAttitudeTransform* n = myVehicles[veh].pos;
n->setPosition(osg::Vec3d(veh->getPosition().x(), veh->getPosition().y(), veh->getPosition().z()));
const double dir = veh->getAngle() + M_PI / 2.;
const double slope = -veh->getSlope();
n->setAttitude(osg::Quat(osg::DegreesToRadians(slope), osg::Vec3(1, 0, 0),
0, osg::Vec3(0, 1, 0),
dir, osg::Vec3(0, 0, 1)));
if (myVisualizationSettings->ignoreColorSchemeFor3DVehicles) {
myVehicles[veh].activateMaterial(false);
} else {
myVehicles[veh].activateMaterial(true);
RGBColor col;
if (!GUIBaseVehicle::setFunctionalColor(myVisualizationSettings->vehicleColorer.getActive(), veh, col)) {
col = myVisualizationSettings->vehicleColorer.getScheme().getColor(veh->getColorValue(*myVisualizationSettings, myVisualizationSettings->vehicleColorer.getActive()));
}
myVehicles[veh].mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4d(col.red() / 255., col.green() / 255., col.blue() / 255., col.alpha() / 255.));
}
myVehicles[veh].lights->setValue(0, veh->signalSet(MSVehicle::VEH_SIGNAL_BLINKER_RIGHT | MSVehicle::VEH_SIGNAL_BLINKER_EMERGENCY));
myVehicles[veh].lights->setValue(1, veh->signalSet(MSVehicle::VEH_SIGNAL_BLINKER_LEFT | MSVehicle::VEH_SIGNAL_BLINKER_EMERGENCY));
myVehicles[veh].lights->setValue(2, veh->signalSet(MSVehicle::VEH_SIGNAL_BRAKELIGHT));
}
l->releaseVehicles();
}
}
for (auto veh = myVehicles.begin(); veh != myVehicles.end();) {
if (!veh->second.active) {
removeVeh((veh++)->first);
} else {
++veh;
}
}
const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
if (now != myLastUpdate || (myGUIDialogViewSettings != 0 && myGUIDialogViewSettings->shown())) {
GUINet::getGUIInstance()->updateColor(*myVisualizationSettings);
}
if (now != myLastUpdate && myTracked != 0) {
osg::Vec3d lookFrom, lookAt, up;
lookAt[0] = myTracked->getPosition().x();
lookAt[1] = myTracked->getPosition().y();
lookAt[2] = myTracked->getPosition().z();
const double angle = myTracked->getAngle();
lookFrom[0] = lookAt[0] + 50. * cos(angle);
lookFrom[1] = lookAt[1] + 50. * sin(angle);
lookFrom[2] = lookAt[2] + 10.;
osg::Matrix m;
m.makeLookAt(lookFrom, lookAt, osg::Z_AXIS);
myViewer->getCameraManipulator()->setByInverseMatrix(m);
}
for (auto& item : myPersons) {
item.second.active = false;
}
for (const MSEdge* e : net->getEdgeControl().getEdges()) {
const GUIEdge* ge = static_cast<const GUIEdge*>(e);
const std::set<MSTransportable*, ComparatorNumericalIdLess>& persons = ge->getPersonsSecure();
for (auto person : persons) {
if (person->hasArrived() || !person->hasDeparted()) {
continue;
}
auto itPers = myPersons.find(person);
if (itPers == myPersons.end()) {
myPersons[person] = GUIOSGBuilder::buildMovable(person->getVehicleType());
myRoot->addChild(myPersons[person].pos);
} else {
itPers->second.active = true;
}
osg::PositionAttitudeTransform* n = myPersons[person].pos;
const Position pos = person->getPosition();
n->setPosition(osg::Vec3d(pos.x(), pos.y(), pos.z()));
const double dir = person->getAngle() + M_PI / 2.;
n->setAttitude(osg::Quat(dir, osg::Vec3d(0, 0, 1)));
RGBColor col;
GUIPerson* actualPerson = dynamic_cast<GUIPerson*>(person);
if (!GUIPerson::setFunctionalColor(myVisualizationSettings->personColorer.getActive(), actualPerson, col)) {
col = myVisualizationSettings->personColorer.getScheme().getColor(actualPerson->getColorValue(*myVisualizationSettings, myVisualizationSettings->vehicleColorer.getActive()));
}
myPersons[person].mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4d(col.red() / 255., col.green() / 255., col.blue() / 255., col.alpha() / 255.));
}
ge->releasePersons();
}
for (auto person = myPersons.begin(); person != myPersons.end();) {
if (!person->second.active) {
removeTransportable((person++)->first);
} else {
++person;
}
}
if (myAdapter->makeCurrent()) {
myViewer->frame();
makeNonCurrent();
}
myLastUpdate = now;
return 1;
}
void
GUIOSGView::removeVeh(MSVehicle* veh) {
if (myTracked == veh) {
stopTrack();
}
std::map<MSVehicle*, OSGMovable>::iterator i = myVehicles.find(veh);
if (i != myVehicles.end()) {
myRoot->removeChild(i->second.pos);
myVehicles.erase(i);
}
}
void
GUIOSGView::removeTransportable(MSTransportable* t) {
std::map<MSTransportable*, OSGMovable>::iterator i = myPersons.find(t);
if (i != myPersons.end()) {
myRoot->removeChild(i->second.pos);
myPersons.erase(i);
}
}
void GUIOSGView::updateViewportValues() {
osg::Vec3d lookFrom, lookAt, up;
myViewer->getCameraManipulator()->getInverseMatrix().getLookAt(lookFrom, lookAt, up);
myGUIDialogEditViewport->setValues(Position(lookFrom[0], lookFrom[1], lookFrom[2]),
Position(lookAt[0], lookAt[1], lookAt[2]), calculateRotation(lookFrom, lookAt, up));
}
void
GUIOSGView::showViewportEditor() {
getViewportEditor();
osg::Vec3d lookFrom, lookAt, up;
myViewer->getCameraManipulator()->getInverseMatrix().getLookAt(lookFrom, lookAt, up);
Position from(lookFrom[0], lookFrom[1], lookFrom[2]), at(lookAt[0], lookAt[1], lookAt[2]);
myGUIDialogEditViewport->setOldValues(from, at, calculateRotation(lookFrom, lookAt, up));
myGUIDialogEditViewport->setZoomValue(100);
myGUIDialogEditViewport->show();
}
void
GUIOSGView::setViewportFromToRot(const Position& lookFrom, const Position& lookAt, double rotation) {
osg::Vec3d lookFromOSG, lookAtOSG, up;
lookFromOSG[0] = lookFrom.x();
lookFromOSG[1] = lookFrom.y();
lookFromOSG[2] = lookFrom.z();
lookAtOSG[0] = lookAt.x();
lookAtOSG[1] = lookAt.y();
lookAtOSG[2] = lookAt.z();
osg::Vec3d viewAxis, viewUp, orthogonal, normal;
viewAxis = lookFromOSG - lookAtOSG;
viewAxis.normalize();
viewUp = (viewAxis[0] + viewAxis[1] == 0.) ? osg::Vec3d(0., 1., 0.) : osg::Vec3d(0., 0., 1.);
orthogonal = viewUp ^ viewAxis;
orthogonal.normalize();
normal = viewAxis ^ orthogonal;
rotation = std::fmod(rotation, 360.);
if (rotation < 0) {
rotation += 360.;
}
myChanger->setRotation(rotation);
double angle = DEG2RAD(rotation);
up = normal * cos(angle) - orthogonal * sin(angle);
up.normalize();
double zoom = (myGUIDialogEditViewport != nullptr) ? myGUIDialogEditViewport->getZoomValue() : 100.;
lookFromOSG = lookFromOSG + viewAxis * (100. - zoom);
lookAtOSG = lookFromOSG - viewAxis;
myViewer->getCameraManipulator()->setHomePosition(lookFromOSG, lookAtOSG, up);
myViewer->home();
}
void
GUIOSGView::copyViewportTo(GUISUMOAbstractView* view) {
osg::Vec3d lookFrom, lookAt, up;
myViewer->getCameraManipulator()->getHomePosition(lookFrom, lookAt, up);
view->setViewportFromToRot(Position(lookFrom[0], lookFrom[1], lookFrom[2]),
Position(lookAt[0], lookAt[1], lookAt[2]), 0);
}
void
GUIOSGView::startTrack(int id) {
if (myTracked == 0 || (int)myTracked->getGlID() != id) {
myTracked = 0;
MSVehicleControl::constVehIt it = MSNet::getInstance()->getVehicleControl().loadedVehBegin();
for (; it != MSNet::getInstance()->getVehicleControl().loadedVehEnd(); it++) {
GUIVehicle* veh = (GUIVehicle*)(*it).second;
if ((int)veh->getGlID() == id) {
if (!veh->isOnRoad() || myVehicles.find(veh) == myVehicles.end()) {
return;
}
myTracked = veh;
break;
}
}
if (myTracked != 0) {
osg::Vec3d lookFrom, lookAt, up;
lookAt[0] = myTracked->getPosition().x();
lookAt[1] = myTracked->getPosition().y();
lookAt[2] = myTracked->getPosition().z();
lookFrom[0] = lookAt[0] + 50.;
lookFrom[1] = lookAt[1] + 50.;
lookFrom[2] = lookAt[2] + 10.;
osg::Matrix m;
m.makeLookAt(lookFrom, lookAt, osg::Z_AXIS);
myViewer->getCameraManipulator()->setByInverseMatrix(m);
}
}
}
void
GUIOSGView::stopTrack() {
myTracked = 0;
}
GUIGlID
GUIOSGView::getTrackedID() const {
return myTracked == 0 ? GUIGlObject::INVALID_ID : myTracked->getGlID();
}
void
GUIOSGView::onGamingClick(Position pos) {
MSTLLogicControl& tlsControl = MSNet::getInstance()->getTLSControl();
const MSTrafficLightLogic* minTll = nullptr;
double minDist = std::numeric_limits<double>::infinity();
for (const MSTrafficLightLogic* const tll : tlsControl.getAllLogics()) {
if (tlsControl.isActive(tll)) {
const MSTrafficLightLogic::LaneVector& lanes = tll->getLanesAt(0);
if (lanes.size() > 0) {
const Position& endPos = lanes[0]->getShape().back();
if (endPos.distanceTo(pos) < minDist) {
minDist = endPos.distanceTo(pos);
minTll = tll;
}
}
}
}
if (minTll != 0) {
const MSTLLogicControl::TLSLogicVariants& vars = tlsControl.get(minTll->getID());
const std::vector<MSTrafficLightLogic*> logics = vars.getAllLogics();
if (logics.size() > 1) {
MSSimpleTrafficLightLogic* l = (MSSimpleTrafficLightLogic*) logics[0];
for (int i = 0; i < (int)logics.size() - 1; i++) {
if (minTll->getProgramID() == logics[i]->getProgramID()) {
l = (MSSimpleTrafficLightLogic*) logics[i + 1];
tlsControl.switchTo(minTll->getID(), l->getProgramID());
}
}
if (l == logics[0]) {
tlsControl.switchTo(minTll->getID(), l->getProgramID());
}
l->changeStepAndDuration(tlsControl, MSNet::getInstance()->getCurrentTimeStep(), 0, l->getPhase(0).duration);
update();
}
}
}
SUMOTime
GUIOSGView::getCurrentTimeStep() const {
return MSNet::getInstance()->getCurrentTimeStep();
}
long GUIOSGView::onConfigure(FXObject* sender, FXSelector sel, void* ptr) {
const int w = getWidth();
const int h = getHeight();
if (w > 0 && h > 0) {
myAdapter->getEventQueue()->windowResize(0, 0, w, h);
myAdapter->resized(0, 0, w, h);
updateHUDPosition(w, h);
}
return FXGLCanvas::onConfigure(sender, sel, ptr);
}
long GUIOSGView::onKeyPress(FXObject* sender, FXSelector sel, void* ptr) {
int key = ((FXEvent*)ptr)->code;
myAdapter->getEventQueue()->keyPress(key);
if (key == FX::KEY_f || key == FX::KEY_Left || key == FX::KEY_Right || key == FX::KEY_Up || key == FX::KEY_Down) {
return 1;
}
return FXGLCanvas::onKeyPress(sender, sel, ptr);
}
long GUIOSGView::onKeyRelease(FXObject* sender, FXSelector sel, void* ptr) {
int key = ((FXEvent*)ptr)->code;
myAdapter->getEventQueue()->keyRelease(key);
if (key == FX::KEY_f || key == FX::KEY_Left || key == FX::KEY_Right || key == FX::KEY_Up || key == FX::KEY_Down) {
return 1;
}
return FXGLCanvas::onKeyRelease(sender, sel, ptr);
}
long GUIOSGView::onLeftBtnPress(FXObject* sender, FXSelector sel, void* ptr) {
handle(this, FXSEL(SEL_FOCUS_SELF, 0), ptr);
FXEvent* event = (FXEvent*)ptr;
myAdapter->getEventQueue()->mouseButtonPress((float)event->click_x, (float)event->click_y, 1);
if (myApp->isGaming()) {
onGamingClick(getPositionInformation());
}
return FXGLCanvas::onLeftBtnPress(sender, sel, ptr);
}
long GUIOSGView::onLeftBtnRelease(FXObject* sender, FXSelector sel, void* ptr) {
FXEvent* event = (FXEvent*)ptr;
myAdapter->getEventQueue()->mouseButtonRelease((float)event->click_x, (float)event->click_y, 1);
myChanger->onLeftBtnRelease(ptr);
return FXGLCanvas::onLeftBtnRelease(sender, sel, ptr);
}
long GUIOSGView::onMiddleBtnPress(FXObject* sender, FXSelector sel, void* ptr) {
handle(this, FXSEL(SEL_FOCUS_SELF, 0), ptr);
FXEvent* event = (FXEvent*)ptr;
myAdapter->getEventQueue()->mouseButtonPress((float)event->click_x, (float)event->click_y, 2);
return FXGLCanvas::onMiddleBtnPress(sender, sel, ptr);
}
long GUIOSGView::onMiddleBtnRelease(FXObject* sender, FXSelector sel, void* ptr) {
FXEvent* event = (FXEvent*)ptr;
myAdapter->getEventQueue()->mouseButtonRelease((float)event->click_x, (float)event->click_y, 2);
myChanger->onMiddleBtnRelease(ptr);
return FXGLCanvas::onMiddleBtnRelease(sender, sel, ptr);
}
long GUIOSGView::onRightBtnPress(FXObject* sender, FXSelector sel, void* ptr) {
handle(this, FXSEL(SEL_FOCUS_SELF, 0), ptr);
FXEvent* event = (FXEvent*)ptr;
myAdapter->getEventQueue()->mouseButtonPress((float)event->click_x, (float)event->click_y, 3);
return FXGLCanvas::onRightBtnPress(sender, sel, ptr);
}
long GUIOSGView::onRightBtnRelease(FXObject* sender, FXSelector sel, void* ptr) {
FXEvent* event = (FXEvent*)ptr;
myAdapter->getEventQueue()->mouseButtonRelease((float)event->click_x, (float)event->click_y, 3);
myChanger->onRightBtnRelease(ptr);
return FXGLCanvas::onRightBtnRelease(sender, sel, ptr);
}
long
GUIOSGView::onMouseMove(FXObject* sender, FXSelector sel, void* ptr) {
if (myPopup && !myPopup->shown()) {
destroyPopup();
}
FXEvent* event = (FXEvent*)ptr;
osgGA::GUIEventAdapter* ea = myAdapter->getEventQueue()->mouseMotion((float)event->win_x, (float)event->win_y);
setWindowCursorPosition(ea->getXnormalized(), ea->getYnormalized());
if (myGUIDialogEditViewport != nullptr && myGUIDialogEditViewport->shown()) {
updateViewportValues();
}
updatePositionInformation();
return FXGLCanvas::onMotion(sender, sel, ptr);
}
long
GUIOSGView::onIdle(FXObject* , FXSelector , void*) {
forceRefresh();
update();
getApp()->addChore(this, MID_CHORE);
return 1;
}
long
GUIOSGView::onCmdCloseLane(FXObject*, FXSelector, void*) {
GUILane* lane = getLaneUnderCursor();
if (lane != nullptr) {
lane->closeTraffic();
GUIGlObjectStorage::gIDStorage.unblockObject(lane->getGlID());
GUINet::getGUIInstance()->updateColor(*myVisualizationSettings);
update();
}
return 1;
}
long
GUIOSGView::onCmdCloseEdge(FXObject*, FXSelector, void*) {
GUILane* lane = getLaneUnderCursor();
if (lane != nullptr) {
dynamic_cast<GUIEdge*>(&lane->getEdge())->closeTraffic(lane);
GUIGlObjectStorage::gIDStorage.unblockObject(lane->getGlID());
GUINet::getGUIInstance()->updateColor(*myVisualizationSettings);
update();
}
return 1;
}
long
GUIOSGView::onCmdAddRerouter(FXObject*, FXSelector, void*) {
GUILane* lane = getLaneUnderCursor();
if (lane != nullptr) {
dynamic_cast<GUIEdge*>(&lane->getEdge())->addRerouter();
GUIGlObjectStorage::gIDStorage.unblockObject(lane->getGlID());
update();
}
return 1;
}
long
GUIOSGView::onCmdShowReachability(FXObject* menu, FXSelector selector, void*) {
GUILane* lane = getLaneUnderCursor();
if (lane != nullptr) {
GUIViewTraffic::showLaneReachability(lane, menu, selector);
if (myVisualizationSettings->laneColorer.getActive() != 36) {
myVisualizationSettings->laneColorer.setActive(1);
GUINet::getGUIInstance()->updateColor(*myVisualizationSettings);
}
update();
}
return 1;
}
long
GUIOSGView::onVisualizationChange(FXObject*, FXSelector, void*) {
adoptViewSettings();
return 1;
}
void
GUIOSGView::setWindowCursorPosition(float x, float y) {
myOSGNormalizedCursorX = x;
myOSGNormalizedCursorY = y;
}
double
GUIOSGView::calculateRotation(const osg::Vec3d& lookFrom, const osg::Vec3d& lookAt, const osg::Vec3d& up) {
osg::Vec3d viewAxis, viewUp, orthogonal, normal;
viewAxis = lookFrom - lookAt;
viewAxis.normalize();
viewUp = (abs(viewAxis[0]) + abs(viewAxis[1]) == 0.) ? osg::Y_AXIS : osg::Z_AXIS;
orthogonal = viewUp ^ viewAxis;
orthogonal.normalize();
normal = viewAxis ^ orthogonal;
double angle = atan2((normal ^ up).length() / (normal.length() * up.length()), (normal * up) / (normal.length() * up.length()));
if (angle < 0) {
angle += M_PI;
}
return RAD2DEG(angle);
}
void
GUIOSGView::updatePositionInformation() const {
Position pos;
if (getPositionAtCursor(myOSGNormalizedCursorX, myOSGNormalizedCursorY, pos)) {
myApp->getCartesianLabel()->setText(("x:" + toString(pos.x()) + ", y:" + toString(pos.y())).c_str());
GeoConvHelper::getFinal().cartesian2geo(pos);
if (GeoConvHelper::getFinal().usingGeoProjection()) {
myApp->getGeoLabel()->setText(("lat:" + toString(pos.y(), gPrecisionGeo) + ", lon:" + toString(pos.x(), gPrecisionGeo)).c_str());
} else {
myApp->getGeoLabel()->setText(TL("(No projection defined)"));
}
} else {
myApp->getCartesianLabel()->setText(TL("N/A"));
myApp->getGeoLabel()->setText(TL("N/A"));
}
}
bool
GUIOSGView::getPositionAtCursor(float xNorm, float yNorm, Position& pos) const {
osg::Vec3d lookFrom, lookAt, up, viewAxis;
myViewer->getCameraManipulator()->getInverseMatrix().getLookAt(lookFrom, lookAt, up);
if ((lookAt - lookFrom).z() >= 0.) {
return false;
}
osg::Matrixd iVP = osg::Matrixd::inverse(myViewer->getCamera()->getViewMatrix() * myViewer->getCamera()->getProjectionMatrix());
osg::Vec3 nearPoint = osg::Vec3(xNorm, yNorm, 0.0f) * iVP;
osg::Vec3 farPoint = osg::Vec3(xNorm, yNorm, 1.0f) * iVP;
osg::Vec3 ray = farPoint - nearPoint;
osg::Vec3 groundPos = nearPoint - ray * nearPoint.z() / ray.z();
pos.setx(groundPos.x());
pos.sety(groundPos.y());
pos.setz(0.);
return true;
}
std::vector<GUIGlObject*>
GUIOSGView::getGUIGlObjectsUnderCursor() {
std::vector<GUIGlObject*> result;
osgUtil::LineSegmentIntersector::Intersections intersections;
if (myViewer->computeIntersections(myViewer->getCamera(), osgUtil::Intersector::CoordinateFrame::PROJECTION, myOSGNormalizedCursorX, myOSGNormalizedCursorY, intersections)) {
for (auto intersection : intersections) {
if (!intersection.nodePath.empty()) {
for (osg::Node* currentNode : intersection.nodePath) {
if (currentNode->getName().length() > 0 && currentNode->getName().find(":") != std::string::npos) {
const std::string objID = currentNode->getName();
GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(objID);
if (o == nullptr) {
continue;
}
if (o->getGlID() == 0) {
continue;
}
result.push_back(o);
GUIGlObjectStorage::gIDStorage.unblockObject(o->getGlID());
}
}
}
}
}
return result;
}
GUILane*
GUIOSGView::getLaneUnderCursor() {
std::vector<GUIGlObject*> objects = getGUIGlObjectsUnderCursor();
if (objects.size() > 0) {
return dynamic_cast<GUILane*>(objects[0]);
}
return nullptr;
}
void
GUIOSGView::zoom2Pos(Position& camera, Position& lookAt, double zoom) {
osg::Vec3d lookFromOSG, lookAtOSG, viewAxis, up;
myViewer->getCameraManipulator()->getInverseMatrix().getLookAt(lookFromOSG, lookAtOSG, up);
lookFromOSG[0] = camera.x();
lookFromOSG[1] = camera.y();
lookFromOSG[2] = camera.z();
lookAtOSG[0] = lookAt.x();
lookAtOSG[1] = lookAt.y();
lookAtOSG[2] = lookAt.z();
viewAxis = lookAtOSG - lookFromOSG;
viewAxis.normalize();
osg::Vec3d cameraUpdate = lookFromOSG + viewAxis * (zoom - 100.);
osg::Vec3d lookAtUpdate = cameraUpdate + viewAxis;
myViewer->getCameraManipulator()->setHomePosition(cameraUpdate, lookAtUpdate, up);
myViewer->home();
}
osg::Vec4d
GUIOSGView::toOSGColorVector(RGBColor c, bool useAlpha) {
return osg::Vec4d(c.red() / 255., c.green() / 255., c.blue() / 255., (useAlpha) ? c.alpha() / 255. : 1.);
}
GUIOSGView::FXOSGAdapter::FXOSGAdapter(GUISUMOAbstractView* parent, FXCursor* cursor)
: myParent(parent), myOldCursor(cursor) {
_traits = new GraphicsContext::Traits();
_traits->x = 0;
_traits->y = 0;
_traits->width = parent->getWidth();
_traits->height = parent->getHeight();
_traits->windowDecoration = false;
_traits->doubleBuffer = true;
_traits->sharedContext = 0;
if (valid()) {
setState(new osg::State());
getState()->setGraphicsContext(this);
#ifdef DEBUG_GLERRORS
getState()->setCheckForGLErrors(osg::State::ONCE_PER_ATTRIBUTE);
std::cout << "OSG getCheckForGLErrors " << getState()->getCheckForGLErrors() << std::endl;
#endif
if (_traits.valid() && _traits->sharedContext != 0) {
getState()->setContextID(_traits->sharedContext->getState()->getContextID());
incrementContextIDUsageCount(getState()->getContextID());
} else {
getState()->setContextID(createNewContextID());
}
}
}
GUIOSGView::FXOSGAdapter::~FXOSGAdapter() {
delete myOldCursor;
}
void
GUIOSGView::FXOSGAdapter::grabFocus() {
myParent->setFocus();
}
void
GUIOSGView::FXOSGAdapter::useCursor(bool cursorOn) {
if (cursorOn) {
myParent->setDefaultCursor(myOldCursor);
} else {
myParent->setDefaultCursor(NULL);
}
}
bool
GUIOSGView::FXOSGAdapter::makeCurrentImplementation() {
myParent->makeCurrent();
return true;
}
bool
GUIOSGView::FXOSGAdapter::releaseContext() {
myParent->makeNonCurrent();
return true;
}
void
GUIOSGView::FXOSGAdapter::swapBuffersImplementation() {
myParent->swapBuffers();
}
bool
GUIOSGView::PickHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& ) {
if (ea.getEventType() == osgGA::GUIEventAdapter::DRAG) {
myDrag = true;
} else if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && ea.getButton() == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) {
if (!myDrag) {
if (myParent->makeCurrent()) {
std::vector<GUIGlObject*> objects = myParent->getGUIGlObjectsUnderCursor();
if (objects.size() > 0) {
myParent->openObjectDialog(objects);
}
myParent->makeNonCurrent();
}
}
myDrag = false;
}
return false;
}
#endif