From 196192cdfe7f530dd9499b6822391f1a2aaea8a9 Mon Sep 17 00:00:00 2001 From: "esrafilian.omid" Date: Fri, 9 Feb 2024 23:53:17 +0100 Subject: [PATCH] 3D View new changes: OSM file is not mondatory, docs updated, using flickable for 3D Settings, using Loader for Viewer3DManager, touchscreen added --- docs/assets/viewer_3d/open_3d_viewer.jpg | Bin 0 -> 22187 bytes docs/en/qgc-user-guide/viewer_3d/viewer_3d.md | 21 +- src/Viewer3D/CityMapGeometry.cc | 35 +-- src/Viewer3D/CityMapGeometry.h | 5 +- src/Viewer3D/OsmParser.cc | 4 +- src/Viewer3D/OsmParser.h | 2 +- .../Viewer3D/Models3D/CameraLightModel.qml | 6 +- .../Viewer3D/Models3D/Viewer3DModel.qml | 179 +++++++++---- src/Viewer3D/Viewer3D/Viewer3D.qml | 31 ++- src/Viewer3D/Viewer3D/Viewer3DSettingMenu.qml | 249 +++++++++--------- src/Viewer3D/Viewer3DQmlBackend.cc | 45 +++- src/Viewer3D/Viewer3DQmlBackend.h | 7 +- 12 files changed, 369 insertions(+), 215 deletions(-) create mode 100644 docs/assets/viewer_3d/open_3d_viewer.jpg diff --git a/docs/assets/viewer_3d/open_3d_viewer.jpg b/docs/assets/viewer_3d/open_3d_viewer.jpg new file mode 100644 index 0000000000000000000000000000000000000000..16569ab636a36ef7ffe12b770d12d789f883f157 GIT binary patch literal 22187 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 + return true; +} - if(_mapLoadedFlag == 0){ - _osmParser->parseOsmFile(_osmFilePath); - _mapLoadedFlag = 1; +void CityMapGeometry::updateViewer() +{ + clear(); + + if(!_osmParser){ + return; } - if(_mapLoadedFlag){ + if(loadOsmMap()){ _vertexData = _osmParser->buildingToMesh(); int stride = 3 * sizeof(float); @@ -72,7 +78,6 @@ void CityMapGeometry::updateData() addAttribute(QQuick3DGeometry::Attribute::PositionSemantic, 0, QQuick3DGeometry::Attribute::F32Type); - } update(); } diff --git a/src/Viewer3D/CityMapGeometry.h b/src/Viewer3D/CityMapGeometry.h index b549c94eff2..f0c8f3cd81f 100644 --- a/src/Viewer3D/CityMapGeometry.h +++ b/src/Viewer3D/CityMapGeometry.h @@ -29,14 +29,15 @@ class CityMapGeometry : public QQuick3DGeometry OsmParser* osmParser(){ return _osmParser;} void setOsmParser(OsmParser* newOsmParser); + bool loadOsmMap(); + signals: void modelNameChanged(); void osmFilePathChanged(); - void gpsRefChanged(); void osmParserChanged(); private: - void updateData(); + void updateViewer(); QString _modelName; QString _osmFilePath; diff --git a/src/Viewer3D/OsmParser.cc b/src/Viewer3D/OsmParser.cc index 46fbcd0f771..014ca5442d8 100644 --- a/src/Viewer3D/OsmParser.cc +++ b/src/Viewer3D/OsmParser.cc @@ -69,8 +69,8 @@ void OsmParser::parseOsmFile(QString filePath) component = component.nextSibling().toElement(); } _mapLoadedFlag = true; - emit newMapLoaded(); - qDebug() << _mapBuildings.size() << " Buildings added to the 3D viewer!!!"; + emit mapChanged(); + qDebug() << _mapBuildings.size() << " Buildings loaded!!!"; } void OsmParser::decodeNodeTags(QDomElement &xmlComponent, QMap &nodeMap) diff --git a/src/Viewer3D/OsmParser.h b/src/Viewer3D/OsmParser.h index 77ee0eba26d..0c101afeab7 100644 --- a/src/Viewer3D/OsmParser.h +++ b/src/Viewer3D/OsmParser.h @@ -57,7 +57,7 @@ class OsmParser : public QObject signals: void gpsRefChanged(QGeoCoordinate newGpsRef); - void newMapLoaded(); + void mapChanged(); void buildingLevelHeightChanged(void); }; diff --git a/src/Viewer3D/Viewer3D/Models3D/CameraLightModel.qml b/src/Viewer3D/Viewer3D/Models3D/CameraLightModel.qml index e0cc6b8bd65..ef3ba0bb90d 100644 --- a/src/Viewer3D/Viewer3D/Models3D/CameraLightModel.qml +++ b/src/Viewer3D/Viewer3D/Models3D/CameraLightModel.qml @@ -11,7 +11,7 @@ Node { property real _tilt: 0.001 property real _pan: 0.001 - property real _zoom: 1000 + property real _zoom: 1500 DirectionalLight { @@ -58,6 +58,10 @@ Node { id: cameraPerspectiveOne + eulerRotation{ + x: -90 + } + } } } diff --git a/src/Viewer3D/Viewer3D/Models3D/Viewer3DModel.qml b/src/Viewer3D/Viewer3D/Models3D/Viewer3DModel.qml index a989329d325..597841a0976 100644 --- a/src/Viewer3D/Viewer3D/Models3D/Viewer3DModel.qml +++ b/src/Viewer3D/Viewer3D/Models3D/Viewer3DModel.qml @@ -21,7 +21,54 @@ import QGroundControl.Vehicle View3D { id: topView property var viewer3DManager: null + property bool viewer3DOpen: false + property real rotationSpeed: 0.1 + property real movementSpeed: 1 + property real zoomSpeed: 0.3 + function rotateCamera(newPose: vector2d, lastPose: vector2d) { + let rotation_vec = Qt.vector2d(newPose.y - lastPose.y, newPose.x - lastPose.x); + + let dx_l = rotation_vec.x * rotationSpeed + let dy_l = rotation_vec.y * rotationSpeed + + standAloneScene.cameraOneRotation.x += dx_l + standAloneScene.cameraOneRotation.y += dy_l + } + + function moveCamera(newPose: vector2d, lastPose: vector2d) { + let _roll = standAloneScene.cameraOneRotation.x * (3.1415/180) + let _pitch = standAloneScene.cameraOneRotation.y * (3.1415/180) + + let dx_l = (newPose.x - lastPose.x) * movementSpeed + let dy_l = (newPose.y - lastPose.y) * movementSpeed + + //Note: Rotation Matrix is computed as: R = R(-_pitch) * R(_roll) + // Then the corerxt tramslation is: d = R * [dx_l; dy_l; dz_l] + + let dx = dx_l * Math.cos(_pitch) - dy_l * Math.sin(_pitch) * Math.sin(_roll) + let dy = dy_l * Math.cos(_roll) + let dz = dx_l * Math.sin(_pitch) + dy_l * Math.cos(_pitch) * Math.sin(_roll) + + standAloneScene.cameraTwoPosition.x -= dx + standAloneScene.cameraTwoPosition.y += dy + standAloneScene.cameraTwoPosition.z += dz + } + + function zoomCamera(zoomValue){ + let dz_l = zoomValue * zoomSpeed; + + let _roll = standAloneScene.cameraOneRotation.x * (3.1415/180) + let _pitch = standAloneScene.cameraOneRotation.y * (3.1415/180) + + let dx = -dz_l * Math.cos(_roll) * Math.sin(_pitch) + let dy = -dz_l * Math.sin(_roll) + let dz = dz_l * Math.cos(_pitch) * Math.cos(_roll) + + standAloneScene.cameraTwoPosition.x -= dx + standAloneScene.cameraTwoPosition.y += dy + standAloneScene.cameraTwoPosition.z += dz + } camera: standAloneScene.cameraOne importScene: CameraLightModel{ @@ -31,7 +78,7 @@ View3D { // renderMode: View3D.Inline environment: SceneEnvironment { - clearColor: "white" + clearColor: "#F9F9F9" backgroundMode: SceneEnvironment.Color } @@ -78,66 +125,102 @@ View3D { vehicle3DLoader.sourceComponent = vehicle3DComponent } - MouseArea{ - property real _transferSpeed: 1 - property real _rotationSpeed: 0.1 - property real _zoomSpeed: 0.3 + DragHandler { + property bool _isMoving: false property point _lastPose; - anchors.fill: parent - acceptedButtons: Qt.AllButtons; - - - onPressed: (mouse)=> { - _lastPose = Qt.point(mouse.x, mouse.y); - } - - onPositionChanged: (mouse)=> { - let _roll = standAloneScene.cameraOneRotation.x * (3.1415/180) - let _pitch = standAloneScene.cameraOneRotation.y * (3.1415/180) - // let yaw = standAloneScene.cameraOneRotation.z * (3.1415/180) - - if (mouse.buttons === Qt.LeftButton) { // Left button for translate - let dx_l = (mouse.x - _lastPose.x) * _transferSpeed - let dy_l = (mouse.y - _lastPose.y) * _transferSpeed + id: cameraMovementDragHandler + target: null + acceptedModifiers: Qt.NoModifier + acceptedButtons: Qt.LeftButton + enabled: viewer3DOpen - //Note: Rotation Matrix is computed as: R = R(-_pitch) * R(_roll) - // Then the corerxt tramslation is: d = R * [dx_l; dy_l; dz_l] + onCentroidChanged: { + if(_isMoving){ + moveCamera(centroid.position, _lastPose); + _lastPose = Qt.point(centroid.position.x, centroid.position.y); + } + } - let dx = dx_l * Math.cos(_pitch) - dy_l * Math.sin(_pitch) * Math.sin(_roll) - let dy = dy_l * Math.cos(_roll) - let dz = dx_l * Math.sin(_pitch) + dy_l * Math.cos(_pitch) * Math.sin(_roll) + onActiveChanged: { + if(active){ // When mouse is pressed + _lastPose = Qt.point(centroid.position.x, centroid.position.y); + _isMoving = true + }else{ // When mouse is released + _isMoving = false + } + } + } - standAloneScene.cameraTwoPosition.x -= dx - standAloneScene.cameraTwoPosition.y += dy - standAloneScene.cameraTwoPosition.z += dz - }else if (mouse.buttons === Qt.RightButton){ // Right button for rotation + DragHandler { + property bool _isRotating: false + property point _lastPose; - let rotation_vec = Qt.vector2d(mouse.y - _lastPose.y, mouse.x - _lastPose.x); + id: cameraRotationDragHandler + target: null + acceptedModifiers: Qt.NoModifier + acceptedButtons: Qt.RightButton + acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad + enabled: viewer3DOpen + + onCentroidChanged: { + if(_isRotating){ + rotateCamera(centroid.position, _lastPose); + _lastPose = Qt.point(centroid.position.x, centroid.position.y); + } + } - let dx_l = rotation_vec.x * _rotationSpeed - let dy_l = rotation_vec.y * _rotationSpeed + onActiveChanged: { + if(active){ // When mouse is pressed + _lastPose = Qt.point(centroid.position.x, centroid.position.y); + _isRotating = true + }else{// When mouse is released + _isRotating = false + } + } + } - standAloneScene.cameraOneRotation.x += dx_l - standAloneScene.cameraOneRotation.y += dy_l + PinchHandler { + id: zoomRotationPinchHandler + target: null - } - _lastPose = Qt.point(mouse.x, mouse.y) - } + property bool _isRotating: false + property point _lastPose; + property real _lastZoomValue; + enabled: viewer3DOpen - onWheel: (wheel)=> { - let dz_l = -wheel.angleDelta.y * _zoomSpeed + onCentroidChanged: { + if(_isRotating){ + rotateCamera(centroid.position, _lastPose); + _lastPose = Qt.point(centroid.position.x, centroid.position.y); + } + } - let _roll = standAloneScene.cameraOneRotation.x * (3.1415/180) - let _pitch = standAloneScene.cameraOneRotation.y * (3.1415/180) + onActiveChanged: { + if (active) { + _lastPose = Qt.point(centroid.position.x, centroid.position.y); + _lastZoomValue = 0 + _isRotating = true; + } else { + _isRotating = false; + } + } + onActiveScaleChanged: { + let zoomValue = (activeScale > 1)?(activeScale - 1):(-((1/activeScale) - 1)) + zoomCamera(- 1000 * (zoomValue - _lastZoomValue)) + _lastZoomValue = zoomValue + } + } - let dx = -dz_l * Math.cos(_roll) * Math.sin(_pitch) - let dy = -dz_l * Math.sin(_roll) - let dz = dz_l * Math.cos(_pitch) * Math.cos(_roll) + WheelHandler { + id: wheelHandler + orientation: Qt.Vertical + target: null + acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad + enabled: viewer3DOpen - standAloneScene.cameraTwoPosition.x -= dx - standAloneScene.cameraTwoPosition.y += dy - standAloneScene.cameraTwoPosition.z += dz + onWheel: event => { + zoomCamera(-event.angleDelta.y) } } } diff --git a/src/Viewer3D/Viewer3D/Viewer3D.qml b/src/Viewer3D/Viewer3D/Viewer3D.qml index 309742dcb84..4c5fbe019f9 100644 --- a/src/Viewer3D/Viewer3D/Viewer3D.qml +++ b/src/Viewer3D/Viewer3D/Viewer3D.qml @@ -17,8 +17,20 @@ Item{ property bool viewer3DOpen: false property bool settingMenuOpen: false - Viewer3DManager{ - id: _viewer3DManager + Component{ + id: viewer3DManagerComponent + + Viewer3DManager{ + id: _viewer3DManager + } + } + + Loader{ + id: view3DManagerLoader + + onLoaded: { + view3DLoader.source = "Models3D/Viewer3DModel.qml" + } } Loader{ @@ -26,12 +38,19 @@ Item{ anchors.fill: parent onLoaded: { - item.viewer3DManager = _viewer3DManager + item.viewer3DManager = view3DManagerLoader.item } } + Binding{ + target: view3DLoader.item + property: "viewer3DOpen" + value: viewer3DOpen + when: view3DLoader.status == Loader.Ready + } + onViewer3DOpenChanged: { - view3DLoader.source = "Models3D/Viewer3DModel.qml" + view3DManagerLoader.sourceComponent = viewer3DManagerComponent if(viewer3DOpen){ viewer3DBody.z = 1 }else{ @@ -50,12 +69,12 @@ Item{ QGCPopupDialog{ id: settingMenuDialog - title: qsTr("3D view setting") + title: qsTr("3D view settings") buttons: Dialog.Ok | Dialog.Cancel Viewer3DSettingMenu{ id: viewer3DSettingMenu - viewer3DManager: _viewer3DManager + viewer3DManager: view3DManagerLoader.item visible: true } diff --git a/src/Viewer3D/Viewer3D/Viewer3DSettingMenu.qml b/src/Viewer3D/Viewer3D/Viewer3DSettingMenu.qml index dac15666fd8..24130aebd4c 100644 --- a/src/Viewer3D/Viewer3D/Viewer3DSettingMenu.qml +++ b/src/Viewer3D/Viewer3D/Viewer3DSettingMenu.qml @@ -11,7 +11,7 @@ import QGroundControl.Viewer3D /// @author Omid Esrafilian -Rectangle { +Flickable { signal menuClosed(bool accept) @@ -20,139 +20,132 @@ Rectangle { id: window_body clip: true - color: qgcPal.window visible: true width: Screen.width * 0.25 - height: Screen.width * 0.15 - - QGCPalette { - id: qgcPal - colorGroupEnabled: enabled - } - - QGCLabel { - id: map_file_label - Layout.fillWidth: true - wrapMode: Text.WordWrap - visible: true - text: qsTr("3D Map File:") - anchors.left: parent.left - anchors.top: parent.top - anchors.leftMargin: leftMarginSpace - anchors.topMargin: ScreenTools.defaultFontPixelWidth * 3 - } - - QGCButton { - id: map_file_btn - anchors.right: map_file_text_feild.right - anchors.top: map_file_text_feild.bottom - anchors.topMargin: ScreenTools.defaultFontPixelWidth * 2 - anchors.rightMargin: ScreenTools.defaultFontPixelWidth - - visible: true - text: qsTr("Select File") - - onClicked: { - fileDialog.openForLoad() - } - - QGCFileDialog { - id: fileDialog - - nameFilters: [qsTr("OpenStreetMap files (*.osm)")] - title: qsTr("Select map file") - onAcceptedForLoad: (file) => { - map_file_text_feild.text = file - } - } - } - - QGCTextField { - id: map_file_text_feild - height: ScreenTools.defaultFontPixelWidth * 4.5 - unitsLabel: "" - showUnits: false - visible: true - - anchors.verticalCenter: map_file_label.verticalCenter - anchors.right: parent.right - anchors.left: map_file_label.right - anchors.rightMargin: 20 - anchors.leftMargin: 20 - readOnly: true - - text: (viewer3DManager)?(viewer3DManager.viewer3DSetting.osmFilePath.rawValue):("nan") - } - - QGCLabel { - id: bld_level_height - Layout.fillWidth: true - wrapMode: Text.WordWrap - visible: true - text: qsTr("Average Building Level Height:") - anchors.left: parent.left - anchors.top: map_file_btn.bottom - anchors.leftMargin: leftMarginSpace - anchors.topMargin: ScreenTools.defaultFontPixelWidth * 2 - } - - QGCTextField { - id: bld_level_height_textfeild - width: ScreenTools.defaultFontPixelWidth * 15 - unitsLabel: "m" - showUnits: true - numericValuesOnly: true - visible: true - - anchors.verticalCenter: bld_level_height.verticalCenter - anchors.left: bld_level_height.right - anchors.leftMargin: ScreenTools.defaultFontPixelWidth * 2 - - text: (viewer3DManager)?(Number(viewer3DManager.viewer3DSetting.buildingLevelHeight.rawValue)):("nan") - - validator: RegularExpressionValidator{ - regularExpression: /(-?\d{1,10})([.]\d{1,6})?$/ + height: Screen.height * 0.2 + contentWidth: width; + contentHeight: main_column.height + boundsBehavior: Flickable.StopAtBounds + ScrollBar.vertical: ScrollBar {} + + Column { + id: main_column + anchors{ + right: parent.right + left: parent.left + margins: ScreenTools.defaultFontPixelWidth } - - onAccepted: - { - focus = false + spacing: ScreenTools.defaultFontPixelHeight * 0.5 + + RowLayout{ + anchors{ + right: parent.right + left: parent.left + } + QGCLabel { + wrapMode: Text.WordWrap + visible: true + text: qsTr("3D Map File:") + } + + QGCTextField { + id: map_file_text_feild + height: ScreenTools.defaultFontPixelWidth * 4.5 + unitsLabel: "" + showUnits: false + visible: true + Layout.fillWidth: true + readOnly: true + + text: (viewer3DManager)?(viewer3DManager.viewer3DSetting.osmFilePath.rawValue):("nan") + } } - } - - QGCLabel { - id: height_bias_label - Layout.fillWidth: true - wrapMode: Text.WordWrap - visible: true - text: qsTr("Vehicles Altitude Bias:") - anchors.left: parent.left - anchors.top: bld_level_height.bottom - anchors.leftMargin: leftMarginSpace - anchors.topMargin: ScreenTools.defaultFontPixelWidth * 4 - } - - QGCTextField { - id: height_bias_textfeild - width: ScreenTools.defaultFontPixelWidth * 15 - unitsLabel: "m" - showUnits: true - numericValuesOnly: true - visible: true - - anchors.verticalCenter: height_bias_label.verticalCenter - anchors.left: height_bias_label.right - anchors.leftMargin: ScreenTools.defaultFontPixelWidth * 2 - - text: (viewer3DManager)?(Number(viewer3DManager.viewer3DSetting.altitudeBias.rawValue)):("nan") - - validator: RegularExpressionValidator{ - regularExpression: /(-?\d{1,10})([.]\d{1,6})?$/ + RowLayout{ + anchors{ + right: parent.right + left: parent.left + } + QGCButton { + id: map_file_btn + Layout.alignment: Qt.AlignRight + + visible: true + text: qsTr("Select File") + + onClicked: { + fileDialog.openForLoad() + } + + QGCFileDialog { + id: fileDialog + + nameFilters: [qsTr("OpenStreetMap files (*.osm)")] + title: qsTr("Select map file") + onAcceptedForLoad: (file) => { + map_file_text_feild.text = file + } + } + } } - onAccepted: - { - focus = false + GridLayout{ + anchors{ + left: parent.left + } + columns: 2 + columnSpacing: ScreenTools.defaultFontPixelHeight + rowSpacing: ScreenTools.defaultFontPixelWidth + + QGCLabel { + wrapMode: Text.WordWrap + text: qsTr("Average Building Level Height:") + } + + QGCTextField{ + id: bld_level_height_textfeild + width: ScreenTools.defaultFontPixelWidth * 15 + unitsLabel: "m" + showUnits: true + numericValuesOnly: true + visible: true + + text: (viewer3DManager)?(Number(viewer3DManager.viewer3DSetting.buildingLevelHeight.rawValue)):("nan") + + validator: RegularExpressionValidator{ + regularExpression: /(-?\d{1,10})([.]\d{1,6})?$/ + } + + onAccepted: + { + focus = false + } + } + + QGCLabel { + wrapMode: Text.WordWrap + visible: true + text: qsTr("Vehicles Altitude Bias:") + } + + QGCTextField { + id: height_bias_textfeild + width: ScreenTools.defaultFontPixelWidth * 15 + unitsLabel: "m" + showUnits: true + numericValuesOnly: true + visible: true + + text: (viewer3DManager)?(Number(viewer3DManager.viewer3DSetting.altitudeBias.rawValue)):("nan") + + validator: RegularExpressionValidator{ + regularExpression: /(-?\d{1,10})([.]\d{1,6})?$/ + } + + onAccepted: + { + focus = false + } + } } } diff --git a/src/Viewer3D/Viewer3DQmlBackend.cc b/src/Viewer3D/Viewer3DQmlBackend.cc index b3186cf0404..1fd7f59ac00 100644 --- a/src/Viewer3D/Viewer3DQmlBackend.cc +++ b/src/Viewer3D/Viewer3DQmlBackend.cc @@ -3,9 +3,17 @@ #include #include +#include "QGCApplication.h" + +#define GPS_REF_NOT_SET 0 +#define GPS_REF_SET_BY_MAP 1 +#define GPS_REF_SET_BY_VEHICLE 2 + Viewer3DQmlBackend::Viewer3DQmlBackend(QObject *parent) : QObject{parent} { + _gpsRefSet = GPS_REF_NOT_SET; + _activeVehicle = nullptr; } void Viewer3DQmlBackend::init(Viewer3DSettings *viewerSettingThr, OsmParser* osmThr) @@ -14,24 +22,47 @@ void Viewer3DQmlBackend::init(Viewer3DSettings *viewerSettingThr, OsmParser* osm _osmFilePath = viewerSettingThr->osmFilePath()->rawValue().toString(); _osmParserThread = osmThr; + _activeVehicleChangedEvent(qgcApp()->toolbox()->multiVehicleManager()->activeVehicle()); + connect(_osmParserThread, &OsmParser::gpsRefChanged, this, &Viewer3DQmlBackend::_gpsRefChangedEvent); + connect(qgcApp()->toolbox()->multiVehicleManager(), &MultiVehicleManager::activeVehicleChanged, this, &Viewer3DQmlBackend::_activeVehicleChangedEvent); } -void Viewer3DQmlBackend::setGpsRef(const QGeoCoordinate &gpsRef) +void Viewer3DQmlBackend::_activeVehicleChangedEvent(Vehicle *vehicle) { - if(_gpsRef == gpsRef){ - return; + if(_activeVehicle){ + disconnect(_activeVehicle, &Vehicle::coordinateChanged, this, &Viewer3DQmlBackend::_activeVehicleCoordinateChanged); } - _gpsRef = gpsRef; - emit gpsRefChanged(); + _activeVehicle = vehicle; + if(!_activeVehicle){ // means that all the vehicle have been disconnected + if(_gpsRefSet == GPS_REF_SET_BY_VEHICLE){ + _gpsRefSet = GPS_REF_NOT_SET; + } + }else{ + connect(_activeVehicle, &Vehicle::coordinateChanged, this, &Viewer3DQmlBackend::_activeVehicleCoordinateChanged); + } +} + +void Viewer3DQmlBackend::_activeVehicleCoordinateChanged(QGeoCoordinate newCoordinate) +{ + if(_gpsRefSet == GPS_REF_NOT_SET){ + if(newCoordinate.latitude() && newCoordinate.longitude()){ + _gpsRef = newCoordinate; + _gpsRef.setAltitude(0); + _gpsRefSet = GPS_REF_SET_BY_VEHICLE; + emit gpsRefChanged(); + + qDebug() << "3D viewer gps reference set by vehicles:" << _gpsRef.latitude() << _gpsRef.longitude() << _gpsRef.altitude(); + } + } } void Viewer3DQmlBackend::_gpsRefChangedEvent(QGeoCoordinate newGpsRef) { _gpsRef = newGpsRef; - + _gpsRefSet = GPS_REF_SET_BY_MAP; emit gpsRefChanged(); - qDebug() << "3D map gps reference:" << _gpsRef.latitude() << _gpsRef.longitude() << _gpsRef.altitude(); + qDebug() << "3D viewer gps reference set by osm map:" << _gpsRef.latitude() << _gpsRef.longitude() << _gpsRef.altitude(); } diff --git a/src/Viewer3D/Viewer3DQmlBackend.h b/src/Viewer3D/Viewer3DQmlBackend.h index b248ad83dae..bcbda28d0c7 100644 --- a/src/Viewer3D/Viewer3DQmlBackend.h +++ b/src/Viewer3D/Viewer3DQmlBackend.h @@ -24,7 +24,6 @@ class Viewer3DQmlBackend : public QObject void init(Viewer3DSettings* viewerSettingThr, OsmParser* osmThr=nullptr); QGeoCoordinate gpsRef(){return _gpsRef;} - void setGpsRef(const QGeoCoordinate& gpsRef); signals: void gpsRefChanged(); @@ -36,10 +35,16 @@ class Viewer3DQmlBackend : public QObject QString _osmFilePath; QGeoCoordinate _gpsRef; + uint8_t _gpsRefSet; float _altitudeBias; + Vehicle *_activeVehicle; + + protected slots: void _gpsRefChangedEvent(QGeoCoordinate newGpsRef); + void _activeVehicleChangedEvent(Vehicle* vehicle); + void _activeVehicleCoordinateChanged(QGeoCoordinate newCoordinate); }; #endif // Viewer3DQmlBackend_H