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