Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file GUIOSGView.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Michael Behrisch
17 : /// @author Mirko Barthauer
18 : /// @date 19.01.2012
19 : ///
20 : // An OSG-based 3D view on the simulation
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #ifdef HAVE_OSG
25 :
26 : #include <cmath>
27 : #include <fxkeys.h>
28 : #include <iostream>
29 : #include <limits>
30 : #include <utility>
31 : #include <foreign/rtree/SUMORTree.h>
32 : #include <gui/GUIApplicationWindow.h>
33 : #include <gui/GUISUMOViewParent.h>
34 : #include <gui/GUIViewTraffic.h>
35 : #include <guisim/GUIEdge.h>
36 : #include <guisim/GUIJunctionWrapper.h>
37 : #include <guisim/GUILane.h>
38 : #include <guisim/GUINet.h>
39 : #include <guisim/GUIPerson.h>
40 : #include <guisim/GUIVehicle.h>
41 : #include <microsim/MSEdge.h>
42 : #include <microsim/MSEdgeControl.h>
43 : #include <microsim/MSLane.h>
44 : #include <microsim/MSNet.h>
45 : #include <microsim/MSVehicleControl.h>
46 : #include <microsim/traffic_lights/MSSimpleTrafficLightLogic.h>
47 : #include <microsim/traffic_lights/MSTLLogicControl.h>
48 : #include <microsim/transportables/MSTransportableControl.h>
49 : #include <utils/common/FileHelpers.h>
50 : #include <utils/common/MsgHandler.h>
51 : #include <utils/common/RGBColor.h>
52 : #include <utils/common/StringUtils.h>
53 : #include <utils/foxtools/MFXCheckableButton.h>
54 : #include <utils/foxtools/MFXImageHelper.h>
55 : #include <utils/geom/GeoConvHelper.h>
56 : #include <utils/geom/PositionVector.h>
57 : #include <utils/gui/div/GLHelper.h>
58 : #include <utils/gui/div/GUIDesigns.h>
59 : #include <utils/gui/div/GUIGlobalSelection.h>
60 : #include <utils/gui/globjects/GLIncludes.h>
61 : #include <utils/gui/globjects/GUIGlObjectStorage.h>
62 : #include <utils/gui/images/GUIIconSubSys.h>
63 : #include <utils/gui/images/GUITexturesHelper.h>
64 : #include <utils/gui/settings/GUICompleteSchemeStorage.h>
65 : #include <utils/gui/windows/GUIAppEnum.h>
66 : #include <utils/gui/windows/GUIDialog_EditViewport.h>
67 : #include <utils/gui/windows/GUIDialog_ViewSettings.h>
68 : #include <utils/gui/windows/GUIPerspectiveChanger.h>
69 : #include <utils/gui/windows/GUISUMOAbstractView.h>
70 :
71 : #include "GUIOSGBuilder.h"
72 : #include "GUIOSGPerspectiveChanger.h"
73 : #include "GUIOSGView.h"
74 :
75 : //#define DEBUG_GLERRORS
76 :
77 : FXDEFMAP(GUIOSGView) GUIOSGView_Map[] = {
78 : //________Message_Type_________ ___ID___ ________Message_Handler________
79 : FXMAPFUNC(SEL_CHORE, MID_CHORE, GUIOSGView::onIdle),
80 : };
81 172307 : FXIMPLEMENT(GUIOSGView, GUISUMOAbstractView, GUIOSGView_Map, ARRAYNUMBER(GUIOSGView_Map))
82 :
83 :
84 : std::ostream&
85 0 : operator<<(std::ostream& os, const osg::Vec3d& v) {
86 0 : return os << v.x() << "," << v.y() << "," << v.z();
87 : }
88 :
89 : // ===========================================================================
90 : // GUIOSGView::Command_TLSChange member method definitions
91 : // ===========================================================================
92 :
93 3450 : GUIOSGView::Command_TLSChange::Command_TLSChange(const MSLink* const link, osg::Switch* switchNode)
94 3450 : : myLink(link), mySwitch(switchNode), myLastState(LINKSTATE_TL_OFF_NOSIGNAL) {
95 3450 : execute();
96 3450 : }
97 :
98 :
99 6900 : GUIOSGView::Command_TLSChange::~Command_TLSChange() {}
100 :
101 :
102 : void
103 79054 : GUIOSGView::Command_TLSChange::execute() {
104 79054 : switch (myLink->getState()) {
105 20224 : case LINKSTATE_TL_GREEN_MAJOR:
106 : case LINKSTATE_TL_GREEN_MINOR:
107 20224 : mySwitch->setSingleChildOn(0);
108 20224 : break;
109 14306 : case LINKSTATE_TL_YELLOW_MAJOR:
110 : case LINKSTATE_TL_YELLOW_MINOR:
111 14306 : mySwitch->setSingleChildOn(1);
112 14306 : break;
113 44484 : case LINKSTATE_TL_RED:
114 : case LINKSTATE_STOP:
115 44484 : mySwitch->setSingleChildOn(2);
116 44484 : break;
117 0 : case LINKSTATE_TL_REDYELLOW:
118 0 : mySwitch->setSingleChildOn(3);
119 0 : break;
120 40 : case LINKSTATE_TL_OFF_BLINKING:
121 : case LINKSTATE_TL_OFF_NOSIGNAL:
122 40 : mySwitch->setSingleChildOn(3);
123 40 : break;
124 0 : default:
125 0 : mySwitch->setAllChildrenOff();
126 : }
127 79054 : myLastState = myLink->getState();
128 79054 : }
129 :
130 : // ===========================================================================
131 : // GUIOSGView member method definitions
132 : // ===========================================================================
133 :
134 436 : GUIOSGView::GUIOSGView(
135 : FXComposite* p,
136 : GUIMainWindow& app,
137 : GUISUMOViewParent* parent,
138 : GUINet& net, FXGLVisual* glVis,
139 436 : FXGLCanvas* share) :
140 : GUISUMOAbstractView(p, app, parent, net.getVisualisationSpeedUp(), glVis, share),
141 436 : myTracked(0), myLastUpdate(-1),
142 436 : myOSGNormalizedCursorX(0.), myOSGNormalizedCursorY(0.) {
143 436 : if (myChanger != nullptr) {
144 436 : delete (myChanger);
145 : }
146 : int w = getWidth();
147 : int h = getHeight();
148 436 : myAdapter = new FXOSGAdapter(this, new FXCursor(parent->getApp(), CURSOR_CROSS));
149 436 : myViewer = new osgViewer::Viewer();
150 436 : myCameraManipulator = new GUIOSGManipulator(this);
151 436 : myChanger = new GUIOSGPerspectiveChanger(*this, *myGrid);
152 436 : const char* sumoPath = getenv("SUMO_HOME");
153 436 : if (sumoPath != 0) {
154 872 : std::string newPath = std::string(sumoPath) + "/data/3D";
155 872 : if (FileHelpers::isReadable(newPath)) {
156 436 : osgDB::FilePathList path = osgDB::Registry::instance()->getDataFilePathList();
157 436 : path.push_back(newPath);
158 436 : osgDB::Registry::instance()->setDataFilePathList(path);
159 436 : }
160 : }
161 :
162 436 : myGreenLight = osgDB::readNodeFile("tlg.obj");
163 436 : myYellowLight = osgDB::readNodeFile("tly.obj");
164 436 : myRedLight = osgDB::readNodeFile("tlr.obj");
165 436 : myRedYellowLight = osgDB::readNodeFile("tlu.obj");
166 872 : myPoleBase = osgDB::readNodeFile("poleBase.obj");
167 436 : if (myGreenLight == 0 || myYellowLight == 0 || myRedLight == 0 || myRedYellowLight == 0 || myPoleBase == 0) {
168 0 : WRITE_ERROR(TL("Could not load traffic light files."));
169 : }
170 : // calculate camera frustum to scale the ground plane all across
171 : double left, right, bottom, top, zNear, zFar;
172 436 : myViewer->getCamera()->getProjectionMatrixAsFrustum(left, right, bottom, top, zNear, zFar);
173 436 : myRoot = GUIOSGBuilder::buildOSGScene(myGreenLight, myYellowLight, myRedLight, myRedYellowLight, myPoleBase);
174 436 : myPlane = new osg::MatrixTransform();
175 436 : myPlane->setCullCallback(new ExcludeFromNearFarComputationCallback());
176 436 : myPlane->addChild(GUIOSGBuilder::buildPlane((float)(zFar - zNear)));
177 872 : myPlane->addUpdateCallback(new PlaneMoverCallback(myViewer->getCamera()));
178 : myRoot->addChild(myPlane);
179 : // add the stats handler
180 436 : osgViewer::StatsHandler* statsHandler = new osgViewer::StatsHandler();
181 : statsHandler->setKeyEventTogglesOnScreenStats(osgGA::GUIEventAdapter::KEY_I);
182 436 : myViewer->addEventHandler(statsHandler);
183 436 : myViewer->setSceneData(myRoot);
184 436 : myViewer->setCameraManipulator(myCameraManipulator);
185 :
186 : myViewer->setKeyEventSetsDone(0);
187 436 : myViewer->getCamera()->setGraphicsContext(myAdapter);
188 436 : myViewer->getCamera()->setViewport(0, 0, w, h);
189 : myViewer->getCamera()->setNearFarRatio(0.005); // does not work together with setUpDepthPartitionForCamera
190 436 : myViewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
191 436 : myViewer->addEventHandler(new PickHandler(this));
192 : osg::Vec3d lookFrom, lookAt, up;
193 436 : myCameraManipulator->getHomePosition(lookFrom, lookAt, up);
194 436 : lookFrom = lookAt + osg::Z_AXIS;
195 436 : up = osg::Y_AXIS;
196 436 : myCameraManipulator->setHomePosition(lookFrom, lookAt, up);
197 436 : myViewer->home();
198 436 : recenterView();
199 436 : myViewer->home();
200 436 : getApp()->addChore(this, MID_CHORE);
201 436 : myTextNode = new osg::Geode();
202 436 : myText = new osgText::Text;
203 : myText->setCharacterSizeMode(osgText::Text::SCREEN_COORDS);
204 436 : myText->setShaderTechnique(osgText::NO_TEXT_SHADER);
205 436 : osgText::Font* font = osgText::readFontFile("arial.ttf");
206 436 : if (font != nullptr) {
207 436 : myText->setFont(font);
208 : }
209 436 : myText->setCharacterSize(16.f);
210 : myTextNode->addDrawable(myText);
211 436 : myText->setAlignment(osgText::TextBase::AlignmentType::LEFT_TOP);
212 436 : myText->setDrawMode(osgText::TextBase::DrawModeMask::FILLEDBOUNDINGBOX | osgText::TextBase::DrawModeMask::TEXT);
213 : myText->setBoundingBoxColor(osg::Vec4(0.0f, 0.0f, 0.2f, 0.5f));
214 436 : myText->setBoundingBoxMargin(2.0f);
215 :
216 436 : myHUD = new osg::Camera;
217 436 : myHUD->setProjectionMatrixAsOrtho2D(0, 800, 0, 800); // default size will be overwritten
218 436 : myHUD->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
219 436 : myHUD->setViewMatrix(osg::Matrix::identity());
220 : myHUD->setClearMask(GL_DEPTH_BUFFER_BIT);
221 : myHUD->setRenderOrder(osg::Camera::POST_RENDER);
222 : myHUD->setAllowEventFocus(false);
223 436 : myHUD->setGraphicsContext(myAdapter);
224 436 : myHUD->addChild(myTextNode);
225 436 : myHUD->setViewport(0, 0, w, h);
226 436 : myViewer->addSlave(myHUD, false);
227 436 : myCameraManipulator->updateHUDText();
228 :
229 : // adjust the main light
230 436 : adoptViewSettings();
231 : osgUtil::Optimizer optimizer;
232 : optimizer.optimize(myRoot);
233 436 : }
234 :
235 :
236 872 : GUIOSGView::~GUIOSGView() {
237 436 : getApp()->removeChore(this, MID_CHORE);
238 : myViewer->setDone(true);
239 436 : myViewer = 0;
240 : myRoot = 0;
241 : myAdapter = 0;
242 436 : myCameraManipulator = 0;
243 : myHUD = 0;
244 : myText = 0;
245 : myTextNode = 0;
246 : myGreenLight = 0;
247 : myYellowLight = 0;
248 : myRedLight = 0;
249 : myRedYellowLight = 0;
250 : myPoleBase = 0;
251 872 : }
252 :
253 :
254 : void
255 436 : GUIOSGView::adoptViewSettings() {
256 : // lighting
257 : osg::Light* globalLight = myViewer->getLight();
258 436 : globalLight->setAmbient(toOSGColorVector(myVisualizationSettings->ambient3DLight));
259 436 : globalLight->setDiffuse(toOSGColorVector(myVisualizationSettings->diffuse3DLight));
260 872 : myViewer->getCamera()->setClearColor(toOSGColorVector(myVisualizationSettings->skyColor));
261 :
262 : // ground color
263 436 : osg::Geode* planeGeode = dynamic_cast<osg::Geode*>(myPlane->getChild(0));
264 436 : osg::Geometry* planeGeom = dynamic_cast<osg::Geometry*>(planeGeode->getChild(0));
265 436 : osg::Vec4ubArray* colors = dynamic_cast<osg::Vec4ubArray*>(planeGeom->getColorArray());
266 436 : (*colors)[0].set(myVisualizationSettings->backgroundColor.red(),
267 436 : myVisualizationSettings->backgroundColor.green(),
268 436 : myVisualizationSettings->backgroundColor.blue(),
269 436 : myVisualizationSettings->backgroundColor.alpha());
270 : planeGeom->setColorArray(colors);
271 :
272 : // show/hide OSG nodes
273 : unsigned int cullMask = 0xFFFFFFFF;
274 436 : if (!myVisualizationSettings->show3DTLSDomes) {
275 : cullMask &= ~(unsigned int)NODESET_TLSDOMES;
276 : }
277 436 : if (!myVisualizationSettings->show3DTLSLinkMarkers) {
278 0 : cullMask &= ~(unsigned int)NODESET_TLSLINKMARKERS;
279 : }
280 436 : if (!myVisualizationSettings->generate3DTLSModels) {
281 436 : cullMask &= ~(unsigned int)NODESET_TLSMODELS;
282 : }
283 : myViewer->getCamera()->setCullMask(cullMask);
284 436 : unsigned int hudCullMask = (myVisualizationSettings->show3DHeadUpDisplay) ? 0xFFFFFFFF : 0;
285 : myHUD->setCullMask(hudCullMask);
286 436 : }
287 :
288 :
289 : Position
290 0 : GUIOSGView::getPositionInformation() const {
291 : Position pos;
292 0 : getPositionAtCursor(myOSGNormalizedCursorX, myOSGNormalizedCursorY, pos);
293 0 : return pos;
294 : }
295 :
296 :
297 : bool
298 0 : GUIOSGView::is3DView() const {
299 0 : return true;
300 : }
301 :
302 :
303 : void
304 436 : GUIOSGView::buildViewToolBars(GUIGlChildWindow* v) {
305 : // build coloring tools
306 : {
307 436 : const std::vector<std::string>& names = gSchemeStorage.getNames();
308 2616 : for (std::vector<std::string>::const_iterator i = names.begin(); i != names.end(); ++i) {
309 2180 : v->getColoringSchemesCombo()->appendIconItem(i->c_str());
310 2180 : if ((*i) == myVisualizationSettings->name) {
311 436 : v->getColoringSchemesCombo()->setCurrentItem(v->getColoringSchemesCombo()->getNumItems() - 1);
312 : }
313 : }
314 : }
315 : // for junctions
316 872 : GUIDesigns::buildFXButton(v->getLocatorPopup(),
317 : "Locate Junction", "Locate a junction within the network.", "",
318 : GUIIconSubSys::getIcon(GUIIcon::LOCATEJUNCTION), v, MID_HOTKEY_SHIFT_J_LOCATEJUNCTION,
319 : GUIDesignButtonPopup);
320 : // for edges
321 872 : GUIDesigns::buildFXButton(v->getLocatorPopup(),
322 : "Locate Street", "Locate a street within the network.", "",
323 : GUIIconSubSys::getIcon(GUIIcon::LOCATEEDGE), v, MID_HOTKEY_SHIFT_E_LOCATEEDGE,
324 : GUIDesignButtonPopup);
325 : // for vehicles
326 872 : GUIDesigns::buildFXButton(v->getLocatorPopup(),
327 : "Locate Vehicle", "Locate a vehicle within the network.", "",
328 : GUIIconSubSys::getIcon(GUIIcon::LOCATEVEHICLE), v, MID_HOTKEY_SHIFT_V_LOCATEVEHICLE,
329 : GUIDesignButtonPopup);
330 : // for persons
331 872 : GUIDesigns::buildFXButton(v->getLocatorPopup(),
332 : "Locate Person", "Locate a person within the network.", "",
333 : GUIIconSubSys::getIcon(GUIIcon::LOCATEPERSON), v, MID_HOTKEY_SHIFT_P_LOCATEPERSON,
334 : GUIDesignButtonPopup);
335 : // for containers
336 872 : GUIDesigns::buildFXButton(v->getLocatorPopup(),
337 : "Locate Container", "Locate a container within the network.", "",
338 : GUIIconSubSys::getIcon(GUIIcon::LOCATECONTAINER), v, MID_HOTKEY_SHIFT_C_LOCATECONTAINER,
339 : GUIDesignButtonPopup);
340 : // for tls
341 872 : GUIDesigns::buildFXButton(v->getLocatorPopup(),
342 : "Locate TLS", "Locate a tls within the network.", "",
343 : GUIIconSubSys::getIcon(GUIIcon::LOCATETLS), v, MID_HOTKEY_SHIFT_T_LOCATETLS,
344 : GUIDesignButtonPopup);
345 : // for additional stuff
346 872 : GUIDesigns::buildFXButton(v->getLocatorPopup(),
347 : "Locate Additional", "Locate an additional structure within the network.", "",
348 : GUIIconSubSys::getIcon(GUIIcon::LOCATEADD), v, MID_HOTKEY_SHIFT_A_LOCATEADDITIONAL,
349 : GUIDesignButtonPopup);
350 : // for pois
351 872 : GUIDesigns::buildFXButton(v->getLocatorPopup(),
352 : "Locate POI", "Locate a POI within the network.", "",
353 : GUIIconSubSys::getIcon(GUIIcon::LOCATEPOI), v, MID_HOTKEY_SHIFT_O_LOCATEPOI,
354 : GUIDesignButtonPopup);
355 : // for polygons
356 872 : GUIDesigns::buildFXButton(v->getLocatorPopup(),
357 : "Locate Polygon", "Locate a Polygon within the network.", "",
358 : GUIIconSubSys::getIcon(GUIIcon::LOCATEPOLY), v, MID_HOTKEY_SHIFT_L_LOCATEPOLY,
359 : GUIDesignButtonPopup);
360 436 : }
361 :
362 :
363 : void
364 0 : GUIOSGView::resize(int w, int h) {
365 0 : GUISUMOAbstractView::resize(w, h);
366 0 : updateHUDPosition(w, h);
367 0 : }
368 :
369 :
370 : void
371 360 : GUIOSGView::position(int x, int y, int w, int h) {
372 360 : GUISUMOAbstractView::position(x, y, w, h);
373 360 : updateHUDPosition(w, h);
374 360 : }
375 :
376 :
377 : void
378 720 : GUIOSGView::updateHUDPosition(int w, int h) {
379 : // keep the HUD text in the left top corner
380 720 : myHUD->setProjectionMatrixAsOrtho2D(0, w, 0, h);
381 720 : myText->setPosition(osg::Vec3d(0., static_cast<double>(height), 0.));
382 720 : }
383 :
384 :
385 : void
386 436 : GUIOSGView::updateHUDText(const std::string text) {
387 436 : myText->setText(text, osgText::String::ENCODING_UTF8);
388 436 : }
389 :
390 :
391 : void
392 436 : GUIOSGView::recenterView() {
393 436 : stopTrack();
394 436 : Position center = myGrid->getCenter();
395 436 : double radius = std::max(myGrid->xmax() - myGrid->xmin(), myGrid->ymax() - myGrid->ymin());
396 436 : myChanger->centerTo(center, radius);
397 436 : }
398 :
399 :
400 : bool
401 0 : GUIOSGView::setColorScheme(const std::string& name) {
402 0 : if (!gSchemeStorage.contains(name)) {
403 : return false;
404 : }
405 0 : if (myGUIDialogViewSettings != 0) {
406 0 : if (myGUIDialogViewSettings->getCurrentScheme() != name) {
407 0 : myGUIDialogViewSettings->setCurrentScheme(name);
408 : }
409 : }
410 0 : myVisualizationSettings = &gSchemeStorage.get(name.c_str());
411 0 : myVisualizationSettings->gaming = myApp->isGaming();
412 0 : adoptViewSettings();
413 0 : update();
414 0 : return true;
415 : }
416 :
417 :
418 : long
419 43504 : GUIOSGView::onPaint(FXObject*, FXSelector, void*) {
420 43504 : if (!isEnabled()) {
421 : return 1;
422 : }
423 43504 : myDecalsLockMutex.lock();
424 43504 : for (GUISUMOAbstractView::Decal& d : myDecals) {
425 0 : if (!d.initialised && d.filename.length() > 0) {
426 0 : if (d.filename.length() == 6 && d.filename.substr(0, 5) == "light") {
427 0 : GUIOSGBuilder::buildLight(d, *myRoot);
428 0 : } else if (d.filename.length() > 3 && d.filename.substr(0, 3) == "tl:") {
429 0 : const int linkStringIdx = (int)d.filename.find(':', 3);
430 0 : GUINet* net = (GUINet*) MSNet::getInstance();
431 : try {
432 0 : const std::string tlLogic = d.filename.substr(3, linkStringIdx - 3);
433 0 : MSTLLogicControl::TLSLogicVariants& vars = net->getTLSControl().get(tlLogic);
434 0 : const int linkIdx = StringUtils::toInt(d.filename.substr(linkStringIdx + 1));
435 0 : if (linkIdx < 0 || linkIdx >= static_cast<int>(vars.getActive()->getLinks().size())) {
436 0 : throw NumberFormatException("");
437 : }
438 0 : const MSLink* const link = vars.getActive()->getLinksAt(linkIdx)[0];
439 0 : osg::Group* tlNode = GUIOSGBuilder::getTrafficLight(d, vars, link, myGreenLight, myYellowLight, myRedLight, myRedYellowLight, myPoleBase, true, 0.5);
440 0 : tlNode->setName("tlLogic:" + tlLogic);
441 0 : myRoot->addChild(tlNode);
442 0 : } catch (NumberFormatException&) {
443 0 : WRITE_ERRORF(TL("Invalid link index in '%'."), d.filename);
444 0 : } catch (InvalidArgument&) {
445 0 : WRITE_ERRORF(TL("Unknown traffic light in '%'."), d.filename);
446 0 : }
447 : } else {
448 0 : GUIOSGBuilder::buildDecal(d, *myRoot);
449 : }
450 0 : d.initialised = true;
451 : }
452 : }
453 43504 : myDecalsLockMutex.unlock();
454 :
455 : // reset active flag
456 3692253 : for (auto& item : myVehicles) {
457 3648749 : item.second.active = false;
458 : }
459 :
460 43504 : GUINet* net = static_cast<GUINet*>(MSNet::getInstance());
461 : // build edges
462 881211 : for (const MSEdge* e : net->getEdgeControl().getEdges()) {
463 2002857 : for (const MSLane* l : e->getLanes()) {
464 1165150 : const MSLane::VehCont& vehicles = l->getVehiclesSecure();
465 4817019 : for (MSVehicle* msVeh : vehicles) {
466 : GUIVehicle* veh = static_cast<GUIVehicle*>(msVeh);
467 3651869 : if (!(veh->isOnRoad() || veh->isParking() || veh->wasRemoteControlled())) {
468 : continue;
469 : }
470 : auto itVeh = myVehicles.find(veh);
471 3651869 : if (itVeh == myVehicles.end()) {
472 33985 : myVehicles[veh] = GUIOSGBuilder::buildMovable(veh->getVehicleType());
473 33985 : myRoot->addChild(myVehicles[veh].pos);
474 33985 : myVehicles[veh].pos->setName("vehicle:" + veh->getID());
475 33985 : veh->setNode(myVehicles[veh].pos);
476 : } else {
477 3617884 : itVeh->second.active = true;
478 : }
479 3651869 : osg::PositionAttitudeTransform* n = myVehicles[veh].pos;
480 3651869 : n->setPosition(osg::Vec3d(veh->getPosition().x(), veh->getPosition().y(), veh->getPosition().z()));
481 3651869 : const double dir = veh->getAngle() + M_PI / 2.;
482 3651869 : const double slope = -veh->getSlope();
483 3651869 : n->setAttitude(osg::Quat(osg::DegreesToRadians(slope), osg::Vec3(1, 0, 0),
484 3651869 : 0, osg::Vec3(0, 1, 0),
485 3651869 : dir, osg::Vec3(0, 0, 1)));
486 : /*
487 : osg::ref_ptr<osg::AnimationPath> path = new osg::AnimationPath;
488 : // path->setLoopMode( osg::AnimationPath::NO_LOOPING );
489 : osg::AnimationPath::ControlPoint pointA(n->getPosition(), n->getAttitude());
490 : osg::AnimationPath::ControlPoint pointB(osg::Vec3(veh->getPosition().x(), veh->getPosition().y(), veh->getPosition().z()),
491 : osg::Quat(dir, osg::Vec3(0, 0, 1)) *
492 : osg::Quat(osg::DegreesToRadians(slope), osg::Vec3(0, 1, 0)));
493 : path->insert(0.0f, pointA);
494 : path->insert(0.5f, pointB);
495 : n->setUpdateCallback(new osg::AnimationPathCallback(path));
496 : */
497 :
498 3651869 : if (myVisualizationSettings->ignoreColorSchemeFor3DVehicles) {
499 0 : myVehicles[veh].activateMaterial(false);
500 : } else {
501 3651869 : myVehicles[veh].activateMaterial(true);
502 3651869 : RGBColor col;
503 3651869 : if (!GUIBaseVehicle::setFunctionalColor(myVisualizationSettings->vehicleColorer.getActive(), veh, col)) {
504 3645251 : col = myVisualizationSettings->vehicleColorer.getScheme().getColor(veh->getColorValue(*myVisualizationSettings, myVisualizationSettings->vehicleColorer.getActive()));
505 : }
506 3651869 : myVehicles[veh].mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4d(col.red() / 255., col.green() / 255., col.blue() / 255., col.alpha() / 255.));
507 : }
508 3651869 : myVehicles[veh].lights->setValue(0, veh->signalSet(MSVehicle::VEH_SIGNAL_BLINKER_RIGHT | MSVehicle::VEH_SIGNAL_BLINKER_EMERGENCY));
509 3651869 : myVehicles[veh].lights->setValue(1, veh->signalSet(MSVehicle::VEH_SIGNAL_BLINKER_LEFT | MSVehicle::VEH_SIGNAL_BLINKER_EMERGENCY));
510 3651869 : myVehicles[veh].lights->setValue(2, veh->signalSet(MSVehicle::VEH_SIGNAL_BRAKELIGHT));
511 : }
512 1165150 : l->releaseVehicles();
513 : }
514 : }
515 : // remove inactive
516 3726238 : for (auto veh = myVehicles.begin(); veh != myVehicles.end();) {
517 3682734 : if (!veh->second.active) {
518 31811 : removeVeh((veh++)->first);
519 : } else {
520 : ++veh;
521 : }
522 : }
523 :
524 43504 : const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
525 43504 : if (now != myLastUpdate || (myGUIDialogViewSettings != 0 && myGUIDialogViewSettings->shown())) {
526 19702 : GUINet::getGUIInstance()->updateColor(*myVisualizationSettings);
527 : }
528 43504 : if (now != myLastUpdate && myTracked != 0) {
529 : osg::Vec3d lookFrom, lookAt, up;
530 0 : lookAt[0] = myTracked->getPosition().x();
531 0 : lookAt[1] = myTracked->getPosition().y();
532 0 : lookAt[2] = myTracked->getPosition().z();
533 0 : const double angle = myTracked->getAngle();
534 0 : lookFrom[0] = lookAt[0] + 50. * cos(angle);
535 0 : lookFrom[1] = lookAt[1] + 50. * sin(angle);
536 0 : lookFrom[2] = lookAt[2] + 10.;
537 : osg::Matrix m;
538 0 : m.makeLookAt(lookFrom, lookAt, osg::Z_AXIS);
539 0 : myViewer->getCameraManipulator()->setByInverseMatrix(m);
540 : }
541 :
542 : // reset active flag
543 48951 : for (auto& item : myPersons) {
544 5447 : item.second.active = false;
545 : }
546 :
547 881211 : for (const MSEdge* e : net->getEdgeControl().getEdges()) {
548 : const GUIEdge* ge = static_cast<const GUIEdge*>(e);
549 : const std::set<MSTransportable*, ComparatorNumericalIdLess>& persons = ge->getPersonsSecure();
550 843309 : for (auto person : persons) {
551 5602 : if (person->hasArrived() || !person->hasDeparted()) {
552 : //std::cout << SIMTIME << " person " << person->getID() << " is loaded but arrived\n";
553 0 : continue;
554 : }
555 : auto itPers = myPersons.find(person);
556 5602 : if (itPers == myPersons.end()) {
557 518 : myPersons[person] = GUIOSGBuilder::buildMovable(person->getVehicleType());
558 518 : myRoot->addChild(myPersons[person].pos);
559 : } else {
560 5084 : itPers->second.active = true;
561 : }
562 5602 : osg::PositionAttitudeTransform* n = myPersons[person].pos;
563 5602 : const Position pos = person->getPosition();
564 : n->setPosition(osg::Vec3d(pos.x(), pos.y(), pos.z()));
565 5602 : const double dir = person->getAngle() + M_PI / 2.;
566 5602 : n->setAttitude(osg::Quat(dir, osg::Vec3d(0, 0, 1)));
567 :
568 5602 : RGBColor col;
569 5602 : GUIPerson* actualPerson = dynamic_cast<GUIPerson*>(person);
570 5602 : if (!GUIPerson::setFunctionalColor(myVisualizationSettings->personColorer.getActive(), actualPerson, col)) {
571 5498 : col = myVisualizationSettings->personColorer.getScheme().getColor(actualPerson->getColorValue(*myVisualizationSettings, myVisualizationSettings->vehicleColorer.getActive()));
572 : }
573 5602 : myPersons[person].mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4d(col.red() / 255., col.green() / 255., col.blue() / 255., col.alpha() / 255.));
574 : }
575 : ge->releasePersons();
576 : }
577 :
578 : // remove inactive
579 49469 : for (auto person = myPersons.begin(); person != myPersons.end();) {
580 5965 : if (!person->second.active) {
581 363 : removeTransportable((person++)->first);
582 : } else {
583 : ++person;
584 : }
585 : }
586 :
587 43504 : if (myAdapter->makeCurrent()) {
588 43504 : myViewer->frame();
589 43504 : makeNonCurrent();
590 : }
591 43504 : myLastUpdate = now;
592 43504 : return 1;
593 : }
594 :
595 :
596 : void
597 31811 : GUIOSGView::removeVeh(MSVehicle* veh) {
598 31811 : if (myTracked == veh) {
599 0 : stopTrack();
600 : }
601 : std::map<MSVehicle*, OSGMovable>::iterator i = myVehicles.find(veh);
602 31811 : if (i != myVehicles.end()) {
603 : myRoot->removeChild(i->second.pos);
604 : myVehicles.erase(i);
605 : }
606 31811 : }
607 :
608 :
609 : void
610 363 : GUIOSGView::removeTransportable(MSTransportable* t) {
611 : std::map<MSTransportable*, OSGMovable>::iterator i = myPersons.find(t);
612 363 : if (i != myPersons.end()) {
613 : myRoot->removeChild(i->second.pos);
614 : myPersons.erase(i);
615 : }
616 363 : }
617 :
618 :
619 0 : void GUIOSGView::updateViewportValues() {
620 : osg::Vec3d lookFrom, lookAt, up;
621 0 : myViewer->getCameraManipulator()->getInverseMatrix().getLookAt(lookFrom, lookAt, up);
622 0 : myGUIDialogEditViewport->setValues(Position(lookFrom[0], lookFrom[1], lookFrom[2]),
623 0 : Position(lookAt[0], lookAt[1], lookAt[2]), calculateRotation(lookFrom, lookAt, up));
624 0 : }
625 :
626 :
627 : void
628 0 : GUIOSGView::showViewportEditor() {
629 0 : getViewportEditor(); // make sure it exists;
630 : osg::Vec3d lookFrom, lookAt, up;
631 0 : myViewer->getCameraManipulator()->getInverseMatrix().getLookAt(lookFrom, lookAt, up);
632 0 : Position from(lookFrom[0], lookFrom[1], lookFrom[2]), at(lookAt[0], lookAt[1], lookAt[2]);
633 0 : myGUIDialogEditViewport->setOldValues(from, at, calculateRotation(lookFrom, lookAt, up));
634 0 : myGUIDialogEditViewport->setZoomValue(100);
635 0 : myGUIDialogEditViewport->show();
636 0 : }
637 :
638 :
639 : void
640 0 : GUIOSGView::setViewportFromToRot(const Position& lookFrom, const Position& lookAt, double rotation) {
641 : osg::Vec3d lookFromOSG, lookAtOSG, up;
642 0 : lookFromOSG[0] = lookFrom.x();
643 0 : lookFromOSG[1] = lookFrom.y();
644 0 : lookFromOSG[2] = lookFrom.z();
645 0 : lookAtOSG[0] = lookAt.x();
646 0 : lookAtOSG[1] = lookAt.y();
647 0 : lookAtOSG[2] = lookAt.z();
648 :
649 : osg::Vec3d viewAxis, viewUp, orthogonal, normal;
650 0 : viewAxis = lookFromOSG - lookAtOSG;
651 0 : viewAxis.normalize();
652 0 : viewUp = (viewAxis[0] + viewAxis[1] == 0.) ? osg::Vec3d(0., 1., 0.) : osg::Vec3d(0., 0., 1.); // check for parallel vectors
653 0 : orthogonal = viewUp ^ viewAxis;
654 0 : orthogonal.normalize();
655 : normal = viewAxis ^ orthogonal;
656 :
657 0 : rotation = std::fmod(rotation, 360.);
658 0 : if (rotation < 0) {
659 0 : rotation += 360.;
660 : }
661 0 : myChanger->setRotation(rotation);
662 0 : double angle = DEG2RAD(rotation);
663 0 : up = normal * cos(angle) - orthogonal * sin(angle);
664 0 : up.normalize();
665 :
666 0 : double zoom = (myGUIDialogEditViewport != nullptr) ? myGUIDialogEditViewport->getZoomValue() : 100.;
667 0 : lookFromOSG = lookFromOSG + viewAxis * (100. - zoom);
668 0 : lookAtOSG = lookFromOSG - viewAxis;
669 0 : myViewer->getCameraManipulator()->setHomePosition(lookFromOSG, lookAtOSG, up);
670 0 : myViewer->home();
671 0 : }
672 :
673 :
674 : void
675 0 : GUIOSGView::copyViewportTo(GUISUMOAbstractView* view) {
676 : osg::Vec3d lookFrom, lookAt, up;
677 0 : myViewer->getCameraManipulator()->getHomePosition(lookFrom, lookAt, up);
678 0 : view->setViewportFromToRot(Position(lookFrom[0], lookFrom[1], lookFrom[2]),
679 0 : Position(lookAt[0], lookAt[1], lookAt[2]), 0);
680 0 : }
681 :
682 :
683 : void
684 0 : GUIOSGView::startTrack(int id) {
685 0 : if (myTracked == 0 || (int)myTracked->getGlID() != id) {
686 0 : myTracked = 0;
687 0 : MSVehicleControl::constVehIt it = MSNet::getInstance()->getVehicleControl().loadedVehBegin();
688 0 : for (; it != MSNet::getInstance()->getVehicleControl().loadedVehEnd(); it++) {
689 0 : GUIVehicle* veh = (GUIVehicle*)(*it).second;
690 0 : if ((int)veh->getGlID() == id) {
691 0 : if (!veh->isOnRoad() || myVehicles.find(veh) == myVehicles.end()) {
692 : return;
693 : }
694 0 : myTracked = veh;
695 0 : break;
696 : }
697 : }
698 0 : if (myTracked != 0) {
699 : osg::Vec3d lookFrom, lookAt, up;
700 0 : lookAt[0] = myTracked->getPosition().x();
701 0 : lookAt[1] = myTracked->getPosition().y();
702 0 : lookAt[2] = myTracked->getPosition().z();
703 0 : lookFrom[0] = lookAt[0] + 50.;
704 0 : lookFrom[1] = lookAt[1] + 50.;
705 0 : lookFrom[2] = lookAt[2] + 10.;
706 : osg::Matrix m;
707 0 : m.makeLookAt(lookFrom, lookAt, osg::Z_AXIS);
708 0 : myViewer->getCameraManipulator()->setByInverseMatrix(m);
709 : }
710 : }
711 : }
712 :
713 :
714 : void
715 436 : GUIOSGView::stopTrack() {
716 436 : myTracked = 0;
717 436 : }
718 :
719 :
720 : GUIGlID
721 28840 : GUIOSGView::getTrackedID() const {
722 28840 : return myTracked == 0 ? GUIGlObject::INVALID_ID : myTracked->getGlID();
723 : }
724 :
725 :
726 : void
727 0 : GUIOSGView::onGamingClick(Position pos) {
728 0 : MSTLLogicControl& tlsControl = MSNet::getInstance()->getTLSControl();
729 : const MSTrafficLightLogic* minTll = nullptr;
730 : double minDist = std::numeric_limits<double>::infinity();
731 0 : for (const MSTrafficLightLogic* const tll : tlsControl.getAllLogics()) {
732 0 : if (tlsControl.isActive(tll)) {
733 : // get the links
734 : const MSTrafficLightLogic::LaneVector& lanes = tll->getLanesAt(0);
735 0 : if (lanes.size() > 0) {
736 0 : const Position& endPos = lanes[0]->getShape().back();
737 0 : if (endPos.distanceTo(pos) < minDist) {
738 0 : minDist = endPos.distanceTo(pos);
739 : minTll = tll;
740 : }
741 : }
742 : }
743 0 : }
744 0 : if (minTll != 0) {
745 0 : const MSTLLogicControl::TLSLogicVariants& vars = tlsControl.get(minTll->getID());
746 0 : const std::vector<MSTrafficLightLogic*> logics = vars.getAllLogics();
747 0 : if (logics.size() > 1) {
748 0 : MSSimpleTrafficLightLogic* l = (MSSimpleTrafficLightLogic*) logics[0];
749 0 : for (int i = 0; i < (int)logics.size() - 1; i++) {
750 0 : if (minTll->getProgramID() == logics[i]->getProgramID()) {
751 0 : l = (MSSimpleTrafficLightLogic*) logics[i + 1];
752 0 : tlsControl.switchTo(minTll->getID(), l->getProgramID());
753 : }
754 : }
755 0 : if (l == logics[0]) {
756 0 : tlsControl.switchTo(minTll->getID(), l->getProgramID());
757 : }
758 0 : l->changeStepAndDuration(tlsControl, MSNet::getInstance()->getCurrentTimeStep(), 0, l->getPhase(0).duration);
759 0 : update();
760 : }
761 0 : }
762 0 : }
763 :
764 :
765 : SUMOTime
766 326857 : GUIOSGView::getCurrentTimeStep() const {
767 326857 : return MSNet::getInstance()->getCurrentTimeStep();
768 : }
769 :
770 :
771 360 : long GUIOSGView::onConfigure(FXObject* sender, FXSelector sel, void* ptr) {
772 : // update the window dimensions, in case the window has been resized.
773 : const int w = getWidth();
774 : const int h = getHeight();
775 360 : if (w > 0 && h > 0) {
776 360 : myAdapter->getEventQueue()->windowResize(0, 0, w, h);
777 360 : myAdapter->resized(0, 0, w, h);
778 360 : updateHUDPosition(w, h);
779 : }
780 360 : return FXGLCanvas::onConfigure(sender, sel, ptr);
781 : }
782 :
783 :
784 0 : long GUIOSGView::onKeyPress(FXObject* sender, FXSelector sel, void* ptr) {
785 0 : int key = ((FXEvent*)ptr)->code;
786 0 : myAdapter->getEventQueue()->keyPress(key);
787 : // leave key handling for some cases to OSG
788 0 : if (key == FX::KEY_f || key == FX::KEY_Left || key == FX::KEY_Right || key == FX::KEY_Up || key == FX::KEY_Down) {
789 : return 1;
790 : }
791 0 : return FXGLCanvas::onKeyPress(sender, sel, ptr);
792 : }
793 :
794 :
795 0 : long GUIOSGView::onKeyRelease(FXObject* sender, FXSelector sel, void* ptr) {
796 0 : int key = ((FXEvent*)ptr)->code;
797 0 : myAdapter->getEventQueue()->keyRelease(key);
798 : // leave key handling for some cases to OSG
799 0 : if (key == FX::KEY_f || key == FX::KEY_Left || key == FX::KEY_Right || key == FX::KEY_Up || key == FX::KEY_Down) {
800 : return 1;
801 : }
802 0 : return FXGLCanvas::onKeyRelease(sender, sel, ptr);
803 : }
804 :
805 :
806 0 : long GUIOSGView::onLeftBtnPress(FXObject* sender, FXSelector sel, void* ptr) {
807 0 : handle(this, FXSEL(SEL_FOCUS_SELF, 0), ptr);
808 :
809 : FXEvent* event = (FXEvent*)ptr;
810 0 : myAdapter->getEventQueue()->mouseButtonPress((float)event->click_x, (float)event->click_y, 1);
811 0 : if (myApp->isGaming()) {
812 0 : onGamingClick(getPositionInformation());
813 : }
814 :
815 0 : return FXGLCanvas::onLeftBtnPress(sender, sel, ptr);
816 : }
817 :
818 :
819 0 : long GUIOSGView::onLeftBtnRelease(FXObject* sender, FXSelector sel, void* ptr) {
820 : FXEvent* event = (FXEvent*)ptr;
821 0 : myAdapter->getEventQueue()->mouseButtonRelease((float)event->click_x, (float)event->click_y, 1);
822 0 : myChanger->onLeftBtnRelease(ptr);
823 0 : return FXGLCanvas::onLeftBtnRelease(sender, sel, ptr);
824 : }
825 :
826 :
827 0 : long GUIOSGView::onMiddleBtnPress(FXObject* sender, FXSelector sel, void* ptr) {
828 0 : handle(this, FXSEL(SEL_FOCUS_SELF, 0), ptr);
829 :
830 : FXEvent* event = (FXEvent*)ptr;
831 0 : myAdapter->getEventQueue()->mouseButtonPress((float)event->click_x, (float)event->click_y, 2);
832 :
833 0 : return FXGLCanvas::onMiddleBtnPress(sender, sel, ptr);
834 : }
835 :
836 :
837 0 : long GUIOSGView::onMiddleBtnRelease(FXObject* sender, FXSelector sel, void* ptr) {
838 : FXEvent* event = (FXEvent*)ptr;
839 0 : myAdapter->getEventQueue()->mouseButtonRelease((float)event->click_x, (float)event->click_y, 2);
840 0 : myChanger->onMiddleBtnRelease(ptr);
841 0 : return FXGLCanvas::onMiddleBtnRelease(sender, sel, ptr);
842 : }
843 :
844 :
845 0 : long GUIOSGView::onRightBtnPress(FXObject* sender, FXSelector sel, void* ptr) {
846 0 : handle(this, FXSEL(SEL_FOCUS_SELF, 0), ptr);
847 :
848 : FXEvent* event = (FXEvent*)ptr;
849 0 : myAdapter->getEventQueue()->mouseButtonPress((float)event->click_x, (float)event->click_y, 3);
850 :
851 0 : return FXGLCanvas::onRightBtnPress(sender, sel, ptr);
852 : }
853 :
854 :
855 0 : long GUIOSGView::onRightBtnRelease(FXObject* sender, FXSelector sel, void* ptr) {
856 : FXEvent* event = (FXEvent*)ptr;
857 0 : myAdapter->getEventQueue()->mouseButtonRelease((float)event->click_x, (float)event->click_y, 3);
858 0 : myChanger->onRightBtnRelease(ptr);
859 0 : return FXGLCanvas::onRightBtnRelease(sender, sel, ptr);
860 : }
861 :
862 :
863 : long
864 0 : GUIOSGView::onMouseMove(FXObject* sender, FXSelector sel, void* ptr) {
865 : // if popup exist but isn't shown, destroy it first
866 0 : if (myPopup && !myPopup->shown()) {
867 0 : destroyPopup();
868 : }
869 :
870 : FXEvent* event = (FXEvent*)ptr;
871 0 : osgGA::GUIEventAdapter* ea = myAdapter->getEventQueue()->mouseMotion((float)event->win_x, (float)event->win_y);
872 0 : setWindowCursorPosition(ea->getXnormalized(), ea->getYnormalized());
873 0 : if (myGUIDialogEditViewport != nullptr && myGUIDialogEditViewport->shown()) {
874 0 : updateViewportValues();
875 : }
876 0 : updatePositionInformation();
877 0 : return FXGLCanvas::onMotion(sender, sel, ptr);
878 : }
879 :
880 :
881 : long
882 23177 : GUIOSGView::onIdle(FXObject* /* sender */, FXSelector /* sel */, void*) {
883 23177 : forceRefresh();
884 23177 : update();
885 23177 : getApp()->addChore(this, MID_CHORE);
886 23177 : return 1;
887 : }
888 :
889 :
890 : long
891 0 : GUIOSGView::onCmdCloseLane(FXObject*, FXSelector, void*) {
892 0 : GUILane* lane = getLaneUnderCursor();
893 0 : if (lane != nullptr) {
894 0 : lane->closeTraffic();
895 0 : GUIGlObjectStorage::gIDStorage.unblockObject(lane->getGlID());
896 0 : GUINet::getGUIInstance()->updateColor(*myVisualizationSettings);
897 0 : update();
898 : }
899 0 : return 1;
900 : }
901 :
902 :
903 : long
904 0 : GUIOSGView::onCmdCloseEdge(FXObject*, FXSelector, void*) {
905 0 : GUILane* lane = getLaneUnderCursor();
906 0 : if (lane != nullptr) {
907 0 : dynamic_cast<GUIEdge*>(&lane->getEdge())->closeTraffic(lane);
908 0 : GUIGlObjectStorage::gIDStorage.unblockObject(lane->getGlID());
909 0 : GUINet::getGUIInstance()->updateColor(*myVisualizationSettings);
910 0 : update();
911 : }
912 0 : return 1;
913 : }
914 :
915 :
916 : long
917 0 : GUIOSGView::onCmdAddRerouter(FXObject*, FXSelector, void*) {
918 0 : GUILane* lane = getLaneUnderCursor();
919 0 : if (lane != nullptr) {
920 0 : dynamic_cast<GUIEdge*>(&lane->getEdge())->addRerouter();
921 0 : GUIGlObjectStorage::gIDStorage.unblockObject(lane->getGlID());
922 0 : update();
923 : }
924 0 : return 1;
925 : }
926 :
927 :
928 : long
929 0 : GUIOSGView::onCmdShowReachability(FXObject* menu, FXSelector selector, void*) {
930 0 : GUILane* lane = getLaneUnderCursor();
931 0 : if (lane != nullptr) {
932 : // reset
933 0 : GUIViewTraffic::showLaneReachability(lane, menu, selector);
934 : // switch to 'color by selection' unless coloring 'by reachability'
935 0 : if (myVisualizationSettings->laneColorer.getActive() != 36) {
936 : myVisualizationSettings->laneColorer.setActive(1);
937 0 : GUINet::getGUIInstance()->updateColor(*myVisualizationSettings);
938 : }
939 0 : update();
940 : }
941 0 : return 1;
942 : }
943 :
944 :
945 : long
946 0 : GUIOSGView::onVisualizationChange(FXObject*, FXSelector, void*) {
947 0 : adoptViewSettings();
948 0 : return 1;
949 : }
950 :
951 :
952 : void
953 0 : GUIOSGView::setWindowCursorPosition(float x, float y) {
954 0 : myOSGNormalizedCursorX = x;
955 0 : myOSGNormalizedCursorY = y;
956 0 : }
957 :
958 :
959 : double
960 0 : GUIOSGView::calculateRotation(const osg::Vec3d& lookFrom, const osg::Vec3d& lookAt, const osg::Vec3d& up) {
961 : osg::Vec3d viewAxis, viewUp, orthogonal, normal;
962 0 : viewAxis = lookFrom - lookAt;
963 0 : viewAxis.normalize();
964 0 : viewUp = (abs(viewAxis[0]) + abs(viewAxis[1]) == 0.) ? osg::Y_AXIS : osg::Z_AXIS; // check for parallel vectors
965 0 : orthogonal = viewUp ^ viewAxis;
966 0 : orthogonal.normalize();
967 : normal = viewAxis ^ orthogonal;
968 0 : double angle = atan2((normal ^ up).length() / (normal.length() * up.length()), (normal * up) / (normal.length() * up.length()));
969 0 : if (angle < 0) {
970 0 : angle += M_PI;
971 : }
972 0 : return RAD2DEG(angle);
973 : }
974 :
975 :
976 : void
977 0 : GUIOSGView::updatePositionInformation() const {
978 : Position pos;
979 0 : if (getPositionAtCursor(myOSGNormalizedCursorX, myOSGNormalizedCursorY, pos)) {
980 0 : myApp->getCartesianLabel()->setText(("x:" + toString(pos.x()) + ", y:" + toString(pos.y())).c_str());
981 : // set geo position
982 0 : GeoConvHelper::getFinal().cartesian2geo(pos);
983 0 : if (GeoConvHelper::getFinal().usingGeoProjection()) {
984 0 : myApp->getGeoLabel()->setText(("lat:" + toString(pos.y(), gPrecisionGeo) + ", lon:" + toString(pos.x(), gPrecisionGeo)).c_str());
985 : } else {
986 0 : myApp->getGeoLabel()->setText(TL("(No projection defined)"));
987 : }
988 : } else {
989 : // set placeholder
990 0 : myApp->getCartesianLabel()->setText(TL("N/A"));
991 0 : myApp->getGeoLabel()->setText(TL("N/A"));
992 : }
993 0 : }
994 :
995 :
996 : bool
997 0 : GUIOSGView::getPositionAtCursor(float xNorm, float yNorm, Position& pos) const {
998 : // only reasonable if view axis points to the ground (not parallel to the ground or in the sky)
999 : osg::Vec3d lookFrom, lookAt, up, viewAxis;
1000 0 : myViewer->getCameraManipulator()->getInverseMatrix().getLookAt(lookFrom, lookAt, up);
1001 0 : if ((lookAt - lookFrom).z() >= 0.) {
1002 : // looking to the sky makes position at ground pointless
1003 : return false;
1004 : }
1005 : // solve linear equation of ray crossing the ground plane
1006 0 : osg::Matrixd iVP = osg::Matrixd::inverse(myViewer->getCamera()->getViewMatrix() * myViewer->getCamera()->getProjectionMatrix());
1007 0 : osg::Vec3 nearPoint = osg::Vec3(xNorm, yNorm, 0.0f) * iVP;
1008 0 : osg::Vec3 farPoint = osg::Vec3(xNorm, yNorm, 1.0f) * iVP;
1009 : osg::Vec3 ray = farPoint - nearPoint;
1010 : osg::Vec3 groundPos = nearPoint - ray * nearPoint.z() / ray.z();
1011 0 : pos.setx(groundPos.x());
1012 0 : pos.sety(groundPos.y());
1013 : pos.setz(0.);
1014 : return true;
1015 : }
1016 :
1017 :
1018 : std::vector<GUIGlObject*>
1019 0 : GUIOSGView::getGUIGlObjectsUnderCursor() {
1020 : std::vector<GUIGlObject*> result;
1021 : osgUtil::LineSegmentIntersector::Intersections intersections;
1022 0 : if (myViewer->computeIntersections(myViewer->getCamera(), osgUtil::Intersector::CoordinateFrame::PROJECTION, myOSGNormalizedCursorX, myOSGNormalizedCursorY, intersections)) {
1023 0 : for (auto intersection : intersections) {
1024 0 : if (!intersection.nodePath.empty()) {
1025 : // the object is identified by the ID stored in OSG
1026 0 : for (osg::Node* currentNode : intersection.nodePath) {
1027 0 : if (currentNode->getName().length() > 0 && currentNode->getName().find(":") != std::string::npos) {
1028 : const std::string objID = currentNode->getName();
1029 0 : GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(objID);
1030 : // check that GUIGlObject exist
1031 0 : if (o == nullptr) {
1032 0 : continue;
1033 : }
1034 : // check that GUIGlObject isn't the network
1035 0 : if (o->getGlID() == 0) {
1036 0 : continue;
1037 : }
1038 0 : result.push_back(o);
1039 : // unblock object
1040 0 : GUIGlObjectStorage::gIDStorage.unblockObject(o->getGlID());
1041 : }
1042 : }
1043 : }
1044 0 : }
1045 : }
1046 0 : return result;
1047 0 : }
1048 :
1049 :
1050 : GUILane*
1051 0 : GUIOSGView::getLaneUnderCursor() {
1052 0 : std::vector<GUIGlObject*> objects = getGUIGlObjectsUnderCursor();
1053 0 : if (objects.size() > 0) {
1054 0 : return dynamic_cast<GUILane*>(objects[0]);
1055 : }
1056 : return nullptr;
1057 0 : }
1058 :
1059 :
1060 : void
1061 0 : GUIOSGView::zoom2Pos(Position& camera, Position& lookAt, double zoom) {
1062 : osg::Vec3d lookFromOSG, lookAtOSG, viewAxis, up;
1063 0 : myViewer->getCameraManipulator()->getInverseMatrix().getLookAt(lookFromOSG, lookAtOSG, up);
1064 0 : lookFromOSG[0] = camera.x();
1065 0 : lookFromOSG[1] = camera.y();
1066 0 : lookFromOSG[2] = camera.z();
1067 0 : lookAtOSG[0] = lookAt.x();
1068 0 : lookAtOSG[1] = lookAt.y();
1069 0 : lookAtOSG[2] = lookAt.z();
1070 0 : viewAxis = lookAtOSG - lookFromOSG;
1071 0 : viewAxis.normalize();
1072 :
1073 : // compute new camera and lookAt pos
1074 0 : osg::Vec3d cameraUpdate = lookFromOSG + viewAxis * (zoom - 100.);
1075 : osg::Vec3d lookAtUpdate = cameraUpdate + viewAxis;
1076 :
1077 0 : myViewer->getCameraManipulator()->setHomePosition(cameraUpdate, lookAtUpdate, up);
1078 0 : myViewer->home();
1079 0 : }
1080 :
1081 :
1082 : osg::Vec4d
1083 1308 : GUIOSGView::toOSGColorVector(RGBColor c, bool useAlpha) {
1084 1308 : return osg::Vec4d(c.red() / 255., c.green() / 255., c.blue() / 255., (useAlpha) ? c.alpha() / 255. : 1.);
1085 : }
1086 :
1087 :
1088 436 : GUIOSGView::FXOSGAdapter::FXOSGAdapter(GUISUMOAbstractView* parent, FXCursor* cursor)
1089 436 : : myParent(parent), myOldCursor(cursor) {
1090 436 : _traits = new GraphicsContext::Traits();
1091 436 : _traits->x = 0;
1092 436 : _traits->y = 0;
1093 436 : _traits->width = parent->getWidth();
1094 436 : _traits->height = parent->getHeight();
1095 436 : _traits->windowDecoration = false;
1096 436 : _traits->doubleBuffer = true;
1097 436 : _traits->sharedContext = 0;
1098 : if (valid()) {
1099 436 : setState(new osg::State());
1100 436 : getState()->setGraphicsContext(this);
1101 : #ifdef DEBUG_GLERRORS
1102 : getState()->setCheckForGLErrors(osg::State::ONCE_PER_ATTRIBUTE);
1103 : std::cout << "OSG getCheckForGLErrors " << getState()->getCheckForGLErrors() << std::endl;
1104 : #endif
1105 436 : if (_traits.valid() && _traits->sharedContext != 0) {
1106 : getState()->setContextID(_traits->sharedContext->getState()->getContextID());
1107 0 : incrementContextIDUsageCount(getState()->getContextID());
1108 : } else {
1109 436 : getState()->setContextID(createNewContextID());
1110 : }
1111 : }
1112 436 : }
1113 :
1114 :
1115 872 : GUIOSGView::FXOSGAdapter::~FXOSGAdapter() {
1116 436 : delete myOldCursor;
1117 872 : }
1118 :
1119 :
1120 : void
1121 0 : GUIOSGView::FXOSGAdapter::grabFocus() {
1122 : // focus this window
1123 0 : myParent->setFocus();
1124 0 : }
1125 :
1126 :
1127 : void
1128 0 : GUIOSGView::FXOSGAdapter::useCursor(bool cursorOn) {
1129 0 : if (cursorOn) {
1130 0 : myParent->setDefaultCursor(myOldCursor);
1131 : } else {
1132 0 : myParent->setDefaultCursor(NULL);
1133 : }
1134 0 : }
1135 :
1136 :
1137 : bool
1138 87444 : GUIOSGView::FXOSGAdapter::makeCurrentImplementation() {
1139 87444 : myParent->makeCurrent();
1140 87444 : return true;
1141 : }
1142 :
1143 :
1144 : bool
1145 0 : GUIOSGView::FXOSGAdapter::releaseContext() {
1146 0 : myParent->makeNonCurrent();
1147 0 : return true;
1148 : }
1149 :
1150 :
1151 : void
1152 43504 : GUIOSGView::FXOSGAdapter::swapBuffersImplementation() {
1153 43504 : myParent->swapBuffers();
1154 43504 : }
1155 :
1156 :
1157 : bool
1158 43862 : GUIOSGView::PickHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& /* aa */) {
1159 43862 : if (ea.getEventType() == osgGA::GUIEventAdapter::DRAG) {
1160 0 : myDrag = true;
1161 43862 : } else if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && ea.getButton() == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) {
1162 0 : if (!myDrag) {
1163 0 : if (myParent->makeCurrent()) {
1164 0 : std::vector<GUIGlObject*> objects = myParent->getGUIGlObjectsUnderCursor();
1165 0 : if (objects.size() > 0) {
1166 0 : myParent->openObjectDialog(objects);
1167 : }
1168 0 : myParent->makeNonCurrent();
1169 0 : }
1170 : }
1171 0 : myDrag = false;
1172 : }
1173 43862 : return false;
1174 : }
1175 :
1176 :
1177 : #endif
1178 :
1179 : /****************************************************************************/
|