Commit 9f857268 authored by Valentin Platzgummer's avatar Valentin Platzgummer
parents 8eb85f52 6af0d454
{
"AreaItems": [
{
"AreaType": "Service Area",
"BorderPolygonOffset": 6,
"DepotAltitude": 0,
"DepotLatitude": 47.76779586216649,
"DepotLongitude": 16.530510396830728,
"ShowBorderPolygon": 0,
"maxAltitude": 30,
"polygon": [
[
47.76780094967389,
16.530343715825353
],
[
47.76788238112663,
16.530625096151965
],
[
47.767783696604035,
16.530655731490725
],
[
47.76771642095403,
16.53041704413795
]
]
},
{
"AreaType": "Measurement Area",
"BorderPolygonOffset": 6,
"MinTileAreaPercent": 30,
"ShowBorderPolygon": 0,
"ShowTiles": true,
"TileHeight": 5,
"TileWidth": 5,
"maxAltitude": 30,
"polygon": [
[
47.76809580679245,
16.530246122817612
],
[
47.76823933601322,
16.53060087654427
],
[
47.7683711160486,
16.530967006195464
],
[
47.7680076482754,
16.531153949077463
],
[
47.7677855557718,
16.530403347547246
],
[
47.76812093862815,
16.53088714314225
]
]
}
],
"MissionItems": {
"fileType": "Plan",
"geoFence": {
"circles": [
],
"polygons": [
],
"version": 2
},
"groundStation": "QGroundControl",
"mission": {
"cruiseSpeed": 15,
"firmwareType": 3,
"hoverSpeed": 1,
"items": [
{
"autoContinue": true,
"command": 22,
"doJumpId": 1,
"frame": 3,
"params": [
15,
0,
0,
null,
47.76779586216649,
16.530510396830728,
10
],
"type": "SimpleItem"
},
{
"Alpha": 23,
"MinLength": 5,
"NumRuns": 1,
"ReferencePointAlt": 0,
"ReferencePointLat": 47.76810433066452,
"ReferencePointLong": 16.530712738301304,
"Run": 1,
"TransectDistance": 3,
"TransectStyleComplexItem": {
"CameraCalc": {
"AdjustedFootprintFrontal": 25,
"AdjustedFootprintSide": 25,
"CameraName": "Manual (no camera specs)",
"DistanceToSurface": 10,
"DistanceToSurfaceRelative": true,
"version": 1
},
"CameraShots": 0,
"CameraTriggerInTurnAround": true,
"FollowTerrain": false,
"HoverAndCapture": false,
"Items": [
{
"autoContinue": true,
"command": 16,
"doJumpId": 2,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76783728898401,
16.530481694784847,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 3,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76802613957926,
16.53114161450939,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 4,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768179446847086,
16.53106276402324,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 5,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76812171672615,
16.530861029906276,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 6,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76831125432985,
16.530806354689858,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 7,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768358305251056,
16.530970771201435,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 8,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76833275405663,
16.53098391307365,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 9,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76818906969824,
16.530481820523075,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 10,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76810775728066,
16.530504966391423,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 11,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76825610046365,
16.53102333861304,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 12,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768281651653936,
16.531010196779448,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 13,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76810310388368,
16.530386278613275,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 14,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76809845036399,
16.530267590829624,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 15,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76830720286059,
16.53099705493299,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 16,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76823054925376,
16.531036480433762,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 17,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768112410554885,
16.530623654217433,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 18,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76811706370638,
16.530742342037925,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 19,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76820499805124,
16.531049622228267,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 20,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76815389564133,
16.531075905805334,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 21,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768086884966515,
16.53084174152664,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 22,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76803696584865,
16.530769731894658,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 23,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76812834442496,
16.531089047574557,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 24,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76810279321597,
16.53110218933091,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 25,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76798704669417,
16.530697722387153,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 26,
"frame": 3,
"params": [
0,
0,
0,
null,
47.767937127512056,
16.530625713070812,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 27,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76807724201434,
16.531115331061052,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 28,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768051690793115,
16.531128472791657,
10
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 29,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76788720826634,
16.530553703838915,
10
],
"type": "SimpleItem"
}
],
"Refly90Degrees": false,
"TurnAroundDistance": 10,
"VisualTransectPoints": [
[
47.76783728898401,
16.530481694784847
],
[
47.76802613957926,
16.53114161450939
],
[
47.768179446847086,
16.53106276402324
],
[
47.76812171672615,
16.530861029906276
],
[
47.76831125432985,
16.530806354689858
],
[
47.768358305251056,
16.530970771201435
],
[
47.76833275405663,
16.53098391307365
],
[
47.76818906969824,
16.530481820523075
],
[
47.76810775728066,
16.530504966391423
],
[
47.76825610046365,
16.53102333861304
],
[
47.768281651653936,
16.531010196779448
],
[
47.76810310388368,
16.530386278613275
],
[
47.76809845036399,
16.530267590829624
],
[
47.76830720286059,
16.53099705493299
],
[
47.76823054925376,
16.531036480433762
],
[
47.768112410554885,
16.530623654217433
],
[
47.76811706370638,
16.530742342037925
],
[
47.76820499805124,
16.531049622228267
],
[
47.76815389564133,
16.531075905805334
],
[
47.768086884966515,
16.53084174152664
],
[
47.76803696584865,
16.530769731894658
],
[
47.76812834442496,
16.531089047574557
],
[
47.76810279321597,
16.53110218933091
],
[
47.76798704669417,
16.530697722387153
],
[
47.767937127512056,
16.530625713070812
],
[
47.76807724201434,
16.531115331061052
],
[
47.768051690793115,
16.531128472791657
],
[
47.76788720826634,
16.530553703838915
]
],
"version": 1
},
"Type": 1,
"Variant": 0,
"complexItemType": "CircularSurvey",
"polygon": [
[
50.54939570164431,
7.196328001507449
],
[
50.54939570164431,
7.238775845997314
],
[
50.522416083956976,
7.238775845997314
],
[
50.522416083956976,
7.196328001507449
]
],
"type": "ComplexItem",
"version": 1
},
{
"AMSLAltAboveTerrain": null,
"Altitude": 10,
"AltitudeMode": 1,
"autoContinue": true,
"command": 16,
"doJumpId": 33,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76807639917751,
16.530893624112736,
10
],
"type": "SimpleItem"
},
{
"AMSLAltAboveTerrain": null,
"Altitude": 10,
"AltitudeMode": 1,
"autoContinue": true,
"command": 16,
"doJumpId": 34,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76779586216649,
16.530510396830728,
10
],
"type": "SimpleItem"
},
{
"AMSLAltAboveTerrain": null,
"Altitude": 0,
"AltitudeMode": 1,
"autoContinue": true,
"command": 21,
"doJumpId": 35,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76779586216649,
16.530510396830728,
0
],
"type": "SimpleItem"
}
],
"plannedHomePosition": [
47.76779586216649,
16.530510396830728,
178
],
"vehicleType": 2,
"version": 2
},
"rallyPoints": {
"points": [
],
"version": 2
},
"version": 1
}
}
......@@ -418,6 +418,9 @@ HEADERS += \
src/Wima/GenericSingelton.h \
src/Wima/Geometry/GenericCircle.h \
src/Wima/RoutingThread.h \
src/Wima/Snake/CircularGenerator.h \
src/Wima/Snake/GeneratorBase.h \
src/Wima/Snake/LinearGenerator.h \
src/Wima/Snake/clipper/clipper.hpp \
src/Wima/Snake/mapbox/feature.hpp \
src/Wima/Snake/mapbox/geometry.hpp \
......@@ -510,6 +513,9 @@ SOURCES += \
src/Wima/CircularSurvey.cc \
src/Wima/GenericSingelton.cpp \
src/Wima/RoutingThread.cpp \
src/Wima/Snake/CircularGenerator.cpp \
src/Wima/Snake/GeneratorBase.cc \
src/Wima/Snake/LinearGenerator.cpp \
src/Wima/Snake/clipper/clipper.cpp \
src/Wima/Snake/snake.cpp \
src/Wima/Geometry/GeoPoint3D.cpp \
......@@ -1449,5 +1455,8 @@ contains (CONFIG, QGC_DISABLE_INSTALLER_SETUP) {
}
DISTFILES += \
src/Wima/Routing/json/CircularGenerator.SettingsGroup.json \
src/Wima/Snake/json/LinearGenerator.SettingsGroup.json \
src/Wima/json/CircularSurvey.SettingsGroup.json \
src/WimaView/WimaMeasurementAreaEditor.qml \
src/Settings/Wima.SettingsGroup.json
......@@ -7,93 +7,146 @@
<file alias="BatteryIndicator.qml">src/ui/toolbar/BatteryIndicator.qml</file>
<file alias="GPSIndicator.qml">src/ui/toolbar/GPSIndicator.qml</file>
<file alias="GPSRTKIndicator.qml">src/ui/toolbar/GPSRTKIndicator.qml</file>
<file alias="JoystickIndicator.qml">src/ui/toolbar/JoystickIndicator.qml</file>
<file alias="LinkIndicator.qml">src/ui/toolbar/LinkIndicator.qml</file>
<file alias="MessageIndicator.qml">src/ui/toolbar/MessageIndicator.qml</file>
<file alias="ModeIndicator.qml">src/ui/toolbar/ModeIndicator.qml</file>
<file alias="VTOLModeIndicator.qml">src/ui/toolbar/VTOLModeIndicator.qml</file>
<file alias="RCRSSIIndicator.qml">src/ui/toolbar/RCRSSIIndicator.qml</file>
<file alias="TelemetryRSSIIndicator.qml">src/ui/toolbar/TelemetryRSSIIndicator.qml</file>
<file alias="JoystickIndicator.qml">src/ui/toolbar/JoystickIndicator.qml</file>
<file alias="LinkIndicator.qml">src/ui/toolbar/LinkIndicator.qml</file>
<file alias="VTOLModeIndicator.qml">src/ui/toolbar/VTOLModeIndicator.qml</file>
</qresource>
<qresource prefix="/qml">
<file alias="CorridorScanEditor.qml">src/PlanView/CorridorScanEditor.qml</file>
<file alias="QGroundControl/Controls/CameraCalc.qml">src/PlanView/CameraCalc.qml</file>
<file alias="QGroundControl/Controls/CorridorScanMapVisual.qml">src/PlanView/CorridorScanMapVisual.qml</file>
<file alias="QGroundControl/Controls/EditPositionDialog.qml">src/QmlControls/EditPositionDialog.qml</file>
<file alias="QGroundControl/Controls/FileButton.qml">src/QmlControls/FileButton.qml</file>
<file alias="QGroundControl/Controls/QGCMapCircleVisuals.qml">src/MissionManager/QGCMapCircleVisuals.qml</file>
<file alias="QGroundControl/Controls/QGCMapPolylineVisuals.qml">src/MissionManager/QGCMapPolylineVisuals.qml</file>
<file alias="QGroundControl/Controls/StructureScanMapVisual.qml">src/PlanView/StructureScanMapVisual.qml</file>
<file alias="QGroundControl/Controls/AnalyzePage.qml">src/AnalyzeView/AnalyzePage.qml</file>
<file alias="AnalyzeView.qml">src/AnalyzeView/AnalyzeView.qml</file>
<file alias="AppSettings.qml">src/ui/AppSettings.qml</file>
<file alias="BluetoothSettings.qml">src/ui/preferences/BluetoothSettings.qml</file>
<file alias="CameraPageWidget.qml">src/FlightMap/Widgets/CameraPageWidget.qml</file>
<file alias="CustomCommandWidget.qml">src/ViewWidgets/CustomCommandWidget.qml</file>
<file alias="DebugWindow.qml">src/ui/preferences/DebugWindow.qml</file>
<file alias="GeoTagPage.qml">src/AnalyzeView/GeoTagPage.qml</file>
<file alias="LogDownloadPage.qml">src/AnalyzeView/LogDownloadPage.qml</file>
<file alias="MavlinkConsolePage.qml">src/AnalyzeView/MavlinkConsolePage.qml</file>
<file alias="ESP8266Component.qml">src/AutoPilotPlugins/Common/ESP8266Component.qml</file>
<file alias="ESP8266ComponentSummary.qml">src/AutoPilotPlugins/Common/ESP8266ComponentSummary.qml</file>
<file alias="FirmwareUpgrade.qml">src/VehicleSetup/FirmwareUpgrade.qml</file>
<file alias="MotorComponent.qml">src/AutoPilotPlugins/Common/MotorComponent.qml</file>
<file alias="RadioComponent.qml">src/AutoPilotPlugins/Common/RadioComponent.qml</file>
<file alias="QGroundControl/Controls/SetupPage.qml">src/AutoPilotPlugins/Common/SetupPage.qml</file>
<file alias="SyslinkComponent.qml">src/AutoPilotPlugins/Common/SyslinkComponent.qml</file>
<file alias="QGroundControl/FactControls/AltitudeFactTextField.qml">src/FactSystem/FactControls/AltitudeFactTextField.qml</file>
<file alias="QGroundControl/FactControls/FactBitmask.qml">src/FactSystem/FactControls/FactBitmask.qml</file>
<file alias="QGroundControl/FactControls/FactCheckBox.qml">src/FactSystem/FactControls/FactCheckBox.qml</file>
<file alias="QGroundControl/FactControls/FactComboBox.qml">src/FactSystem/FactControls/FactComboBox.qml</file>
<file alias="QGroundControl/FactControls/FactLabel.qml">src/FactSystem/FactControls/FactLabel.qml</file>
<file alias="QGroundControl/FactControls/FactPanel.qml">src/FactSystem/FactControls/FactPanel.qml</file>
<file alias="QGroundControl/FactControls/FactTextField.qml">src/FactSystem/FactControls/FactTextField.qml</file>
<file alias="QGroundControl/FactControls/FactTextFieldGrid.qml">src/FactSystem/FactControls/FactTextFieldGrid.qml</file>
<file alias="QGroundControl/FactControls/FactTextFieldRow.qml">src/FactSystem/FactControls/FactTextFieldRow.qml</file>
<file alias="QGroundControl/FactControls/FactTextFieldSlider.qml">src/FactSystem/FactControls/FactTextFieldSlider.qml</file>
<file alias="QGroundControl/FactControls/FactValueSlider.qml">src/FactSystem/FactControls/FactValueSlider.qml</file>
<file alias="QGroundControl/FactControls/qmldir">src/FactSystem/FactControls/qmldir</file>
<file alias="QGroundControl/FlightDisplay/BuiltInPreFlightCheckModel.qml">src/FlightDisplay/BuiltInPreFlightCheckModel.qml</file>
<file alias="QGroundControl/FlightDisplay/FlightDisplayView.qml">src/FlightDisplay/FlightDisplayView.qml</file>
<file alias="FlightDisplayViewDummy.qml">src/FlightDisplay/FlightDisplayViewDummy.qml</file>
<file alias="QGroundControl/FlightDisplay/FlightDisplayViewMap.qml">src/FlightDisplay/FlightDisplayViewMap.qml</file>
<file alias="FlightDisplayViewUVC.qml">src/FlightDisplay/FlightDisplayViewUVC.qml</file>
<file alias="FWLandingPatternEditor.qml">src/PlanView/FWLandingPatternEditor.qml</file>
<file alias="GeneralSettings.qml">src/ui/preferences/GeneralSettings.qml</file>
<file alias="GeoTagPage.qml">src/AnalyzeView/GeoTagPage.qml</file>
<file alias="QGroundControl/FlightDisplay/FlightDisplayViewVideo.qml">src/FlightDisplay/FlightDisplayViewVideo.qml</file>
<file alias="QGroundControl/FlightDisplay/FlightDisplayViewWidgets.qml">src/FlightDisplay/FlightDisplayViewWidgets.qml</file>
<file alias="QGroundControl/FlightDisplay/FlightDisplayWimaMenu.qml">src/FlightDisplay/FlightDisplayWimaMenu.qml</file>
<file alias="QGroundControl/FlightDisplay/GuidedActionConfirm.qml">src/FlightDisplay/GuidedActionConfirm.qml</file>
<file alias="QGroundControl/FlightDisplay/GuidedActionList.qml">src/FlightDisplay/GuidedActionList.qml</file>
<file alias="QGroundControl/FlightDisplay/GuidedActionsController.qml">src/FlightDisplay/GuidedActionsController.qml</file>
<file alias="QGroundControl/FlightDisplay/GuidedAltitudeSlider.qml">src/FlightDisplay/GuidedAltitudeSlider.qml</file>
<file alias="QGroundControl/FlightDisplay/MultiVehicleList.qml">src/FlightDisplay/MultiVehicleList.qml</file>
<file alias="QGroundControl/FlightDisplay/PreFlightBatteryCheck.qml">src/FlightDisplay/PreFlightBatteryCheck.qml</file>
<file alias="QGroundControl/FlightDisplay/PreFlightGPSCheck.qml">src/FlightDisplay/PreFlightGPSCheck.qml</file>
<file alias="QGroundControl/FlightDisplay/PreFlightRCCheck.qml">src/FlightDisplay/PreFlightRCCheck.qml</file>
<file alias="QGroundControl/FlightDisplay/PreFlightSensorsHealthCheck.qml">src/FlightDisplay/PreFlightSensorsHealthCheck.qml</file>
<file alias="QGroundControl/FlightDisplay/PreFlightSoundCheck.qml">src/FlightDisplay/PreFlightSoundCheck.qml</file>
<file alias="QGroundControl/FlightDisplay/SmallValue.qml">src/FlightDisplay/SmallValue.qml</file>
<file alias="VirtualJoystick.qml">src/FlightDisplay/VirtualJoystick.qml</file>
<file alias="QGroundControl/FlightDisplay/qmldir">src/FlightDisplay/qmldir</file>
<file alias="QGroundControl/FlightMap/FlightMap.qml">src/FlightMap/FlightMap.qml</file>
<file alias="QGroundControl/FlightMap/CameraTriggerIndicator.qml">src/FlightMap/MapItems/CameraTriggerIndicator.qml</file>
<file alias="QGroundControl/FlightMap/CustomMapItems.qml">src/FlightMap/MapItems/CustomMapItems.qml</file>
<file alias="QGroundControl/FlightMap/MissionItemIndicator.qml">src/FlightMap/MapItems/MissionItemIndicator.qml</file>
<file alias="QGroundControl/FlightMap/MissionItemIndicatorDrag.qml">src/FlightMap/MapItems/MissionItemIndicatorDrag.qml</file>
<file alias="QGroundControl/FlightMap/MissionItemView.qml">src/FlightMap/MapItems/MissionItemView.qml</file>
<file alias="QGroundControl/FlightMap/MissionLineView.qml">src/FlightMap/MapItems/MissionLineView.qml</file>
<file alias="QGroundControl/FlightMap/PlanMapItems.qml">src/FlightMap/MapItems/PlanMapItems.qml</file>
<file alias="QGroundControl/FlightMap/PolygonEditor.qml">src/FlightMap/MapItems/PolygonEditor.qml</file>
<file alias="QGroundControl/FlightMap/VehicleMapItem.qml">src/FlightMap/MapItems/VehicleMapItem.qml</file>
<file alias="QGroundControl/FlightMap/WimaPlanMapItems.qml">src/FlightMap/MapItems/WimaPlanMapItems.qml</file>
<file alias="QGroundControl/FlightMap/MapScale.qml">src/FlightMap/MapScale.qml</file>
<file alias="QGroundControl/FlightMap/QGCVideoBackground.qml">src/FlightMap/QGCVideoBackground.qml</file>
<file alias="CameraPageWidget.qml">src/FlightMap/Widgets/CameraPageWidget.qml</file>
<file alias="QGroundControl/FlightMap/CenterMapDropButton.qml">src/FlightMap/Widgets/CenterMapDropButton.qml</file>
<file alias="QGroundControl/FlightMap/CenterMapDropPanel.qml">src/FlightMap/Widgets/CenterMapDropPanel.qml</file>
<file alias="QGroundControl/FlightMap/CompassRing.qml">src/FlightMap/Widgets/CompassRing.qml</file>
<file alias="HealthPageWidget.qml">src/FlightMap/Widgets/HealthPageWidget.qml</file>
<file alias="HelpSettings.qml">src/ui/preferences/HelpSettings.qml</file>
<file alias="JoystickConfig.qml">src/VehicleSetup/JoystickConfig.qml</file>
<file alias="LinkSettings.qml">src/ui/preferences/LinkSettings.qml</file>
<file alias="LogDownloadPage.qml">src/AnalyzeView/LogDownloadPage.qml</file>
<file alias="LogReplaySettings.qml">src/ui/preferences/LogReplaySettings.qml</file>
<file alias="MainWindowHybrid.qml">src/ui/MainWindowHybrid.qml</file>
<file alias="MainWindowInner.qml">src/ui/MainWindowInner.qml</file>
<file alias="MainWindowNative.qml">src/ui/MainWindowNative.qml</file>
<file alias="MavlinkConsolePage.qml">src/AnalyzeView/MavlinkConsolePage.qml</file>
<file alias="MavlinkSettings.qml">src/ui/preferences/MavlinkSettings.qml</file>
<file alias="MissionSettingsEditor.qml">src/PlanView/MissionSettingsEditor.qml</file>
<file alias="MockLink.qml">src/ui/preferences/MockLink.qml</file>
<file alias="MockLinkSettings.qml">src/ui/preferences/MockLinkSettings.qml</file>
<file alias="MotorComponent.qml">src/AutoPilotPlugins/Common/MotorComponent.qml</file>
<file alias="OfflineMap.qml">src/QtLocationPlugin/QMLControl/OfflineMap.qml</file>
<file alias="PlanView.qml">src/PlanView/PlanView.qml</file>
<file alias="PX4FlowSensor.qml">src/VehicleSetup/PX4FlowSensor.qml</file>
<file alias="QGroundControl/FlightMap/InstrumentSwipeView.qml">src/FlightMap/Widgets/InstrumentSwipeView.qml</file>
<file alias="QGroundControl/FlightMap/MapFitFunctions.qml">src/FlightMap/Widgets/MapFitFunctions.qml</file>
<file alias="QGroundControl/FlightMap/QGCArtificialHorizon.qml">src/FlightMap/Widgets/QGCArtificialHorizon.qml</file>
<file alias="QGroundControl/FlightMap/QGCAttitudeHUD.qml">src/FlightMap/Widgets/QGCAttitudeHUD.qml</file>
<file alias="QGroundControl/FlightMap/QGCAttitudeWidget.qml">src/FlightMap/Widgets/QGCAttitudeWidget.qml</file>
<file alias="QGroundControl/FlightMap/QGCCompassWidget.qml">src/FlightMap/Widgets/QGCCompassWidget.qml</file>
<file alias="QGCInstrumentWidget.qml">src/FlightMap/Widgets/QGCInstrumentWidget.qml</file>
<file alias="QGCInstrumentWidgetAlternate.qml">src/FlightMap/Widgets/QGCInstrumentWidgetAlternate.qml</file>
<file alias="QGroundControl/Controls/AnalyzePage.qml">src/AnalyzeView/AnalyzePage.qml</file>
<file alias="QGroundControl/Controls/AppMessages.qml">src/QmlControls/AppMessages.qml</file>
<file alias="QGroundControl/FlightMap/QGCPitchIndicator.qml">src/FlightMap/Widgets/QGCPitchIndicator.qml</file>
<file alias="ValuePageWidget.qml">src/FlightMap/Widgets/ValuePageWidget.qml</file>
<file alias="VibrationPageWidget.qml">src/FlightMap/Widgets/VibrationPageWidget.qml</file>
<file alias="VideoPageWidget.qml">src/FlightMap/Widgets/VideoPageWidget.qml</file>
<file alias="QGroundControl/FlightMap/qmldir">src/FlightMap/qmldir</file>
<file alias="QGroundControl/Controls/QGCMapCircleVisuals.qml">src/MissionManager/QGCMapCircleVisuals.qml</file>
<file alias="QGroundControl/Controls/QGCMapPolygonVisuals.qml">src/MissionManager/QGCMapPolygonVisuals.qml</file>
<file alias="QGroundControl/Controls/QGCMapPolylineVisuals.qml">src/MissionManager/QGCMapPolylineVisuals.qml</file>
<file alias="QGroundControl/Controls/CameraCalc.qml">src/PlanView/CameraCalc.qml</file>
<file alias="QGroundControl/Controls/CameraSection.qml">src/PlanView/CameraSection.qml</file>
<file alias="CorridorScanEditor.qml">src/PlanView/CorridorScanEditor.qml</file>
<file alias="QGroundControl/Controls/CorridorScanMapVisual.qml">src/PlanView/CorridorScanMapVisual.qml</file>
<file alias="FWLandingPatternEditor.qml">src/PlanView/FWLandingPatternEditor.qml</file>
<file alias="QGroundControl/Controls/FWLandingPatternMapVisual.qml">src/PlanView/FWLandingPatternMapVisual.qml</file>
<file alias="QGroundControl/Controls/GeoFenceEditor.qml">src/PlanView/GeoFenceEditor.qml</file>
<file alias="QGroundControl/Controls/GeoFenceMapVisuals.qml">src/PlanView/GeoFenceMapVisuals.qml</file>
<file alias="QGroundControl/Controls/MissionItemEditor.qml">src/PlanView/MissionItemEditor.qml</file>
<file alias="QGroundControl/Controls/MissionItemMapVisual.qml">src/PlanView/MissionItemMapVisual.qml</file>
<file alias="QGroundControl/Controls/MissionItemStatus.qml">src/PlanView/MissionItemStatus.qml</file>
<file alias="MissionSettingsEditor.qml">src/PlanView/MissionSettingsEditor.qml</file>
<file alias="QGroundControl/Controls/PlanToolBar.qml">src/PlanView/PlanToolBar.qml</file>
<file alias="PlanView.qml">src/PlanView/PlanView.qml</file>
<file alias="QGroundControl/Controls/RallyPointEditorHeader.qml">src/PlanView/RallyPointEditorHeader.qml</file>
<file alias="QGroundControl/Controls/RallyPointItemEditor.qml">src/PlanView/RallyPointItemEditor.qml</file>
<file alias="QGroundControl/Controls/RallyPointMapVisuals.qml">src/PlanView/RallyPointMapVisuals.qml</file>
<file alias="SimpleItemEditor.qml">src/PlanView/SimpleItemEditor.qml</file>
<file alias="QGroundControl/Controls/SimpleItemMapVisual.qml">src/PlanView/SimpleItemMapVisual.qml</file>
<file alias="StructureScanEditor.qml">src/PlanView/StructureScanEditor.qml</file>
<file alias="QGroundControl/Controls/StructureScanMapVisual.qml">src/PlanView/StructureScanMapVisual.qml</file>
<file alias="SurveyItemEditor.qml">src/PlanView/SurveyItemEditor.qml</file>
<file alias="QGroundControl/Controls/SurveyMapVisual.qml">src/PlanView/SurveyMapVisual.qml</file>
<file alias="QGroundControl/Controls/TransectStyleComplexItemStats.qml">src/PlanView/TransectStyleComplexItemStats.qml</file>
<file alias="QGroundControl/FlightMap/WimaMissionItemMapVisual.qml">src/PlanView/WimaMissionItemMapVisual.qml</file>
<file alias="QGroundControl/Controls/AppMessages.qml">src/QmlControls/AppMessages.qml</file>
<file alias="QGroundControl/Controls/ClickableColor.qml">src/QmlControls/ClickableColor.qml</file>
<file alias="QGroundControl/Controls/DeadMouseArea.qml">src/QmlControls/DeadMouseArea.qml</file>
<file alias="QGroundControl/Controls/DropButton.qml">src/QmlControls/DropButton.qml</file>
<file alias="QGroundControl/Controls/DropPanel.qml">src/QmlControls/DropPanel.qml</file>
<file alias="QGroundControl/Controls/EditPositionDialog.qml">src/QmlControls/EditPositionDialog.qml</file>
<file alias="QGroundControl/Controls/ExclusiveGroupItem.qml">src/QmlControls/ExclusiveGroupItem.qml</file>
<file alias="QGroundControl/Controls/FactSliderPanel.qml">src/QmlControls/FactSliderPanel.qml</file>
<file alias="QGroundControl/Controls/FileButton.qml">src/QmlControls/FileButton.qml</file>
<file alias="QGroundControl/Controls/FlightModeDropdown.qml">src/QmlControls/FlightModeDropdown.qml</file>
<file alias="QGroundControl/Controls/FlightModeMenu.qml">src/QmlControls/FlightModeMenu.qml</file>
<file alias="QGroundControl/Controls/FWLandingPatternMapVisual.qml">src/PlanView/FWLandingPatternMapVisual.qml</file>
<file alias="QGroundControl/Controls/GeoFenceEditor.qml">src/PlanView/GeoFenceEditor.qml</file>
<file alias="QGroundControl/Controls/GeoFenceMapVisuals.qml">src/PlanView/GeoFenceMapVisuals.qml</file>
<file alias="QGroundControl/Controls/IndicatorButton.qml">src/QmlControls/IndicatorButton.qml</file>
<file alias="QGroundControl/Controls/JoystickThumbPad.qml">src/QmlControls/JoystickThumbPad.qml</file>
<file alias="QGroundControl/Controls/MainToolBar.qml">src/ui/toolbar/MainToolBar.qml</file>
<file alias="QGroundControl/Controls/MainToolBarIndicators.qml">src/ui/toolbar/MainToolBarIndicators.qml</file>
<file alias="QGroundControl/Controls/MissionCommandDialog.qml">src/QmlControls/MissionCommandDialog.qml</file>
<file alias="QGroundControl/Controls/MissionItemEditor.qml">src/PlanView/MissionItemEditor.qml</file>
<file alias="QGroundControl/Controls/MissionItemIndexLabel.qml">src/QmlControls/MissionItemIndexLabel.qml</file>
<file alias="QGroundControl/Controls/MissionItemMapVisual.qml">src/PlanView/MissionItemMapVisual.qml</file>
<file alias="QGroundControl/Controls/MissionItemStatus.qml">src/PlanView/MissionItemStatus.qml</file>
<file alias="QGroundControl/Controls/ModeSwitchDisplay.qml">src/QmlControls/ModeSwitchDisplay.qml</file>
<file alias="QGroundControl/Controls/MultiRotorMotorDisplay.qml">src/QmlControls/MultiRotorMotorDisplay.qml</file>
<file alias="QGroundControl/Controls/OfflineMapButton.qml">src/QmlControls/OfflineMapButton.qml</file>
<file alias="QGroundControl/Controls/PIDTuning.qml">src/QmlControls/PIDTuning.qml</file>
<file alias="QGroundControl/Controls/PageView.qml">src/QmlControls/PageView.qml</file>
<file alias="QGroundControl/Controls/ParameterEditor.qml">src/QmlControls/ParameterEditor.qml</file>
<file alias="QGroundControl/Controls/ParameterEditorDialog.qml">src/QmlControls/ParameterEditorDialog.qml</file>
<file alias="QGroundControl/Controls/PIDTuning.qml">src/QmlControls/PIDTuning.qml</file>
<file alias="QGroundControl/Controls/PlanToolBar.qml">src/PlanView/PlanToolBar.qml</file>
<file alias="QGroundControl/Controls/PreFlightCheckButton.qml">src/QmlControls/PreFlightCheckButton.qml</file>
<file alias="QGroundControl/Controls/PreFlightCheckGroup.qml">src/QmlControls/PreFlightCheckGroup.qml</file>
<file alias="QGroundControl/Controls/PreFlightCheckList.qml">src/QmlControls/PreFlightCheckList.qml</file>
<file alias="QGroundControl/Controls/PreFlightCheckModel.qml">src/QmlControls/PreFlightCheckModel.qml</file>
<file alias="QGroundControl/Controls/QGCButton.qml">src/QmlControls/QGCButton.qml</file>
<file alias="QGroundControl/Controls/QGCButtonColumn.qml">src/QmlControls/QGCButtonColumn.qml</file>
<file alias="QGroundControl/Controls/QGCCheckBox.qml">src/QmlControls/QGCCheckBox.qml</file>
<file alias="QGroundControl/Controls/QGCColoredImage.qml">src/QmlControls/QGCColoredImage.qml</file>
<file alias="QGroundControl/Controls/QGCComboBox.qml">src/QmlControls/QGCComboBox.qml</file>
......@@ -105,7 +158,6 @@
<file alias="QGroundControl/Controls/QGCLabel.qml">src/QmlControls/QGCLabel.qml</file>
<file alias="QGroundControl/Controls/QGCListView.qml">src/QmlControls/QGCListView.qml</file>
<file alias="QGroundControl/Controls/QGCMapLabel.qml">src/QmlControls/QGCMapLabel.qml</file>
<file alias="QGroundControl/Controls/QGCMapPolygonVisuals.qml">src/MissionManager/QGCMapPolygonVisuals.qml</file>
<file alias="QGroundControl/Controls/QGCMouseArea.qml">src/QmlControls/QGCMouseArea.qml</file>
<file alias="QGroundControl/Controls/QGCMovableItem.qml">src/QmlControls/QGCMovableItem.qml</file>
<file alias="QGroundControl/Controls/QGCPipable.qml">src/QmlControls/QGCPipable.qml</file>
......@@ -120,142 +172,83 @@
<file alias="QGroundControl/Controls/QGCViewMessage.qml">src/QmlControls/QGCViewMessage.qml</file>
<file alias="QGroundControl/Controls/QGCViewPanel.qml">src/QmlControls/QGCViewPanel.qml</file>
<file alias="QGroundControl/Controls/qmldir">src/QmlControls/QGroundControl.Controls.qmldir</file>
<file alias="QGroundControl/Controls/RallyPointEditorHeader.qml">src/PlanView/RallyPointEditorHeader.qml</file>
<file alias="QGroundControl/Controls/RallyPointItemEditor.qml">src/PlanView/RallyPointItemEditor.qml</file>
<file alias="QGroundControl/Controls/RallyPointMapVisuals.qml">src/PlanView/RallyPointMapVisuals.qml</file>
<file alias="QGroundControl/ScreenTools/qmldir">src/QmlControls/QGroundControl.ScreenTools.qmldir</file>
<file alias="QmlTest.qml">src/QmlControls/QmlTest.qml</file>
<file alias="QGroundControl/Controls/RCChannelMonitor.qml">src/QmlControls/RCChannelMonitor.qml</file>
<file alias="QGroundControl/Controls/RoundButton.qml">src/QmlControls/RoundButton.qml</file>
<file alias="QGroundControl/ScreenTools/ScreenTools.qml">src/QmlControls/ScreenTools.qml</file>
<file alias="QGroundControl/Controls/SectionHeader.qml">src/QmlControls/SectionHeader.qml</file>
<file alias="QGroundControl/Controls/SetupPage.qml">src/AutoPilotPlugins/Common/SetupPage.qml</file>
<file alias="QGroundControl/Controls/SignalStrength.qml">src/ui/toolbar/SignalStrength.qml</file>
<file alias="QGroundControl/Controls/SimpleItemMapVisual.qml">src/PlanView/SimpleItemMapVisual.qml</file>
<file alias="QGroundControl/Controls/SliderSwitch.qml">src/QmlControls/SliderSwitch.qml</file>
<file alias="QGroundControl/Controls/SubMenuButton.qml">src/QmlControls/SubMenuButton.qml</file>
<file alias="QGroundControl/Controls/SurveyMapVisual.qml">src/PlanView/SurveyMapVisual.qml</file>
<file alias="QGroundControl/Controls/TransectStyleComplexItemStats.qml">src/PlanView/TransectStyleComplexItemStats.qml</file>
<file alias="QGroundControl/Controls/ToolStrip.qml">src/QmlControls/ToolStrip.qml</file>
<file alias="QGroundControl/Controls/VehicleRotationCal.qml">src/QmlControls/VehicleRotationCal.qml</file>
<file alias="QGroundControl/Controls/VehicleSummaryRow.qml">src/QmlControls/VehicleSummaryRow.qml</file>
<file alias="QGroundControl/Controls/ViewWidget.qml">src/ViewWidgets/ViewWidget.qml</file>
<file alias="QGroundControl/FactControls/AltitudeFactTextField.qml">src/FactSystem/FactControls/AltitudeFactTextField.qml</file>
<file alias="QGroundControl/FactControls/FactBitmask.qml">src/FactSystem/FactControls/FactBitmask.qml</file>
<file alias="QGroundControl/FactControls/FactCheckBox.qml">src/FactSystem/FactControls/FactCheckBox.qml</file>
<file alias="QGroundControl/FactControls/FactComboBox.qml">src/FactSystem/FactControls/FactComboBox.qml</file>
<file alias="QGroundControl/FactControls/FactLabel.qml">src/FactSystem/FactControls/FactLabel.qml</file>
<file alias="QGroundControl/FactControls/FactPanel.qml">src/FactSystem/FactControls/FactPanel.qml</file>
<file alias="QGroundControl/FactControls/FactTextField.qml">src/FactSystem/FactControls/FactTextField.qml</file>
<file alias="QGroundControl/FactControls/FactTextFieldGrid.qml">src/FactSystem/FactControls/FactTextFieldGrid.qml</file>
<file alias="QGroundControl/FactControls/FactTextFieldRow.qml">src/FactSystem/FactControls/FactTextFieldRow.qml</file>
<file alias="QGroundControl/FactControls/FactValueSlider.qml">src/FactSystem/FactControls/FactValueSlider.qml</file>
<file alias="QGroundControl/FactControls/FactTextFieldSlider.qml">src/FactSystem/FactControls/FactTextFieldSlider.qml</file>
<file alias="QGroundControl/FactControls/qmldir">src/FactSystem/FactControls/qmldir</file>
<file alias="QGroundControl/FlightDisplay/FlightDisplayView.qml">src/FlightDisplay/FlightDisplayView.qml</file>
<file alias="QGroundControl/FlightDisplay/FlightDisplayViewMap.qml">src/FlightDisplay/FlightDisplayViewMap.qml</file>
<file alias="QGroundControl/FlightDisplay/FlightDisplayViewVideo.qml">src/FlightDisplay/FlightDisplayViewVideo.qml</file>
<file alias="QGroundControl/FlightDisplay/FlightDisplayViewWidgets.qml">src/FlightDisplay/FlightDisplayViewWidgets.qml</file>
<file alias="QGroundControl/FlightDisplay/GuidedActionConfirm.qml">src/FlightDisplay/GuidedActionConfirm.qml</file>
<file alias="QGroundControl/FlightDisplay/GuidedActionList.qml">src/FlightDisplay/GuidedActionList.qml</file>
<file alias="QGroundControl/FlightDisplay/GuidedActionsController.qml">src/FlightDisplay/GuidedActionsController.qml</file>
<file alias="QGroundControl/FlightDisplay/GuidedAltitudeSlider.qml">src/FlightDisplay/GuidedAltitudeSlider.qml</file>
<file alias="QGroundControl/FlightDisplay/MultiVehicleList.qml">src/FlightDisplay/MultiVehicleList.qml</file>
<file alias="QGroundControl/FlightDisplay/PreFlightBatteryCheck.qml">src/FlightDisplay/PreFlightBatteryCheck.qml</file>
<file alias="QGroundControl/FlightDisplay/BuiltInPreFlightCheckModel.qml">src/FlightDisplay/BuiltInPreFlightCheckModel.qml</file>
<file alias="QGroundControl/FlightDisplay/PreFlightGPSCheck.qml">src/FlightDisplay/PreFlightGPSCheck.qml</file>
<file alias="QGroundControl/FlightDisplay/PreFlightRCCheck.qml">src/FlightDisplay/PreFlightRCCheck.qml</file>
<file alias="QGroundControl/FlightDisplay/PreFlightSensorsHealthCheck.qml">src/FlightDisplay/PreFlightSensorsHealthCheck.qml</file>
<file alias="QGroundControl/FlightDisplay/PreFlightSoundCheck.qml">src/FlightDisplay/PreFlightSoundCheck.qml</file>
<file alias="QGroundControl/FlightDisplay/qmldir">src/FlightDisplay/qmldir</file>
<file alias="QGroundControl/FlightMap/CameraTriggerIndicator.qml">src/FlightMap/MapItems/CameraTriggerIndicator.qml</file>
<file alias="QGroundControl/FlightMap/CenterMapDropButton.qml">src/FlightMap/Widgets/CenterMapDropButton.qml</file>
<file alias="QGroundControl/FlightMap/CenterMapDropPanel.qml">src/FlightMap/Widgets/CenterMapDropPanel.qml</file>
<file alias="QGroundControl/FlightMap/CompassRing.qml">src/FlightMap/Widgets/CompassRing.qml</file>
<file alias="QGroundControl/FlightMap/CustomMapItems.qml">src/FlightMap/MapItems/CustomMapItems.qml</file>
<file alias="QGroundControl/FlightMap/FlightMap.qml">src/FlightMap/FlightMap.qml</file>
<file alias="QGroundControl/FlightMap/InstrumentSwipeView.qml">src/FlightMap/Widgets/InstrumentSwipeView.qml</file>
<file alias="QGroundControl/FlightMap/MapFitFunctions.qml">src/FlightMap/Widgets/MapFitFunctions.qml</file>
<file alias="QGroundControl/FlightMap/MapScale.qml">src/FlightMap/MapScale.qml</file>
<file alias="QGroundControl/FlightMap/MissionItemIndicator.qml">src/FlightMap/MapItems/MissionItemIndicator.qml</file>
<file alias="QGroundControl/FlightMap/MissionItemIndicatorDrag.qml">src/FlightMap/MapItems/MissionItemIndicatorDrag.qml</file>
<file alias="QGroundControl/FlightMap/MissionItemView.qml">src/FlightMap/MapItems/MissionItemView.qml</file>
<file alias="QGroundControl/FlightMap/MissionLineView.qml">src/FlightMap/MapItems/MissionLineView.qml</file>
<file alias="QGroundControl/FlightMap/PlanMapItems.qml">src/FlightMap/MapItems/PlanMapItems.qml</file>
<file alias="QGroundControl/FlightMap/PolygonEditor.qml">src/FlightMap/MapItems/PolygonEditor.qml</file>
<file alias="QGroundControl/FlightMap/QGCArtificialHorizon.qml">src/FlightMap/Widgets/QGCArtificialHorizon.qml</file>
<file alias="QGroundControl/FlightMap/QGCAttitudeHUD.qml">src/FlightMap/Widgets/QGCAttitudeHUD.qml</file>
<file alias="QGroundControl/FlightMap/QGCAttitudeWidget.qml">src/FlightMap/Widgets/QGCAttitudeWidget.qml</file>
<file alias="QGroundControl/FlightMap/QGCCompassWidget.qml">src/FlightMap/Widgets/QGCCompassWidget.qml</file>
<file alias="QGroundControl/FlightMap/QGCPitchIndicator.qml">src/FlightMap/Widgets/QGCPitchIndicator.qml</file>
<file alias="QGroundControl/FlightMap/QGCVideoBackground.qml">src/FlightMap/QGCVideoBackground.qml</file>
<file alias="QGroundControl/FlightMap/qmldir">src/FlightMap/qmldir</file>
<file alias="QGroundControl/FlightMap/VehicleMapItem.qml">src/FlightMap/MapItems/VehicleMapItem.qml</file>
<file alias="QGroundControl/ScreenTools/qmldir">src/QmlControls/QGroundControl.ScreenTools.qmldir</file>
<file alias="QGroundControl/ScreenTools/ScreenTools.qml">src/QmlControls/ScreenTools.qml</file>
<file alias="QmlTest.qml">src/QmlControls/QmlTest.qml</file>
<file alias="RadioComponent.qml">src/AutoPilotPlugins/Common/RadioComponent.qml</file>
<file alias="SerialSettings.qml">src/ui/preferences/SerialSettings.qml</file>
<file alias="OfflineMap.qml">src/QtLocationPlugin/QMLControl/OfflineMap.qml</file>
<file alias="TaisyncSettings.qml">src/Taisync/TaisyncSettings.qml</file>
<file alias="FirmwareUpgrade.qml">src/VehicleSetup/FirmwareUpgrade.qml</file>
<file alias="JoystickConfig.qml">src/VehicleSetup/JoystickConfig.qml</file>
<file alias="PX4FlowSensor.qml">src/VehicleSetup/PX4FlowSensor.qml</file>
<file alias="SetupParameterEditor.qml">src/VehicleSetup/SetupParameterEditor.qml</file>
<file alias="SetupView.qml">src/VehicleSetup/SetupView.qml</file>
<file alias="SimpleItemEditor.qml">src/PlanView/SimpleItemEditor.qml</file>
<file alias="StructureScanEditor.qml">src/PlanView/StructureScanEditor.qml</file>
<file alias="SurveyItemEditor.qml">src/PlanView/SurveyItemEditor.qml</file>
<file alias="SyslinkComponent.qml">src/AutoPilotPlugins/Common/SyslinkComponent.qml</file>
<file alias="TcpSettings.qml">src/ui/preferences/TcpSettings.qml</file>
<file alias="TaisyncSettings.qml">src/Taisync/TaisyncSettings.qml</file>
<file alias="test.qml">src/test.qml</file>
<file alias="UdpSettings.qml">src/ui/preferences/UdpSettings.qml</file>
<file alias="ValuePageWidget.qml">src/FlightMap/Widgets/ValuePageWidget.qml</file>
<file alias="VehicleSummary.qml">src/VehicleSetup/VehicleSummary.qml</file>
<file alias="VibrationPageWidget.qml">src/FlightMap/Widgets/VibrationPageWidget.qml</file>
<file alias="VideoPageWidget.qml">src/FlightMap/Widgets/VideoPageWidget.qml</file>
<file alias="VirtualJoystick.qml">src/FlightDisplay/VirtualJoystick.qml</file>
<file alias="QGroundControl/Controls/WimaToolBar.qml">src/WimaView/WimaToolBar.qml</file>
<file alias="WimaView.qml">src/WimaView/WimaView.qml</file>
<file alias="QGroundControl/Controls/WimaMapVisual.qml">src/WimaView/WimaMapVisual.qml</file>
<file alias="QGroundControl/Controls/WimaItemEditor.qml">src/WimaView/WimaItemEditor.qml</file>
<file alias="QGroundControl/Controls/WimaMapPolylineVisuals.qml">src/WimaView/WimaMapPolylineVisuals.qml</file>
<file alias="QGroundControl/Controls/WimaMapPolygonVisuals.qml">src/WimaView/WimaMapPolygonVisuals.qml</file>
<file alias="QGroundControl/Controls/WimaServiceAreaMapVisual.qml">src/WimaView/WimaServiceAreaMapVisual.qml</file>
<file alias="QGroundControl/Controls/WimaServiceAreaEditor.qml">src/WimaView/WimaServiceAreaEditor.qml</file>
<file alias="QGroundControl/Controls/WimaAreaMapVisual.qml">src/WimaView/WimaAreaMapVisual.qml</file>
<file alias="QGroundControl/Controls/WimaMeasurementAreaMapVisual.qml">src/WimaView/WimaMeasurementAreaMapVisual.qml</file>
<file alias="QGroundControl/Controls/WimaCorridorMapVisual.qml">src/WimaView/WimaCorridorMapVisual.qml</file>
<file alias="QGroundControl/Controls/WimaMeasurementAreaEditor.qml">src/WimaView/WimaMeasurementAreaEditor.qml</file>
<file alias="CircularSurveyItemEditor.qml">src/PlanView/CircularSurveyItemEditor.qml</file>
<file alias="QGroundControl/Controls/DragCoordinate.qml">src/WimaView/DragCoordinate.qml</file>
<file alias="QGroundControl/Controls/CoordinateIndicatorDrag.qml">src/WimaView/CoordinateIndicatorDrag.qml</file>
<file alias="QGroundControl/Controls/CoordinateIndicator.qml">src/WimaView/CoordinateIndicator.qml</file>
<file alias="QGroundControl/Controls/WimaJoinedAreaMapVisual.qml">src/WimaView/WimaJoinedAreaMapVisual.qml</file>
<file alias="QGroundControl/Controls/WimaCorridorEditor.qml">src/WimaView/WimaCorridorEditor.qml</file>
<file alias="QGroundControl/FlightMap/WimaPlanMapItems.qml">src/FlightMap/MapItems/WimaPlanMapItems.qml</file>
<file alias="QGroundControl/FlightMap/WimaMissionItemMapVisual.qml">src/PlanView/WimaMissionItemMapVisual.qml</file>
<file alias="QGroundControl/FlightDisplay/FlightDisplayWimaMenu.qml">src/FlightDisplay/FlightDisplayWimaMenu.qml</file>
<file alias="CustomCommandWidget.qml">src/ViewWidgets/CustomCommandWidget.qml</file>
<file alias="QGroundControl/Controls/ViewWidget.qml">src/ViewWidgets/ViewWidget.qml</file>
<file alias="Wima/WimaAreaNoVisual.qml">src/Wima/Snake/WimaAreaNoVisual.qml</file>
<file alias="CircularGeneratorEditor.qml">src/WimaView/CircularGeneratorEditor.qml</file>
<file alias="QGroundControl/Controls/CircularGeneratorMapVisual.qml">src/WimaView/CircularGeneratorMapVisual.qml</file>
<file alias="CircularSurveyItemEditor.qml">src/WimaView/CircularSurveyItemEditor.qml</file>
<file alias="QGroundControl/Controls/CircularSurveyMapVisual.qml">src/WimaView/CircularSurveyMapVisual.qml</file>
<file alias="QGroundControl/FlightDisplay/SmallValue.qml">src/FlightDisplay/SmallValue.qml</file>
<file alias="QGroundControl/Controls/ProgressIndicator.qml">src/WimaView/ProgressIndicator.qml</file>
<file alias="QGroundControl/Controls/WimaServiceAreaDataVisual.qml">src/WimaView/WimaServiceAreaDataVisual.qml</file>
<file alias="QGroundControl/Controls/WimaCorridorDataVisual.qml">src/WimaView/WimaCorridorDataVisual.qml</file>
<file alias="QGroundControl/Controls/WimaJoinedAreaDataVisual.qml">src/WimaView/WimaJoinedAreaDataVisual.qml</file>
<file alias="QGroundControl/Controls/WimaAreaNoVisual.qml">src/Wima/Snake/WimaAreaNoVisual.qml</file>
<file alias="QGroundControl/Controls/WimaMeasurementAreaDataVisual.qml">src/WimaView/WimaMeasurementAreaDataVisual.qml</file>
<file alias="QGroundControl/Controls/QGCButtonColumn.qml">src/QmlControls/QGCButtonColumn.qml</file>
<file alias="Wima/CoordinateIndicator.qml">src/WimaView/CoordinateIndicator.qml</file>
<file alias="Wima/CoordinateIndicatorDrag.qml">src/WimaView/CoordinateIndicatorDrag.qml</file>
<file alias="Wima/DragCoordinate.qml">src/WimaView/DragCoordinate.qml</file>
<file alias="LinearGeneratorEditor.qml">src/WimaView/LinearGeneratorEditor.qml</file>
<file alias="Wima/ProgressIndicator.qml">src/WimaView/ProgressIndicator.qml</file>
<file alias="Wima/qmldir">src/WimaView/Wima.qmldir</file>
<file alias="Wima/WimaAreaMapVisual.qml">src/WimaView/WimaAreaMapVisual.qml</file>
<file alias="Wima/WimaCorridorDataVisual.qml">src/WimaView/WimaCorridorDataVisual.qml</file>
<file alias="Wima/WimaCorridorEditor.qml">src/WimaView/WimaCorridorEditor.qml</file>
<file alias="Wima/WimaCorridorMapVisual.qml">src/WimaView/WimaCorridorMapVisual.qml</file>
<file alias="Wima/WimaItemEditor.qml">src/WimaView/WimaItemEditor.qml</file>
<file alias="Wima/WimaJoinedAreaDataVisual.qml">src/WimaView/WimaJoinedAreaDataVisual.qml</file>
<file alias="Wima/WimaJoinedAreaMapVisual.qml">src/WimaView/WimaJoinedAreaMapVisual.qml</file>
<file alias="Wima/WimaMapPolygonVisuals.qml">src/WimaView/WimaMapPolygonVisuals.qml</file>
<file alias="Wima/WimaMapPolylineVisuals.qml">src/WimaView/WimaMapPolylineVisuals.qml</file>
<file alias="Wima/WimaMapVisual.qml">src/WimaView/WimaMapVisual.qml</file>
<file alias="Wima/WimaMeasurementAreaDataVisual.qml">src/WimaView/WimaMeasurementAreaDataVisual.qml</file>
<file alias="Wima/WimaMeasurementAreaEditor.qml">src/WimaView/WimaMeasurementAreaEditor.qml</file>
<file alias="Wima/WimaMeasurementAreaMapVisual.qml">src/WimaView/WimaMeasurementAreaMapVisual.qml</file>
<file alias="Wima/WimaServiceAreaDataVisual.qml">src/WimaView/WimaServiceAreaDataVisual.qml</file>
<file alias="Wima/WimaServiceAreaEditor.qml">src/WimaView/WimaServiceAreaEditor.qml</file>
<file alias="Wima/WimaServiceAreaMapVisual.qml">src/WimaView/WimaServiceAreaMapVisual.qml</file>
<file alias="Wima/WimaToolBar.qml">src/WimaView/WimaToolBar.qml</file>
<file alias="WimaView.qml">src/WimaView/WimaView.qml</file>
<file alias="test.qml">src/test.qml</file>
<file alias="AppSettings.qml">src/ui/AppSettings.qml</file>
<file alias="MainWindowHybrid.qml">src/ui/MainWindowHybrid.qml</file>
<file alias="MainWindowInner.qml">src/ui/MainWindowInner.qml</file>
<file alias="MainWindowNative.qml">src/ui/MainWindowNative.qml</file>
<file alias="BluetoothSettings.qml">src/ui/preferences/BluetoothSettings.qml</file>
<file alias="DebugWindow.qml">src/ui/preferences/DebugWindow.qml</file>
<file alias="GeneralSettings.qml">src/ui/preferences/GeneralSettings.qml</file>
<file alias="HelpSettings.qml">src/ui/preferences/HelpSettings.qml</file>
<file alias="LinkSettings.qml">src/ui/preferences/LinkSettings.qml</file>
<file alias="LogReplaySettings.qml">src/ui/preferences/LogReplaySettings.qml</file>
<file alias="MavlinkSettings.qml">src/ui/preferences/MavlinkSettings.qml</file>
<file alias="MockLink.qml">src/ui/preferences/MockLink.qml</file>
<file alias="MockLinkSettings.qml">src/ui/preferences/MockLinkSettings.qml</file>
<file alias="SerialSettings.qml">src/ui/preferences/SerialSettings.qml</file>
<file alias="TcpSettings.qml">src/ui/preferences/TcpSettings.qml</file>
<file alias="UdpSettings.qml">src/ui/preferences/UdpSettings.qml</file>
<file alias="QGroundControl/Controls/MainToolBar.qml">src/ui/toolbar/MainToolBar.qml</file>
<file alias="QGroundControl/Controls/MainToolBarIndicators.qml">src/ui/toolbar/MainToolBarIndicators.qml</file>
<file alias="QGroundControl/Controls/SignalStrength.qml">src/ui/toolbar/SignalStrength.qml</file>
</qresource>
<qresource prefix="/json">
<file alias="APMMavlinkStreamRate.SettingsGroup.json">src/Settings/APMMavlinkStreamRate.SettingsGroup.json</file>
<file alias="CameraCalc.FactMetaData.json">src/MissionManager/CameraCalc.FactMetaData.json</file>
<file alias="CameraSection.FactMetaData.json">src/MissionManager/CameraSection.FactMetaData.json</file>
<file alias="CameraSpec.FactMetaData.json">src/MissionManager/CameraSpec.FactMetaData.json</file>
<file alias="CorridorScan.SettingsGroup.json">src/MissionManager/CorridorScan.SettingsGroup.json</file>
<file alias="EditPositionDialog.FactMetaData.json">src/QmlControls/EditPositionDialog.FactMetaData.json</file>
<file alias="QGCMapCircle.Facts.json">src/MissionManager/QGCMapCircle.Facts.json</file>
<file alias="StructureScan.SettingsGroup.json">src/MissionManager/StructureScan.SettingsGroup.json</file>
<file alias="TransectStyle.SettingsGroup.json">src/MissionManager/TransectStyle.SettingsGroup.json</file>
<file alias="App.SettingsGroup.json">src/Settings/App.SettingsGroup.json</file>
<file alias="AutoConnect.SettingsGroup.json">src/Settings/AutoConnect.SettingsGroup.json</file>
<file alias="BrandImage.SettingsGroup.json">src/Settings/BrandImage.SettingsGroup.json</file>
<file alias="CameraSection.FactMetaData.json">src/MissionManager/CameraSection.FactMetaData.json</file>
<file alias="FlightMap.SettingsGroup.json">src/Settings/FlightMap.SettingsGroup.json</file>
<file alias="FWLandingPattern.FactMetaData.json">src/MissionManager/FWLandingPattern.FactMetaData.json</file>
<file alias="FlyView.SettingsGroup.json">src/Settings/FlyView.SettingsGroup.json</file>
<file alias="PlanView.SettingsGroup.json">src/Settings/PlanView.SettingsGroup.json</file>
<file alias="MavCmdInfoCommon.json">src/MissionManager/MavCmdInfoCommon.json</file>
<file alias="MavCmdInfoFixedWing.json">src/MissionManager/MavCmdInfoFixedWing.json</file>
<file alias="MavCmdInfoMultiRotor.json">src/MissionManager/MavCmdInfoMultiRotor.json</file>
......@@ -263,12 +256,24 @@
<file alias="MavCmdInfoSub.json">src/MissionManager/MavCmdInfoSub.json</file>
<file alias="MavCmdInfoVTOL.json">src/MissionManager/MavCmdInfoVTOL.json</file>
<file alias="MissionSettings.FactMetaData.json">src/MissionManager/MissionSettings.FactMetaData.json</file>
<file alias="QGCMapCircle.Facts.json">src/MissionManager/QGCMapCircle.Facts.json</file>
<file alias="RallyPoint.FactMetaData.json">src/MissionManager/RallyPoint.FactMetaData.json</file>
<file alias="RTK.SettingsGroup.json">src/Settings/RTK.SettingsGroup.json</file>
<file alias="SpeedSection.FactMetaData.json">src/MissionManager/SpeedSection.FactMetaData.json</file>
<file alias="StructureScan.SettingsGroup.json">src/MissionManager/StructureScan.SettingsGroup.json</file>
<file alias="Survey.SettingsGroup.json">src/MissionManager/Survey.SettingsGroup.json</file>
<file alias="TransectStyle.SettingsGroup.json">src/MissionManager/TransectStyle.SettingsGroup.json</file>
<file alias="EditPositionDialog.FactMetaData.json">src/QmlControls/EditPositionDialog.FactMetaData.json</file>
<file alias="APMMavlinkStreamRate.SettingsGroup.json">src/Settings/APMMavlinkStreamRate.SettingsGroup.json</file>
<file alias="App.SettingsGroup.json">src/Settings/App.SettingsGroup.json</file>
<file alias="AutoConnect.SettingsGroup.json">src/Settings/AutoConnect.SettingsGroup.json</file>
<file alias="BrandImage.SettingsGroup.json">src/Settings/BrandImage.SettingsGroup.json</file>
<file alias="FlightMap.SettingsGroup.json">src/Settings/FlightMap.SettingsGroup.json</file>
<file alias="FlyView.SettingsGroup.json">src/Settings/FlyView.SettingsGroup.json</file>
<file alias="PlanView.SettingsGroup.json">src/Settings/PlanView.SettingsGroup.json</file>
<file alias="RTK.SettingsGroup.json">src/Settings/RTK.SettingsGroup.json</file>
<file alias="Units.SettingsGroup.json">src/Settings/Units.SettingsGroup.json</file>
<file alias="USBBoardInfo.json">src/comm/USBBoardInfo.json</file>
<file alias="Video.SettingsGroup.json">src/Settings/Video.SettingsGroup.json</file>
<file alias="Wima.SettingsGroup.json">src/Settings/Wima.SettingsGroup.json</file>
<file alias="Vehicle/BatteryFact.json">src/Vehicle/BatteryFact.json</file>
<file alias="Vehicle/ClockFact.json">src/Vehicle/ClockFact.json</file>
<file alias="Vehicle/DistanceSensorFact.json">src/Vehicle/DistanceSensorFact.json</file>
......@@ -281,12 +286,13 @@
<file alias="Vehicle/VehicleFact.json">src/Vehicle/VehicleFact.json</file>
<file alias="Vehicle/VibrationFact.json">src/Vehicle/VibrationFact.json</file>
<file alias="Vehicle/WindFact.json">src/Vehicle/WindFact.json</file>
<file alias="Video.SettingsGroup.json">src/Settings/Video.SettingsGroup.json</file>
<file alias="WimaArea.SettingsGroup.json">src/Wima/Geometry/json/WimaArea.SettingsGroup.json</file>
<file alias="WimaMeasurementArea.SettingsGroup.json">src/Wima/Geometry/json/WimaMeasurementArea.SettingsGroup.json</file>
<file alias="CircularGenerator.SettingsGroup.json">src/Wima/Snake/json/CircularGenerator.SettingsGroup.json</file>
<file alias="LinearGenerator.SettingsGroup.json">src/Wima/Snake/json/LinearGenerator.SettingsGroup.json</file>
<file alias="CircularSurvey.SettingsGroup.json">src/Wima/json/CircularSurvey.SettingsGroup.json</file>
<file alias="WimaArea.SettingsGroup.json">src/Wima/Geometry/json/WimaArea.SettingsGroup.json</file>
<file alias="WimaController.SettingsGroup.json">src/Wima/json/WimaController.SettingsGroup.json</file>
<file alias="Wima.SettingsGroup.json">src/Settings/Wima.SettingsGroup.json</file>
<file alias="USBBoardInfo.json">src/comm/USBBoardInfo.json</file>
</qresource>
<qresource prefix="/MockLink">
<file alias="APMArduCopterMockLink.params">src/comm/APMArduCopterMockLink.params</file>
......
......@@ -24,6 +24,8 @@ import QGroundControl.Palette 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Vehicle 1.0
import Wima 1.0
FlightMap {
id: flightMap
anchors.fill: parent
......
......@@ -30,5 +30,9 @@ MapItemView {
object.coordinate1,
object.coordinate2,
] : []
// onParentChanged: {
// console.log("MapItemView, path:" + path)
// }
}
}
......@@ -15,7 +15,7 @@ import QtPositioning 5.3
import QGroundControl.ScreenTools 1.0
import QGroundControl.Palette 1.0
import QGroundControl.Controls 1.0
import Wima 1.0
/// Mission item map visual
Item {
......
......@@ -89,6 +89,8 @@
#include "VideoSurface.h"
#include "ViewWidgetController.h"
#include "VisualMissionItem.h"
#include "Wima/Snake/CircularGenerator.h"
#include "Wima/Snake/LinearGenerator.h"
#include "Wima/Snake/NemoInterface.h"
#include "Wima/WimaController.h"
#include "Wima/WimaPlaner.h"
......@@ -520,6 +522,10 @@ void QGCApplication::_initCommon(void) {
qmlRegisterType<WimaController>("Wima", 1, 0, "WimaController");
qmlRegisterType<WimaPlaner>("Wima", 1, 0, "WimaPlaner");
qmlRegisterType<NemoInterface>("Wima", 1, 0, "NemoInterface");
qmlRegisterInterface<routing::GeneratorBase>("GeneratorBase");
qmlRegisterType<routing::CircularGenerator>("Wima", 1, 0,
"CircularGenerator");
qmlRegisterType<routing::LinearGenerator>("Wima", 1, 0, "LinearGenerator");
// Register Qml Singletons
qmlRegisterSingletonType<QGroundControlQmlGlobal>(
......
......@@ -65,7 +65,6 @@ QGCViewDialog 1.0 QGCViewDialog.qml
QGCViewDialogContainer 1.0 QGCViewDialogContainer.qml
QGCViewMessage 1.0 QGCViewMessage.qml
QGCViewPanel 1.0 QGCViewPanel.qml
WimaToolBar 1.0 WimaToolBar.qml
RallyPointEditorHeader 1.0 RallyPointEditorHeader.qml
RallyPointItemEditor 1.0 RallyPointItemEditor.qml
RallyPointMapVisuals 1.0 RallyPointMapVisuals.qml
......@@ -85,22 +84,6 @@ VehicleSummaryRow 1.0 VehicleSummaryRow.qml
ViewWidget 1.0 ViewWidget.qml
FlyAreaItemEditor 1.0 FlyAreaItemEditor.qml
WimaMapVisual 1.0 WimaMapVisual.qml
WimaMeasurementAreaMapVisual 1.0 WimaMeasurementAreaMapVisual.qml
WimaJoinedAreaMapVisual 1.0 WimaJoinedAreaMapVisual.qml
WimaMeasurementAreaEditor 1.0 WimaMeasurementAreaEditor.qml
WimaServiceAreaMapVisual 1.0 WimaServiceAreaMapVisual.qml
WimaAreaMapVisual 1.0 WimaAreaMapVisual.qml
WimaServiceAreaEditor 1.0 WimaServiceAreaEditor.qml
WimaCorridorMapVisual 1.0 WimaCorridorMapVisual.qml
WimaItemEditor 1.0 WimaItemEditor.qml
WimaMapPolygonVisuals 1.0 WimaMapPolygonVisuals.qml
WimaMapPolylineVisuals 1.0 WimaMapPolylineVisuals.qml
CircularSurveyMapVisual 1.0 CircularSurveyMapVisual.qml
DragCoordinate 1.0 DragCoordinate.qml
CoordinateIndicator 1.0 CoordinateIndicator.qml
CoordinateIndicatorDrag 1.0 CoordinateIndicatorDrag.qml
ProgressIndicator 1.0 ProgressIndicator.qml
QGCButtonColumn 1.0 QGCButtonColumn.qml
......@@ -16,92 +16,36 @@
#include <boost/units/io.hpp>
#include <boost/units/systems/si.hpp>
QGC_LOGGING_CATEGORY(CircularSurveyLog, "CircularSurveyLog")
using namespace ClipperLib;
template <> auto get<0>(const IntPoint &p) { return p.X; }
template <> auto get<1>(const IntPoint &p) { return p.Y; }
template <class Functor> class CommandRAII {
public:
CommandRAII(Functor f) : fun(f) {}
~CommandRAII() { fun(); }
#include "CircularGenerator.h"
#include "LinearGenerator.h"
private:
Functor fun;
};
QGC_LOGGING_CATEGORY(CircularSurveyLog, "CircularSurveyLog")
template <typename T>
constexpr typename std::underlying_type<T>::type integral(T value) {
return static_cast<typename std::underlying_type<T>::type>(value);
}
bool circularTransects(const snake::FPolygon &polygon,
const std::vector<snake::FPolygon> &tiles,
snake::Length deltaR, snake::Angle deltaAlpha,
snake::Length minLength, snake::Transects &transects);
bool linearTransects(const snake::FPolygon &polygon,
const std::vector<snake::FPolygon> &tiles,
snake::Length distance, snake::Angle angle,
snake::Length minLength, snake::Transects &transects);
const char *CircularSurvey::settingsGroup = "CircularSurvey";
const char *CircularSurvey::transectDistanceName = "TransectDistance";
const char *CircularSurvey::alphaName = "Alpha";
const char *CircularSurvey::minLengthName = "MinLength";
const char *CircularSurvey::typeName = "Type";
const char *CircularSurvey::CircularSurveyName = "CircularSurvey";
const char *CircularSurvey::refPointLatitudeName = "ReferencePointLat";
const char *CircularSurvey::refPointLongitudeName = "ReferencePointLong";
const char *CircularSurvey::refPointAltitudeName = "ReferencePointAlt";
const char *CircularSurvey::variantName = "Variant";
const char *CircularSurvey::numRunsName = "NumRuns";
const char *CircularSurvey::runName = "Run";
CircularSurvey::CircularSurvey(Vehicle *vehicle, bool flyView,
const QString &kmlOrShpFile, QObject *parent)
: TransectStyleComplexItem(vehicle, flyView, settingsGroup, parent),
_referencePoint(QGeoCoordinate(0, 0, 0)),
_state(STATE::IDLE),
_metaDataMap(FactMetaData::createMapFromJsonFile(
QStringLiteral(":/json/CircularSurvey.SettingsGroup.json"), this)),
_transectDistance(settingsGroup, _metaDataMap[transectDistanceName]),
_alpha(settingsGroup, _metaDataMap[alphaName]),
_minLength(settingsGroup, _metaDataMap[minLengthName]),
_type(settingsGroup, _metaDataMap[typeName]),
_variant(settingsGroup, _metaDataMap[variantName]),
_numRuns(settingsGroup, _metaDataMap[numRunsName]),
_run(settingsGroup, _metaDataMap[runName]),
_pWorker(std::make_unique<RoutingThread>()), _state(STATE::DEFAULT),
_hidePolygon(false) {
_pAreaData(std::make_shared<WimaPlanData>()),
_pWorker(std::make_unique<RoutingThread>()) {
Q_UNUSED(kmlOrShpFile)
_editorQml = "qrc:/qml/CircularSurveyItemEditor.qml";
// Connect facts.
connect(&_transectDistance, &Fact::valueChanged, this,
&CircularSurvey::_rebuildTransects);
connect(&_alpha, &Fact::valueChanged, this,
&CircularSurvey::_rebuildTransects);
connect(&_minLength, &Fact::valueChanged, this,
&CircularSurvey::_rebuildTransects);
connect(this, &CircularSurvey::refPointChanged, this,
&CircularSurvey::_rebuildTransects);
connect(this, &CircularSurvey::depotChanged, this,
&CircularSurvey::_rebuildTransects);
connect(&this->_type, &Fact::rawValueChanged, this,
&CircularSurvey::_rebuildTransects);
connect(&this->_variant, &Fact::rawValueChanged, this,
&CircularSurvey::_changeVariant);
connect(&this->_run, &Fact::rawValueChanged, this,
&CircularSurvey::_changeRun);
connect(&this->_numRuns, &Fact::rawValueChanged, this,
&CircularSurvey::_rebuildTransects);
// Areas.
connect(this, &CircularSurvey::measurementAreaChanged, this,
&CircularSurvey::_rebuildTransects);
connect(this, &CircularSurvey::joinedAreaChanged, this,
&CircularSurvey::_rebuildTransects);
// Connect worker.
connect(this->_pWorker.get(), &RoutingThread::result, this,
......@@ -115,87 +59,32 @@ CircularSurvey::CircularSurvey(Vehicle *vehicle, bool flyView,
&CircularSurvey::coordinateHasRelativeAltitudeChanged);
connect(&_cameraCalc, &CameraCalc::distanceToSurfaceRelativeChanged, this,
&CircularSurvey::exitCoordinateHasRelativeAltitudeChanged);
// Register Generators.
auto lg = std::make_shared<routing::LinearGenerator>(this->_pAreaData);
registerGenerator(lg->name(), lg);
auto cg = std::make_shared<routing::CircularGenerator>(this->_pAreaData);
registerGenerator(cg->name(), cg);
}
CircularSurvey::~CircularSurvey() {}
void CircularSurvey::resetReference() { setRefPoint(_mArea.center()); }
void CircularSurvey::reverse() {
this->_state = STATE::REVERSE;
this->_rebuildTransects();
}
void CircularSurvey::setRefPoint(const QGeoCoordinate &refPt) {
if (refPt != _referencePoint) {
_referencePoint = refPt;
_referencePoint.setAltitude(0);
emit refPointChanged();
}
void CircularSurvey::setPlanData(const WimaPlanData &d) {
*this->_pAreaData = d;
}
QGeoCoordinate CircularSurvey::refPoint() const { return _referencePoint; }
Fact *CircularSurvey::transectDistance() { return &_transectDistance; }
Fact *CircularSurvey::alpha() { return &_alpha; }
bool CircularSurvey::hidePolygon() const { return _hidePolygon; }
QList<QString> CircularSurvey::variantNames() const { return _variantNames; }
QList<QString> CircularSurvey::runNames() const { return _runNames; }
QGeoCoordinate CircularSurvey::depot() const { return this->_depot; }
const QList<QList<QGeoCoordinate>> &CircularSurvey::rawTransects() const {
return this->_rawTransects;
const WimaPlanData &CircularSurvey::planData() const {
return *this->_pAreaData;
}
void CircularSurvey::setHidePolygon(bool hide) {
if (this->_hidePolygon != hide) {
this->_hidePolygon = hide;
emit hidePolygonChanged();
}
}
void CircularSurvey::setMeasurementArea(const WimaMeasurementAreaData &mArea) {
if (this->_mArea != mArea) {
this->_mArea = mArea;
emit measurementAreaChanged();
}
}
void CircularSurvey::setJoinedArea(const WimaJoinedAreaData &jArea) {
if (this->_jArea != jArea) {
this->_jArea = jArea;
emit joinedAreaChanged();
}
}
WimaPlanData &CircularSurvey::planData() { return *this->_pAreaData; }
void CircularSurvey::setMeasurementArea(const WimaMeasurementArea &mArea) {
if (this->_mArea != mArea) {
this->_mArea = mArea;
emit measurementAreaChanged();
}
}
void CircularSurvey::setJoinedArea(const WimaJoinedArea &jArea) {
if (this->_jArea != jArea) {
this->_jArea = jArea;
emit joinedAreaChanged();
}
}
void CircularSurvey::setDepot(const QGeoCoordinate &depot) {
if (this->_depot.latitude() != depot.latitude() ||
this->_depot.longitude() != depot.longitude()) {
this->_depot = depot;
this->_depot.setAltitude(0);
emit depotChanged();
}
}
QStringList CircularSurvey::variantNames() const { return _variantNames; }
bool CircularSurvey::load(const QJsonObject &complexObject, int sequenceNumber,
QString &errorString) {
......@@ -218,16 +107,7 @@ bool CircularSurvey::load(const QJsonObject &complexObject, int sequenceNumber,
QList<JsonHelper::KeyValidateInfo> keyInfoList = {
{VisualMissionItem::jsonTypeKey, QJsonValue::String, true},
{ComplexMissionItem::jsonComplexItemTypeKey, QJsonValue::String, true},
{transectDistanceName, QJsonValue::Double, true},
{alphaName, QJsonValue::Double, true},
{minLengthName, QJsonValue::Double, true},
{typeName, QJsonValue::Double, true},
{variantName, QJsonValue::Double, false},
{numRunsName, QJsonValue::Double, false},
{runName, QJsonValue::Double, false},
{refPointLatitudeName, QJsonValue::Double, true},
{refPointLongitudeName, QJsonValue::Double, true},
{refPointAltitudeName, QJsonValue::Double, true},
};
if (!JsonHelper::validateKeys(complexObject, keyInfoList, errorString)) {
......@@ -262,16 +142,7 @@ bool CircularSurvey::load(const QJsonObject &complexObject, int sequenceNumber,
return false;
}
_transectDistance.setRawValue(complexObject[transectDistanceName].toDouble());
_alpha.setRawValue(complexObject[alphaName].toDouble());
_minLength.setRawValue(complexObject[minLengthName].toDouble());
_type.setRawValue(complexObject[typeName].toInt());
_variant.setRawValue(complexObject[variantName].toInt());
_numRuns.setRawValue(complexObject[numRunsName].toInt());
_run.setRawValue(complexObject[runName].toInt());
_referencePoint.setLongitude(complexObject[refPointLongitudeName].toDouble());
_referencePoint.setLatitude(complexObject[refPointLatitudeName].toDouble());
_referencePoint.setAltitude(complexObject[refPointAltitudeName].toDouble());
_ignoreRecalc = false;
......@@ -298,16 +169,7 @@ void CircularSurvey::save(QJsonArray &planItems) {
VisualMissionItem::jsonTypeComplexItemValue;
saveObject[ComplexMissionItem::jsonComplexItemTypeKey] = CircularSurveyName;
saveObject[transectDistanceName] = _transectDistance.rawValue().toDouble();
saveObject[alphaName] = _alpha.rawValue().toDouble();
saveObject[minLengthName] = _minLength.rawValue().toDouble();
saveObject[typeName] = double(_type.rawValue().toUInt());
saveObject[variantName] = double(_variant.rawValue().toUInt());
saveObject[numRunsName] = double(_numRuns.rawValue().toUInt());
saveObject[runName] = double(_numRuns.rawValue().toUInt());
saveObject[refPointLongitudeName] = _referencePoint.longitude();
saveObject[refPointLatitudeName] = _referencePoint.latitude();
saveObject[refPointAltitudeName] = _referencePoint.altitude();
// Polygon shape
_surveyAreaPolygon.saveToJson(saveObject);
......@@ -379,13 +241,31 @@ void CircularSurvey::_buildAndAppendMissionItems(QList<MissionItem *> &items,
}
}
void CircularSurvey::_changeVariant() {
this->_state = STATE::VARIANT_CHANGE;
this->_rebuildTransects();
bool CircularSurvey::_switchToGenerator(
const CircularSurvey::PtrGenerator &newG) {
if (this->_pGenerator != newG) {
if (this->_pGenerator != nullptr) {
disconnect(this->_pGenerator.get(),
&routing::GeneratorBase::generatorChanged, this,
&CircularSurvey::_rebuildTransects);
}
this->_pGenerator = newG;
connect(this->_pGenerator.get(), &routing::GeneratorBase::generatorChanged,
this, &CircularSurvey::_rebuildTransects);
emit generatorChanged();
this->_state = STATE::IDLE;
_rebuildTransects();
return true;
} else {
return false;
}
}
void CircularSurvey::_changeRun() {
this->_state = STATE::RUN_CHANGE;
void CircularSurvey::_changeVariant() {
this->_state = STATE::VARIANT_CHANGE;
this->_rebuildTransects();
}
......@@ -394,204 +274,105 @@ void CircularSurvey::_updateWorker() {
this->_transectsDirty = true;
// Reset data.
this->_transects.clear();
this->_rawTransects.clear();
this->_variantVector.clear();
this->_variantNames.clear();
this->_runNames.clear();
emit variantNamesChanged();
emit runNamesChanged();
// Prepare data.
auto ref = this->_referencePoint;
auto geoPolygon = this->_mArea.coordinateList();
for (auto &v : geoPolygon) {
v.setAltitude(0);
}
auto pPolygon = std::make_shared<snake::FPolygon>();
snake::areaToEnu(ref, geoPolygon, *pPolygon);
// Progress and tiles.
const auto &progress = this->_mArea.progress();
const auto *tiles = this->_mArea.tiles();
auto pTiles = std::make_shared<std::vector<snake::FPolygon>>();
if (progress.size() == tiles->count()) {
for (int i = 0; i < tiles->count(); ++i) {
if (progress[i] == 100) {
const auto *tile = tiles->value<const SnakeTile *>(i);
if (tile != nullptr) {
snake::FPolygon tileENU;
snake::areaToEnu(ref, tile->coordinateList(), tileENU);
pTiles->push_back(std::move(tileENU));
} else {
qCWarning(CircularSurveyLog)
<< "_updateWorker(): progress.size() != tiles->count().";
return;
}
}
}
} else {
qCWarning(CircularSurveyLog)
<< "_updateWorker(): progress.size() != tiles->count().";
return;
}
if (this->_pAreaData->isValid()) {
// Convert safe area.
auto geoDepot = this->_depot;
auto geoSafeArea = this->_jArea.coordinateList();
if (!geoDepot.isValid()) {
qCWarning(CircularSurveyLog)
<< "_updateWorker(): depot invalid." << geoDepot;
return;
}
if (!(geoSafeArea.size() >= 3)) {
qCWarning(CircularSurveyLog)
<< "_updateWorker(): safe area invalid." << geoSafeArea;
return;
}
for (auto &v : geoSafeArea) {
v.setAltitude(0);
}
snake::FPoint depot;
snake::toENU(ref, geoDepot, depot);
// Routing par.
RoutingParameter par;
par.numSolutionsPerRun = 5;
if (this->_numRuns.rawValue().toUInt() < 1) {
disconnect(&this->_numRuns, &Fact::rawValueChanged, this,
&CircularSurvey::_rebuildTransects);
// Prepare data.
auto origin = this->_pAreaData->origin();
origin.setAltitude(0);
if (!origin.isValid()) {
qCDebug(CircularSurveyLog)
<< "_updateWorker(): origin invalid." << origin;
return;
}
this->_numRuns.setCookedValue(QVariant(1));
// Convert safe area.
auto geoSafeArea = this->_pAreaData->joinedArea().coordinateList();
if (!(geoSafeArea.size() >= 3)) {
qCDebug(CircularSurveyLog)
<< "_updateWorker(): safe area invalid." << geoSafeArea;
return;
}
for (auto &v : geoSafeArea) {
if (v.isValid()) {
v.setAltitude(0);
} else {
qCDebug(CircularSurveyLog)
<< "_updateWorker(): safe area contains invalid coordinate."
<< geoSafeArea;
return;
}
}
connect(&this->_numRuns, &Fact::rawValueChanged, this,
&CircularSurvey::_rebuildTransects);
}
par.numRuns = this->_numRuns.rawValue().toUInt();
auto &safeAreaENU = par.safeArea;
snake::areaToEnu(ref, geoSafeArea, safeAreaENU);
// Fetch transect parameter.
auto distance = snake::Length(this->_transectDistance.rawValue().toDouble() *
bu::si::meter);
auto minLength =
snake::Length(this->_minLength.rawValue().toDouble() * bu::si::meter);
auto alpha =
snake::Angle(this->_alpha.rawValue().toDouble() * bu::degree::degree);
// Select survey type.
if (this->_type.rawValue().toUInt() == integral(Type::Circular)) {
// Clip angle.
if (alpha >= snake::Angle(0.3 * bu::degree::degree) &&
alpha <= snake::Angle(45 * bu::degree::degree)) {
auto generator = [depot, pPolygon, pTiles, distance, alpha,
minLength](snake::Transects &transects) -> bool {
bool value = circularTransects(*pPolygon, *pTiles, distance, alpha,
minLength, transects);
transects.insert(transects.begin(), snake::FLineString{depot});
return value;
};
// Start routing worker.
this->_pWorker->route(par, generator);
} else {
if (alpha < snake::Angle(0.3 * bu::degree::degree)) {
this->_alpha.setCookedValue(QVariant(0.3));
// Routing par.
RoutingParameter par;
par.numSolutions = 5;
auto &safeAreaENU = par.safeArea;
snake::areaToEnu(origin, geoSafeArea, safeAreaENU);
// Create generator.
if (this->_pGenerator) {
routing::GeneratorBase::Generator g; // Transect generator.
if (this->_pGenerator->get(g)) {
// Start/Restart routing worker.
this->_pWorker->route(par, g);
} else {
this->_alpha.setCookedValue(QVariant(45));
qCDebug(CircularSurveyLog)
<< "_updateWorker(): generator creation failed.";
}
} else {
qCDebug(CircularSurveyLog)
<< "_updateWorker(): pGenerator == nullptr, number of registered "
"generators: "
<< this->_generatorList.size();
}
} else if (this->_type.rawValue().toUInt() == integral(Type::Linear)) {
auto generator = [depot, pPolygon, pTiles, distance, alpha,
minLength](snake::Transects &transects) -> bool {
bool value = linearTransects(*pPolygon, *pTiles, distance, alpha,
minLength, transects);
transects.insert(transects.begin(), snake::FLineString{depot});
return value;
};
// Start routing worker.
this->_pWorker->route(par, generator);
} else {
qCWarning(CircularSurveyLog)
<< "CircularSurvey::rebuildTransectsPhase1(): invalid survey type:"
<< this->_type.rawValue().toUInt();
qCDebug(CircularSurveyLog) << "_updateWorker(): plan data invalid.";
}
}
void CircularSurvey::_changeVariantRunWorker() {
void CircularSurvey::_changeVariantWorker() {
auto variant = this->_variant.rawValue().toUInt();
auto run = this->_run.rawValue().toUInt();
// Find old variant and run. Old run corresponts with empty list.
std::size_t old_variant = std::numeric_limits<std::size_t>::max();
std::size_t old_run = std::numeric_limits<std::size_t>::max();
for (std::size_t i = 0; i < std::size_t(this->_variantVector.size()); ++i) {
const auto &solution = this->_variantVector.at(i);
for (std::size_t j = 0; j < std::size_t(solution.size()); ++j) {
const auto &r = solution[j];
if (r.isEmpty()) {
old_variant = i;
old_run = j;
// break
i = std::numeric_limits<std::size_t>::max() - 1;
j = std::numeric_limits<std::size_t>::max() - 1;
}
const auto &variantCoordinates = this->_variantVector.at(i);
if (variantCoordinates.isEmpty()) {
old_variant = i;
break;
}
}
// Swap route.
if (variant != old_variant || run != old_run) {
// Swap in new variant, if condition.
if (variant < std::size_t(this->_variantVector.size()) &&
run < std::size_t(this->_variantVector.at(variant).size())) {
if (variant != old_variant) {
// Swap in new variant.
if (variant < std::size_t(this->_variantVector.size())) {
if (old_variant != std::numeric_limits<std::size_t>::max()) {
// this->_transects containes a route, swap it back to
// this->_solutionVector
auto &old_solution = this->_variantVector[old_variant];
auto &old_route = old_solution[old_run];
old_route.swap(this->_transects);
}
auto &solution = this->_variantVector[variant];
auto &route = solution[run];
this->_transects.swap(route);
if (variant != old_variant) {
// Add run names.
this->_runNames.clear();
for (std::size_t i = 1; i <= std::size_t(solution.size()); ++i) {
this->_runNames.append(QString::number(i));
}
emit runNamesChanged();
auto &oldVariantCoordinates = this->_variantVector[old_variant];
oldVariantCoordinates.swap(this->_transects);
}
auto &newVariantCoordinates = this->_variantVector[variant];
this->_transects.swap(newVariantCoordinates);
} else { // error
qCWarning(CircularSurveyLog)
<< "Variant or run out of bounds (variant = " << variant
<< ", run = " << run << ").";
qCWarning(CircularSurveyLog) << "Resetting variant and run.";
qCDebug(CircularSurveyLog)
<< "Variant out of bounds (variant =" << variant << ").";
qCDebug(CircularSurveyLog) << "Resetting variant to zero.";
disconnect(&this->_variant, &Fact::rawValueChanged, this,
&CircularSurvey::_changeVariant);
disconnect(&this->_run, &Fact::rawValueChanged, this,
&CircularSurvey::_changeRun);
if (old_variant < std::size_t(this->_variantVector.size())) {
this->_variant.setCookedValue(QVariant::fromValue(old_variant));
auto &solution = this->_variantVector[old_variant];
if (old_run < std::size_t(solution.size())) {
this->_run.setCookedValue(QVariant::fromValue(old_run));
} else {
this->_run.setCookedValue(QVariant(0));
}
} else {
this->_variant.setCookedValue(QVariant(0));
this->_run.setCookedValue(QVariant(0));
}
this->_variant.setCookedValue(QVariant(0));
connect(&this->_variant, &Fact::rawValueChanged, this,
&CircularSurvey::_changeVariant);
connect(&this->_run, &Fact::rawValueChanged, this,
&CircularSurvey::_changeRun);
if (this->_variantVector.size() > 0 &&
this->_variantVector.front().size() > 0) {
this->_changeVariantRunWorker();
if (this->_variantVector.size() > 0) {
this->_changeVariantWorker();
}
}
}
......@@ -604,41 +385,195 @@ void CircularSurvey::_reverseWorker() {
}
}
void CircularSurvey::_storeWorker() {
// If the transects are getting rebuilt then any previously loaded
// mission items are now invalid.
if (_loadedMissionItemsParent) {
_loadedMissionItems.clear();
_loadedMissionItemsParent->deleteLater();
_loadedMissionItemsParent = nullptr;
void CircularSurvey::applyNewAltitude(double newAltitude) {
_cameraCalc.valueSetIsDistance()->setRawValue(true);
_cameraCalc.distanceToSurface()->setRawValue(newAltitude);
_cameraCalc.setDistanceToSurfaceRelative(true);
}
double CircularSurvey::timeBetweenShots() { return 1; }
QString CircularSurvey::commandDescription() const {
return tr("Circular Survey");
}
QString CircularSurvey::commandName() const { return tr("Circular Survey"); }
QString CircularSurvey::abbreviation() const { return tr("C.S."); }
bool CircularSurvey::readyForSave() const {
return TransectStyleComplexItem::readyForSave() && !_transectsDirty &&
this->_state == STATE::IDLE;
}
double CircularSurvey::additionalTimeDelay() const { return 0; }
bool CircularSurvey::registerGenerator(
const QString &name, std::shared_ptr<routing::GeneratorBase> g) {
if (name.isEmpty()) {
qCDebug(CircularSurveyLog) << "registerGenerator(): empty name string.";
return false;
}
// Store raw transects.
const auto &pRoutingData = this->_pRoutingData;
const auto &ori = this->_referencePoint;
const auto &transectsENU = pRoutingData->transects;
QList<QList<QGeoCoordinate>> rawTransects;
for (std::size_t i = 1; i < transectsENU.size(); ++i) {
const auto &t = transectsENU[i];
rawTransects.append(QList<QGeoCoordinate>());
auto trGeo = rawTransects.back();
for (auto &v : t) {
QGeoCoordinate c;
snake::fromENU(ori, v, c);
trGeo.append(c);
if (!g) {
qCDebug(CircularSurveyLog) << "registerGenerator(): empty generator.";
return false;
}
if (this->_generatorNameList.contains(name)) {
qCDebug(CircularSurveyLog) << "registerGenerator(): generator "
"already registered.";
return false;
} else {
this->_generatorNameList.push_back(name);
this->_generatorList.push_back(g);
if (this->_generatorList.size() == 1) {
_switchToGenerator(g);
}
emit generatorNameListChanged();
return true;
}
}
bool CircularSurvey::unregisterGenerator(const QString &name) {
auto index = this->_generatorNameList.indexOf(name);
if (index >= 0) {
// Is this the current generator?
const auto &g = this->_generatorList.at(index);
if (g == this->_pGenerator) {
if (index > 0) {
_switchToGenerator(this->_generatorList.at(index - 1));
} else {
_switchToGenerator(nullptr);
qCDebug(CircularSurveyLog)
<< "unregisterGenerator(): last generator unregistered.";
}
}
this->_generatorNameList.removeAt(index);
this->_generatorList.removeAt(index);
emit generatorNameListChanged();
return true;
} else {
qCDebug(CircularSurveyLog)
<< "unregisterGenerator(): generator " << name << " not registered.";
return false;
}
}
bool CircularSurvey::unregisterGenerator(int index) {
if (index > 0 && index < this->_generatorNameList.size()) {
return unregisterGenerator(this->_generatorNameList.at(index));
} else {
qCDebug(CircularSurveyLog) << "unregisterGenerator(): index (" << index
<< ") out"
"of bounds ( "
<< this->_generatorList.size() << " ).";
return false;
}
}
bool CircularSurvey::switchToGenerator(const QString &name) {
auto index = this->_generatorNameList.indexOf(name);
if (index >= 0) {
_switchToGenerator(this->_generatorList.at(index));
return true;
} else {
qCDebug(CircularSurveyLog)
<< "switchToGenerator(): generator " << name << " not registered.";
return false;
}
}
bool CircularSurvey::switchToGenerator(int index) {
if (index >= 0) {
_switchToGenerator(this->_generatorList.at(index));
return true;
} else {
qCDebug(CircularSurveyLog) << "unregisterGenerator(): index (" << index
<< ") out"
"of bounds ( "
<< this->_generatorNameList.size() << " ).";
return false;
}
}
QStringList CircularSurvey::generatorNameList() {
return this->_generatorNameList;
}
routing::GeneratorBase *CircularSurvey::generator() {
return _pGenerator.get();
}
int CircularSurvey::generatorIndex() {
return this->_generatorList.indexOf(this->_pGenerator);
}
void CircularSurvey::_rebuildTransectsPhase1(void) {
auto start = std::chrono::high_resolution_clock::now();
switch (this->_state) {
case STATE::SKIPP:
qCDebug(CircularSurveyLog) << "rebuildTransectsPhase1: skipp.";
break;
case STATE::VARIANT_CHANGE:
qCDebug(CircularSurveyLog) << "rebuildTransectsPhase1: variant change.";
this->_changeVariantWorker();
break;
case STATE::RUN_CHANGE:
qCDebug(CircularSurveyLog) << "rebuildTransectsPhase1: run change.";
this->_changeVariantWorker();
break;
case STATE::REVERSE:
qCDebug(CircularSurveyLog) << "rebuildTransectsPhase1: reverse.";
this->_reverseWorker();
break;
case STATE::IDLE:
qCDebug(CircularSurveyLog) << "rebuildTransectsPhase1: update.";
this->_updateWorker();
break;
}
this->_state = STATE::IDLE;
qCDebug(CircularSurveyLog)
<< "rebuildTransectsPhase1(): "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start)
.count()
<< " ms";
}
void CircularSurvey::_recalcComplexDistance() {
_complexDistance = 0;
if (_transectsDirty)
return;
for (int i = 0; i < _visualTransectPoints.count() - 1; i++) {
_complexDistance +=
_visualTransectPoints[i].value<QGeoCoordinate>().distanceTo(
_visualTransectPoints[i + 1].value<QGeoCoordinate>());
}
emit complexDistanceChanged();
}
// no cameraShots in Circular Survey, add if desired
void CircularSurvey::_recalcCameraShots() { _cameraShots = 0; }
void CircularSurvey::_setTransects(CircularSurvey::PtrRoutingData pRoute) {
// Store solutions.
QVector<Runs> solutionVector;
const auto nSolutions = pRoutingData->solutionVector.size();
auto ori = this->_pAreaData->origin();
ori.setAltitude(0);
const auto &transectsENU = pRoute->transects;
QVector<Variant> variantVector;
const auto nSolutions = pRoute->solutionVector.size();
for (std::size_t j = 0; j < nSolutions; ++j) {
const auto &solution = pRoutingData->solutionVector.at(j);
const auto nRuns = solution.size();
// Store runs.
Runs runs(nRuns, Transects{QList<CoordInfo_t>()});
for (std::size_t k = 0; k < nRuns; ++k) {
const auto &route = solution.at(k);
Variant var{QList<CoordInfo_t>()};
const auto &solution = pRoute->solutionVector.at(j);
if (solution.size() > 0) {
const auto &route = solution.at(0);
const auto &path = route.path;
const auto &info = route.info;
if (info.size() > 1) {
......@@ -674,56 +609,47 @@ void CircularSurvey::_storeWorker() {
}
// Convert to geo coordinates.
auto &list = runs[k].front();
auto &list = var.front();
for (std::size_t i = idxFirst; i <= idxLast; ++i) {
auto &vertex = path[i];
QGeoCoordinate c;
snake::fromENU(ori, vertex, c);
list.append(CoordInfo_t{c, CoordTypeInterior});
}
} else {
qCWarning(CircularSurveyLog)
<< "_storeWorker(): lastTransect.size() == 0";
qCDebug(CircularSurveyLog)
<< "_setTransects(): lastTransect.size() == 0";
}
} else {
qCWarning(CircularSurveyLog)
<< "_storeWorker(): firstTransect.size() == 0";
qCDebug(CircularSurveyLog)
<< "_setTransects(): firstTransect.size() == 0";
}
} else {
qCWarning(CircularSurveyLog)
<< "_storeWorker(): transectsInfo.size() <= 1";
}
}
// Remove empty runs.
bool error = true;
for (auto it = runs.begin(); it < runs.end();) {
if (it->size() > 0 && it->front().size() > 0) {
error = false;
++it;
} else {
it = runs.erase(it);
qCDebug(CircularSurveyLog)
<< "_setTransects(): transectsInfo.size() <= 1";
}
} else {
qCDebug(CircularSurveyLog) << "_setTransects(): solution.size() == 0";
}
if (!error) {
solutionVector.push_back(std::move(runs));
}
}
// Remove empty solutions.
std::size_t nSol = 0;
for (auto it = solutionVector.begin(); it < solutionVector.end();) {
if (it->size() > 0 && it->front().size() > 0) {
++it;
++nSol;
} else {
it = solutionVector.erase(it);
if (var.size() > 0 && var.front().size() > 0) {
variantVector.push_back(std::move(var));
}
}
// Assign routes if no error occured.
if (nSol > 0) {
if (variantVector.size() > 0) {
// Swap first route to _transects.
this->_variantVector.swap(solutionVector);
this->_variantVector.swap(variantVector);
// If the transects are getting rebuilt then any previously loaded
// mission items are now invalid.
if (_loadedMissionItemsParent) {
_loadedMissionItems.clear();
_loadedMissionItemsParent->deleteLater();
_loadedMissionItemsParent = nullptr;
}
// Add route variant names.
this->_variantNames.clear();
......@@ -733,482 +659,31 @@ void CircularSurvey::_storeWorker() {
}
emit variantNamesChanged();
// Swap in rawTransects.
this->_rawTransects.swap(rawTransects);
disconnect(&this->_variant, &Fact::rawValueChanged, this,
&CircularSurvey::_changeVariant);
disconnect(&this->_run, &Fact::rawValueChanged, this,
&CircularSurvey::_changeRun);
this->_variant.setCookedValue(QVariant(0));
this->_run.setCookedValue(QVariant(0));
connect(&this->_variant, &Fact::rawValueChanged, this,
&CircularSurvey::_changeVariant);
connect(&this->_run, &Fact::rawValueChanged, this,
&CircularSurvey::_changeRun);
this->_changeVariantRunWorker();
// Mark transect as stored and ready.
this->_transectsDirty = false;
}
}
this->_changeVariantWorker();
void CircularSurvey::applyNewAltitude(double newAltitude) {
_cameraCalc.valueSetIsDistance()->setRawValue(true);
_cameraCalc.distanceToSurface()->setRawValue(newAltitude);
_cameraCalc.setDistanceToSurfaceRelative(true);
}
double CircularSurvey::timeBetweenShots() { return 1; }
QString CircularSurvey::commandDescription() const {
return tr("Circular Survey");
}
QString CircularSurvey::commandName() const { return tr("Circular Survey"); }
QString CircularSurvey::abbreviation() const { return tr("C.S."); }
bool CircularSurvey::readyForSave() const {
return TransectStyleComplexItem::readyForSave() && !_transectsDirty;
}
double CircularSurvey::additionalTimeDelay() const { return 0; }
void CircularSurvey::_rebuildTransectsPhase1(void) {
auto start = std::chrono::high_resolution_clock::now();
switch (this->_state) {
case STATE::STORE:
qCWarning(CircularSurveyLog) << "rebuildTransectsPhase1: store.";
this->_storeWorker();
break;
case STATE::VARIANT_CHANGE:
qCWarning(CircularSurveyLog) << "rebuildTransectsPhase1: variant change.";
this->_changeVariantRunWorker();
break;
case STATE::RUN_CHANGE:
qCWarning(CircularSurveyLog) << "rebuildTransectsPhase1: run change.";
this->_changeVariantRunWorker();
break;
case STATE::REVERSE:
qCWarning(CircularSurveyLog) << "rebuildTransectsPhase1: reverse.";
this->_reverseWorker();
break;
case STATE::DEFAULT:
qCWarning(CircularSurveyLog) << "rebuildTransectsPhase1: update.";
this->_updateWorker();
break;
}
this->_state = STATE::DEFAULT;
qCWarning(CircularSurveyLog)
<< "rebuildTransectsPhase1(): "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start)
.count()
<< " ms";
}
// Mark transect ready.
this->_transectsDirty = false;
void CircularSurvey::_recalcComplexDistance() {
_complexDistance = 0;
if (_transectsDirty)
return;
for (int i = 0; i < _visualTransectPoints.count() - 1; i++) {
_complexDistance +=
_visualTransectPoints[i].value<QGeoCoordinate>().distanceTo(
_visualTransectPoints[i + 1].value<QGeoCoordinate>());
this->_state = STATE::SKIPP;
this->_rebuildTransects();
} else {
qCDebug(CircularSurveyLog)
<< "_setTransects(): failed, variantVector empty.";
this->_state = STATE::IDLE;
}
emit complexDistanceChanged();
}
// no cameraShots in Circular Survey, add if desired
void CircularSurvey::_recalcCameraShots() { _cameraShots = 0; }
void CircularSurvey::_setTransects(CircularSurvey::PtrRoutingData pRoute) {
this->_pRoutingData = pRoute;
this->_state = STATE::STORE;
this->_rebuildTransects();
}
Fact *CircularSurvey::minLength() { return &_minLength; }
Fact *CircularSurvey::type() { return &_type; }
Fact *CircularSurvey::variant() { return &_variant; }
Fact *CircularSurvey::numRuns() { return &_numRuns; }
Fact *CircularSurvey::run() { return &_run; }
int CircularSurvey::typeCount() const { return int(integral(Type::Count)); }
bool CircularSurvey::calculating() const {
return this->_pWorker->calculating();
}
bool circularTransects(const snake::FPolygon &polygon,
const std::vector<snake::FPolygon> &tiles,
snake::Length deltaR, snake::Angle deltaAlpha,
snake::Length minLength, snake::Transects &transects) {
auto s1 = std::chrono::high_resolution_clock::now();
// Check preconitions
if (polygon.outer().size() >= 3) {
using namespace boost::units;
// Convert geo polygon to ENU polygon.
snake::FPoint origin{0, 0};
std::string error;
// Check validity.
if (!bg::is_valid(polygon, error)) {
qCWarning(CircularSurveyLog) << "circularTransects(): "
"invalid polygon.";
qCWarning(CircularSurveyLog) << error.c_str();
std::stringstream ss;
ss << bg::wkt(polygon);
qCWarning(CircularSurveyLog) << ss.str().c_str();
} else {
// Calculate polygon distances and angles.
std::vector<snake::Length> distances;
distances.reserve(polygon.outer().size());
std::vector<snake::Angle> angles;
angles.reserve(polygon.outer().size());
//#ifdef DEBUG_CIRCULAR_SURVEY
// qCWarning(CircularSurveyLog) << "circularTransects():";
//#endif
for (const auto &p : polygon.outer()) {
snake::Length distance = bg::distance(origin, p) * si::meter;
distances.push_back(distance);
snake::Angle alpha = (std::atan2(p.get<1>(), p.get<0>())) * si::radian;
alpha = alpha < 0 * si::radian ? alpha + 2 * M_PI * si::radian : alpha;
angles.push_back(alpha);
//#ifdef DEBUG_CIRCULAR_SURVEY
// qCWarning(CircularSurveyLog) << "distances, angles,
// coordinates:"; qCWarning(CircularSurveyLog) <<
// to_string(distance).c_str(); qCWarning(CircularSurveyLog) <<
// to_string(snake::Degree(alpha)).c_str();
// qCWarning(CircularSurveyLog) << "x = " << p.get<0>() << "y = "
// << p.get<1>();
//#endif
}
auto rMin = deltaR; // minimal circle radius
snake::Angle alpha1(0 * degree::degree);
snake::Angle alpha2(360 * degree::degree);
// Determine r_min by successive approximation
if (!bg::within(origin, polygon.outer())) {
rMin = bg::distance(origin, polygon) * si::meter;
}
auto rMax = (*std::max_element(distances.begin(),
distances.end())); // maximal circle radius
// Scale parameters and coordinates.
const auto rMinScaled =
ClipperLib::cInt(std::round(rMin.value() * CLIPPER_SCALE));
const auto deltaRScaled =
ClipperLib::cInt(std::round(deltaR.value() * CLIPPER_SCALE));
auto originScaled =
ClipperLib::IntPoint{ClipperLib::cInt(std::round(origin.get<0>())),
ClipperLib::cInt(std::round(origin.get<1>()))};
// Generate circle sectors.
auto rScaled = rMinScaled;
const auto nTran = long(std::ceil(((rMax - rMin) / deltaR).value()));
vector<ClipperLib::Path> sectors(nTran, ClipperLib::Path());
const auto nSectors =
long(std::round(((alpha2 - alpha1) / deltaAlpha).value()));
//#ifdef DEBUG_CIRCULAR_SURVEY
// qCWarning(CircularSurveyLog) << "circularTransects(): sector
// parameres:"; qCWarning(CircularSurveyLog) << "alpha1: " <<
// to_string(snake::Degree(alpha1)).c_str();
// qCWarning(CircularSurveyLog) << "alpha2:
// "
// << to_string(snake::Degree(alpha2)).c_str();
// qCWarning(CircularSurveyLog) << "n: "
// << to_string((alpha2 - alpha1) / deltaAlpha).c_str();
// qCWarning(CircularSurveyLog)
// << "nSectors: " << nSectors; qCWarning(CircularSurveyLog) <<
// "rMin: " << to_string(rMin).c_str(); qCWarning(CircularSurveyLog)
// << "rMax: " << to_string(rMax).c_str();
// qCWarning(CircularSurveyLog) << "nTran: " << nTran;
//#endif
using ClipperCircle =
GenericCircle<ClipperLib::cInt, ClipperLib::IntPoint>;
for (auto &sector : sectors) {
ClipperCircle circle(rScaled, originScaled);
approximate(circle, nSectors, sector);
rScaled += deltaRScaled;
}
// Clip sectors to polygonENU.
ClipperLib::Path polygonClipper;
snake::FPolygon shrinked;
snake::offsetPolygon(polygon, shrinked, -0.3);
auto &outer = shrinked.outer();
polygonClipper.reserve(outer.size());
for (auto it = outer.begin(); it < outer.end() - 1; ++it) {
auto x = ClipperLib::cInt(std::round(it->get<0>() * CLIPPER_SCALE));
auto y = ClipperLib::cInt(std::round(it->get<1>() * CLIPPER_SCALE));
polygonClipper.push_back(ClipperLib::IntPoint{x, y});
}
ClipperLib::Clipper clipper;
clipper.AddPath(polygonClipper, ClipperLib::ptClip, true);
clipper.AddPaths(sectors, ClipperLib::ptSubject, false);
ClipperLib::PolyTree transectsClipper;
clipper.Execute(ClipperLib::ctIntersection, transectsClipper,
ClipperLib::pftNonZero, ClipperLib::pftNonZero);
// Subtract holes.
if (tiles.size() > 0) {
vector<ClipperLib::Path> processedTiles;
for (const auto &tile : tiles) {
ClipperLib::Path path;
for (const auto &v : tile.outer()) {
path.push_back(ClipperLib::IntPoint{
static_cast<ClipperLib::cInt>(v.get<0>() * CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(v.get<1>() * CLIPPER_SCALE)});
}
processedTiles.push_back(std::move(path));
}
clipper.Clear();
for (const auto &child : transectsClipper.Childs) {
clipper.AddPath(child->Contour, ClipperLib::ptSubject, false);
}
clipper.AddPaths(processedTiles, ClipperLib::ptClip, true);
transectsClipper.Clear();
clipper.Execute(ClipperLib::ctDifference, transectsClipper,
ClipperLib::pftNonZero, ClipperLib::pftNonZero);
}
// Extract transects from PolyTree and convert them to
// BoostLineString
for (const auto &child : transectsClipper.Childs) {
snake::FLineString transect;
transect.reserve(child->Contour.size());
for (const auto &vertex : child->Contour) {
auto x = static_cast<double>(vertex.X) / CLIPPER_SCALE;
auto y = static_cast<double>(vertex.Y) / CLIPPER_SCALE;
transect.push_back(snake::FPoint(x, y));
}
transects.push_back(transect);
}
// Join sectors which where slit due to clipping.
const double th = 0.01;
for (auto ito = transects.begin(); ito < transects.end(); ++ito) {
for (auto iti = ito + 1; iti < transects.end(); ++iti) {
auto dist1 = bg::distance(ito->front(), iti->front());
if (dist1 < th) {
snake::FLineString temp;
for (auto it = iti->end() - 1; it >= iti->begin(); --it) {
temp.push_back(*it);
}
temp.insert(temp.end(), ito->begin(), ito->end());
*ito = temp;
transects.erase(iti);
break;
}
auto dist2 = bg::distance(ito->front(), iti->back());
if (dist2 < th) {
snake::FLineString temp;
temp.insert(temp.end(), iti->begin(), iti->end());
temp.insert(temp.end(), ito->begin(), ito->end());
*ito = temp;
transects.erase(iti);
break;
}
auto dist3 = bg::distance(ito->back(), iti->front());
if (dist3 < th) {
snake::FLineString temp;
temp.insert(temp.end(), ito->begin(), ito->end());
temp.insert(temp.end(), iti->begin(), iti->end());
*ito = temp;
transects.erase(iti);
break;
}
auto dist4 = bg::distance(ito->back(), iti->back());
if (dist4 < th) {
snake::FLineString temp;
temp.insert(temp.end(), ito->begin(), ito->end());
for (auto it = iti->end() - 1; it >= iti->begin(); --it) {
temp.push_back(*it);
}
*ito = temp;
transects.erase(iti);
break;
}
}
}
// Remove short transects
for (auto it = transects.begin(); it < transects.end();) {
if (bg::length(*it) < minLength.value()) {
it = transects.erase(it);
} else {
++it;
}
}
qCWarning(CircularSurveyLog)
<< "circularTransects(): transect gen. time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - s1)
.count()
<< " ms";
return true;
}
}
return false;
}
bool linearTransects(const snake::FPolygon &polygon,
const std::vector<snake::FPolygon> &tiles,
snake::Length distance, snake::Angle angle,
snake::Length minLength, snake::Transects &transects) {
namespace tr = bg::strategy::transform;
auto s1 = std::chrono::high_resolution_clock::now();
// Check preconitions
if (polygon.outer().size() >= 3) {
// Convert to ENU system.
std::string error;
// Check validity.
if (!bg::is_valid(polygon, error)) {
std::stringstream ss;
ss << bg::wkt(polygon);
qCWarning(CircularSurveyLog) << "linearTransects(): "
"invalid polygon. "
<< error.c_str() << ss.str().c_str();
} else {
tr::rotate_transformer<bg::degree, double, 2, 2> rotate(angle.value() *
180 / M_PI);
// Rotate polygon by angle and calculate bounding box.
snake::FPolygon polygonENURotated;
bg::transform(polygon.outer(), polygonENURotated.outer(), rotate);
snake::FBox box;
boost::geometry::envelope(polygonENURotated, box);
double x0 = box.min_corner().get<0>();
double y0 = box.min_corner().get<1>();
double x1 = box.max_corner().get<0>();
double y1 = box.max_corner().get<1>();
// Generate transects and convert them to clipper path.
size_t num_t = ceil((y1 - y0) / distance.value()); // number of transects
vector<ClipperLib::Path> transectsClipper;
transectsClipper.reserve(num_t);
for (size_t i = 0; i < num_t; ++i) {
// calculate transect
snake::FPoint v1{x0, y0 + i * distance.value()};
snake::FPoint v2{x1, y0 + i * distance.value()};
snake::FLineString transect;
transect.push_back(v1);
transect.push_back(v2);
// transform back
snake::FLineString temp_transect;
tr::rotate_transformer<bg::degree, double, 2, 2> rotate_back(
-angle.value() * 180 / M_PI);
bg::transform(transect, temp_transect, rotate_back);
// to clipper
ClipperLib::IntPoint c1{static_cast<ClipperLib::cInt>(
temp_transect[0].get<0>() * CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(
temp_transect[0].get<1>() * CLIPPER_SCALE)};
ClipperLib::IntPoint c2{static_cast<ClipperLib::cInt>(
temp_transect[1].get<0>() * CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(
temp_transect[1].get<1>() * CLIPPER_SCALE)};
ClipperLib::Path path{c1, c2};
transectsClipper.push_back(path);
}
if (transectsClipper.size() == 0) {
std::stringstream ss;
ss << "Not able to generate transects. Parameter: distance = "
<< distance << std::endl;
qCWarning(CircularSurveyLog)
<< "linearTransects(): " << ss.str().c_str();
return false;
}
// Convert measurement area to clipper path.
snake::FPolygon shrinked;
snake::offsetPolygon(polygon, shrinked, -0.2);
auto &outer = shrinked.outer();
ClipperLib::Path polygonClipper;
for (auto vertex : outer) {
polygonClipper.push_back(ClipperLib::IntPoint{
static_cast<ClipperLib::cInt>(vertex.get<0>() * CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(vertex.get<1>() * CLIPPER_SCALE)});
}
// Perform clipping.
// Clip transects to measurement area.
ClipperLib::Clipper clipper;
clipper.AddPath(polygonClipper, ClipperLib::ptClip, true);
clipper.AddPaths(transectsClipper, ClipperLib::ptSubject, false);
ClipperLib::PolyTree clippedTransecs;
clipper.Execute(ClipperLib::ctIntersection, clippedTransecs,
ClipperLib::pftNonZero, ClipperLib::pftNonZero);
// Subtract holes.
if (tiles.size() > 0) {
vector<ClipperLib::Path> processedTiles;
for (const auto &tile : tiles) {
ClipperLib::Path path;
for (const auto &v : tile.outer()) {
path.push_back(ClipperLib::IntPoint{
static_cast<ClipperLib::cInt>(v.get<0>() * CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(v.get<1>() * CLIPPER_SCALE)});
}
processedTiles.push_back(std::move(path));
}
clipper.Clear();
for (const auto &child : clippedTransecs.Childs) {
clipper.AddPath(child->Contour, ClipperLib::ptSubject, false);
}
clipper.AddPaths(processedTiles, ClipperLib::ptClip, true);
clippedTransecs.Clear();
clipper.Execute(ClipperLib::ctDifference, clippedTransecs,
ClipperLib::pftNonZero, ClipperLib::pftNonZero);
}
// Extract transects from PolyTree and convert them to BoostLineString
for (const auto &child : clippedTransecs.Childs) {
const auto &clipperTransect = child->Contour;
snake::FPoint v1{
static_cast<double>(clipperTransect[0].X) / CLIPPER_SCALE,
static_cast<double>(clipperTransect[0].Y) / CLIPPER_SCALE};
snake::FPoint v2{
static_cast<double>(clipperTransect[1].X) / CLIPPER_SCALE,
static_cast<double>(clipperTransect[1].Y) / CLIPPER_SCALE};
snake::FLineString transect{v1, v2};
if (bg::length(transect) >= minLength.value()) {
transects.push_back(transect);
}
}
if (transects.size() == 0) {
std::stringstream ss;
ss << "Not able to generatetransects. Parameter: minLength = "
<< minLength << std::endl;
qCWarning(CircularSurveyLog)
<< "linearTransects(): " << ss.str().c_str();
return false;
}
qCWarning(CircularSurveyLog)
<< "linearTransects(): transect gen. time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - s1)
.count()
<< " ms";
return true;
}
}
return false;
}
/*!
\class CircularSurveyComplexItem
\inmodule Wima
......
......@@ -2,26 +2,30 @@
#include <QFutureWatcher>
#include <QVector>
#include <memory>
#include "SettingsFact.h"
#include "TransectStyleComplexItem.h"
#include "Geometry/WimaJoinedAreaData.h"
#include "Geometry/WimaMeasurementAreaData.h"
#include "WimaPlanData.h"
class RoutingThread;
class RoutingData;
namespace routing {
class GeneratorBase;
}
class CircularSurvey : public TransectStyleComplexItem {
Q_OBJECT
public:
using PtrRoutingData = QSharedPointer<RoutingData>;
enum class Type {
Circular = 0,
Linear = 1,
Count = 2 // Must me last, onyl for counting
};
using PtrGenerator = std::shared_ptr<routing::GeneratorBase>;
using PtrRoutingData = std::shared_ptr<RoutingData>;
using PtrWorker = std::shared_ptr<RoutingThread>;
public:
/// @param vehicle Vehicle which this is being contructed for
/// @param flyView true: Created for use in the Fly View, false: Created for
/// use in the Plan View
......@@ -31,50 +35,27 @@ public:
QObject *parent);
~CircularSurvey();
Q_PROPERTY(QGeoCoordinate refPoint READ refPoint WRITE setRefPoint NOTIFY
refPointChanged)
Q_PROPERTY(Fact *transectDistance READ transectDistance CONSTANT)
Q_PROPERTY(Fact *alpha READ alpha CONSTANT)
Q_PROPERTY(Fact *minLength READ minLength CONSTANT)
Q_PROPERTY(Fact *type READ type CONSTANT)
Q_PROPERTY(Fact *variant READ variant CONSTANT)
Q_PROPERTY(Fact *numRuns READ numRuns CONSTANT)
Q_PROPERTY(Fact *run READ run CONSTANT)
Q_PROPERTY(int typeCount READ typeCount CONSTANT)
Q_PROPERTY(
QStringList variantNames READ variantNames NOTIFY variantNamesChanged)
Q_PROPERTY(QStringList generatorNameList READ generatorNameList NOTIFY
generatorNameListChanged)
Q_PROPERTY(bool calculating READ calculating NOTIFY calculatingChanged)
Q_PROPERTY(bool hidePolygon READ hidePolygon NOTIFY hidePolygonChanged)
Q_PROPERTY(
QList<QString> variantNames READ variantNames NOTIFY variantNamesChanged)
Q_PROPERTY(QList<QString> runNames READ runNames NOTIFY runNamesChanged)
routing::GeneratorBase *generator READ generator NOTIFY generatorChanged)
Q_PROPERTY(int generatorIndex READ generatorIndex NOTIFY generatorChanged)
Q_INVOKABLE void resetReference(void);
Q_INVOKABLE void reverse(void);
// Property setters
void setRefPoint(const QGeoCoordinate &refPt);
void setHidePolygon(bool hide);
void setMeasurementArea(const WimaMeasurementAreaData &mArea);
void setJoinedArea(const WimaJoinedAreaData &jArea);
void setMeasurementArea(const WimaMeasurementArea &mArea);
void setJoinedArea(const WimaJoinedArea &jArea);
void setDepot(const QGeoCoordinate &depot);
void setPlanData(const WimaPlanData &d);
// Property getters
QGeoCoordinate refPoint() const;
Fact *transectDistance();
Fact *alpha();
Fact *minLength();
Fact *type();
const WimaPlanData &planData() const;
WimaPlanData &planData();
Fact *variant();
Fact *numRuns();
Fact *run();
int typeCount() const;
QStringList variantNames() const;
bool calculating() const;
bool hidePolygon() const;
QList<QString> variantNames() const;
QList<QString> runNames() const;
QGeoCoordinate depot() const;
const QList<QList<QGeoCoordinate>> &rawTransects() const;
// Overrides
bool load(const QJsonObject &complexObject, int sequenceNumber,
......@@ -92,91 +73,73 @@ public:
bool readyForSave(void) const override final;
double additionalTimeDelay(void) const override final;
// Generator
bool registerGenerator(const QString &name,
std::shared_ptr<routing::GeneratorBase> g);
bool unregisterGenerator(const QString &name);
bool unregisterGenerator(int index);
Q_INVOKABLE bool switchToGenerator(const QString &name);
Q_INVOKABLE bool switchToGenerator(int index);
QStringList generatorNameList();
routing::GeneratorBase *generator();
int generatorIndex();
static const char *settingsGroup;
static const char *transectDistanceName;
static const char *alphaName;
static const char *minLengthName;
static const char *typeName;
static const char *variantName;
static const char *numRunsName;
static const char *runName;
static const char *CircularSurveyName;
static const char *refPointLongitudeName;
static const char *refPointLatitudeName;
static const char *refPointAltitudeName;
signals:
void refPointChanged();
void calculatingChanged();
void hidePolygonChanged();
void depotChanged();
void variantNamesChanged();
void runNamesChanged();
void measurementAreaChanged();
void joinedAreaChanged();
void generatorNameListChanged();
void generatorChanged();
private slots:
// Overrides from TransectStyleComplexItem
void _rebuildTransectsPhase1(void) final;
void _recalcComplexDistance(void) final;
void _recalcCameraShots(void) final;
// Worker functions.
void _setTransects(PtrRoutingData pRoute);
void _changeVariant();
void _updateWorker();
void _changeVariantWorker();
void _reverseWorker();
private:
void _appendLoadedMissionItems(QList<MissionItem *> &items,
QObject *missionItemParent);
void _buildAndAppendMissionItems(QList<MissionItem *> &items,
QObject *missionItemParent);
void _changeVariant();
void _changeRun();
void _updateWorker();
void _changeVariantRunWorker();
void _reverseWorker();
void _storeWorker();
void _changeRunWorker();
// center of the circular lanes, e.g. base station
QGeoCoordinate _referencePoint;
QMap<QString, FactMetaData *> _metaDataMap;
// distance between two neighbour circles
SettingsFact _transectDistance;
// angle discretisation of the circles
SettingsFact _alpha;
// minimal transect lenght, transects are rejected if they are shorter than
// this value
SettingsFact _minLength;
SettingsFact _type;
SettingsFact _variant;
QList<QString> _variantNames;
SettingsFact _numRuns;
SettingsFact _run;
QList<QString> _runNames;
// Area data
WimaMeasurementAreaData _mArea;
WimaJoinedAreaData _jArea;
QGeoCoordinate _depot;
// Worker
using PtrWorker = std::shared_ptr<RoutingThread>;
PtrWorker _pWorker;
PtrRoutingData _pRoutingData;
// Routing data.
QList<QList<QGeoCoordinate>> _rawTransects;
using Runs = QVector<Transects>;
QVector<Runs> _variantVector;
bool _switchToGenerator(const PtrGenerator &newG);
// State.
enum class STATE {
DEFAULT,
STORE,
IDLE,
SKIPP,
REVERSE,
VARIANT_CHANGE,
RUN_CHANGE,
};
STATE _state;
bool _hidePolygon;
// center of the circular lanes, e.g. base station
QMap<QString, FactMetaData *> _metaDataMap;
SettingsFact _variant;
QStringList _variantNames;
// Area data
std::shared_ptr<WimaPlanData> _pAreaData;
// Generators
QList<PtrGenerator> _generatorList;
QStringList _generatorNameList;
PtrGenerator _pGenerator;
// Routing.
using Variant = Transects;
QVector<Variant> _variantVector;
PtrWorker _pWorker;
};
......@@ -2,7 +2,14 @@
WimaAreaData::WimaAreaData(QObject *parent) : QObject(parent) {}
WimaAreaData::~WimaAreaData() {}
WimaAreaData::WimaAreaData(const WimaAreaData &other, QObject *parent)
: QObject(parent), _path(other._path), _list(other._list),
_center(other._center) {}
WimaAreaData::WimaAreaData(const WimaArea &otherData, QObject *parent)
: QObject(parent), _center(otherData.center()) {
_setPathImpl(otherData.path());
}
bool WimaAreaData::operator==(const WimaAreaData &data) const {
return this->_path == data._path && this->_center == data._center;
......@@ -25,7 +32,7 @@ bool WimaAreaData::containsCoordinate(const QGeoCoordinate &coordinate) const {
using namespace PolygonCalculus;
using namespace GeoUtilities;
if (_path.size() > 2) {
if (this->coordinateList().size() > 2) {
QPolygonF polygon;
toCartesianList(this->coordinateList(), coordinate, polygon);
return PlanimetryCalculus::contains(polygon, QPointF(0, 0));
......@@ -36,44 +43,60 @@ bool WimaAreaData::containsCoordinate(const QGeoCoordinate &coordinate) const {
void WimaAreaData::append(const QGeoCoordinate &c) {
_list.append(c);
_path.push_back(QVariant::fromValue(c));
emit pathChanged();
}
void WimaAreaData::push_back(const QGeoCoordinate &c) { append(c); }
void WimaAreaData::clear() {
_list.clear();
_path.clear();
if (_list.size() > 0 || _path.size() > 0) {
_list.clear();
_path.clear();
emit pathChanged();
}
}
void WimaAreaData::setPath(const QVariantList &coordinateList) {
_path = coordinateList;
_list.clear();
for (auto variant : coordinateList) {
_list.push_back(variant.value<QGeoCoordinate>());
if (_path != coordinateList) {
_setPathImpl(coordinateList);
emit pathChanged();
}
}
void WimaAreaData::setCenter(const QGeoCoordinate &center) {
if (_center != center) {
_center = center;
emit centerChanged();
}
}
/*!
* \fn void WimaAreaData::assign(const WimaAreaData &other)
*
* Assigns \a other to the invoking object
*/
void WimaAreaData::assign(const WimaAreaData &other) {
setPath(other.path());
setCenter(other.center());
WimaAreaData &WimaAreaData::operator=(const WimaAreaData &otherData) {
setPath(otherData._list);
setCenter(otherData._center);
return *this;
}
void WimaAreaData::assign(const WimaArea &other) {
setPath(other.path());
setCenter(other.center());
WimaAreaData &WimaAreaData::operator=(const WimaArea &otherData) {
setPath(otherData.path());
setCenter(otherData.center());
return *this;
}
void WimaAreaData::_setPathImpl(const QList<QGeoCoordinate> &coordinateList) {
_list = coordinateList;
_path.clear();
// copy all coordinates to _path
for (const auto &vertex : coordinateList) {
_path.append(QVariant::fromValue(vertex));
}
}
void WimaAreaData::_setPathImpl(const QVariantList &coordinateList) {
_path = coordinateList;
_list.clear();
for (const auto &variant : coordinateList) {
_list.push_back(variant.value<QGeoCoordinate>());
}
}
/*!
......@@ -83,24 +106,26 @@ void WimaAreaData::assign(const WimaArea &other) {
* coordinateList. Emits the \c pathChanged() signal.
*/
void WimaAreaData::setPath(const QList<QGeoCoordinate> &coordinateList) {
_list = coordinateList;
_path.clear();
// copy all coordinates to _path
for (int i = 0; i < coordinateList.size(); i++) {
_path.append(QVariant::fromValue(coordinateList.value(i)));
if (_list != coordinateList) {
_setPathImpl(coordinateList);
emit pathChanged();
}
emit pathChanged(_path);
}
bool operator==(const WimaAreaData &m1, const WimaArea &m2) {
return m1.path() == m2.path() && m1.center() == m2.center();
}
bool operator!=(const WimaAreaData &m1, const WimaArea &m2) {
return !operator==(m1, m2);
}
bool operator==(const WimaArea &m1, const WimaAreaData &m2) { return m2 == m1; }
bool operator!=(const WimaArea &m1, const WimaAreaData &m2) {
return !operator==(m2, m1);
}
/*!
* \class WimaArea::WimaAreaData
* \brief Class to store and exchange data of a \c WimaArea Object.
......
#pragma once
#pragma once
#include <QObject>
......@@ -11,16 +11,12 @@ class WimaAreaData
{
Q_OBJECT
public:
WimaAreaData(QObject *parent = nullptr);
Q_PROPERTY(const QVariantList path READ path NOTIFY pathChanged)
Q_PROPERTY(QString type READ type CONSTANT)
Q_PROPERTY(QString mapVisualQML READ mapVisualQML CONSTANT)
WimaAreaData(QObject *parent = nullptr);
~WimaAreaData();
WimaAreaData(const WimaAreaData &otherData) = delete; // avoid slicing
WimaAreaData &
operator=(const WimaAreaData &otherData) = delete; // avoid slicing
bool operator==(const WimaAreaData &data) const;
bool operator!=(const WimaAreaData &data) const;
......@@ -37,8 +33,8 @@ public:
void clear();
signals:
void pathChanged(const QVariantList &coordinateList);
void centerChanged(void);
void pathChanged();
void centerChanged();
public slots:
void setPath(const QList<QGeoCoordinate> &coordinateList);
......@@ -46,18 +42,21 @@ public slots:
void setCenter(const QGeoCoordinate &center);
protected:
void assign(const WimaAreaData &other);
void assign(const WimaArea &other);
WimaAreaData(const WimaAreaData &otherData, QObject *parent);
WimaAreaData(const WimaArea &otherData, QObject *parent);
WimaAreaData &operator=(const WimaAreaData &otherData);
WimaAreaData &operator=(const WimaArea &otherData);
private:
// Member Functions
void _setPathImpl(const QList<QGeoCoordinate> &coordinateList);
void _setPathImpl(const QVariantList &coordinateList);
// Member Variables
// see WimaArea.h for explanation
QVariantList _path;
mutable QList<QGeoCoordinate> _list;
mutable QVariantList _path;
QList<QGeoCoordinate> _list;
QGeoCoordinate _center;
};
bool operator==(const WimaAreaData &m1, const WimaArea &m2);
bool operator!=(const WimaAreaData &m1, const WimaArea &m2);
bool operator==(const WimaArea &m1, const WimaAreaData &m2);
bool operator!=(const WimaArea &m1, const WimaAreaData &m2);
......@@ -6,14 +6,10 @@ WimaCorridorData::WimaCorridorData(QObject *parent) : WimaAreaData(parent) {}
WimaCorridorData::WimaCorridorData(const WimaCorridorData &other,
QObject *parent)
: WimaAreaData(parent) {
*this = other;
}
: WimaAreaData(other, parent) {}
WimaCorridorData::WimaCorridorData(const WimaCorridor &other, QObject *parent)
: WimaAreaData(parent) {
*this = other;
}
: WimaAreaData(other, parent) {}
/*!
* \overload operator=()
......@@ -21,8 +17,7 @@ WimaCorridorData::WimaCorridorData(const WimaCorridor &other, QObject *parent)
* Assigns \a other to the invoking object.
*/
WimaCorridorData &WimaCorridorData::operator=(const WimaCorridorData &other) {
this->assign(other);
WimaAreaData::operator=(other);
return *this;
}
......@@ -32,8 +27,7 @@ WimaCorridorData &WimaCorridorData::operator=(const WimaCorridorData &other) {
* Assigns \a other to the invoking object.
*/
WimaCorridorData &WimaCorridorData::operator=(const WimaCorridor &other) {
this->assign(other);
WimaAreaData::operator=(other);
return *this;
}
......@@ -43,14 +37,6 @@ QString WimaCorridorData::mapVisualQML() const {
QString WimaCorridorData::type() const { return this->typeString; }
void WimaCorridorData::assign(const WimaCorridorData &corridorData) {
WimaAreaData::assign(corridorData);
}
void WimaCorridorData::assign(const WimaCorridor &corridor) {
WimaAreaData::assign(corridor);
}
/*!
* \class WimaAreaData::WimaCorridorData
* \brief Class to store and exchange data of a \c WimaCorridorData Object.
......
......@@ -23,14 +23,4 @@ public:
WimaCorridorData *Clone() const { return new WimaCorridorData(*this); }
static const char *typeString;
signals:
public slots:
protected:
void assign(const WimaCorridorData &corridorData);
void assign(const WimaCorridor &corridor);
private:
};
......@@ -7,15 +7,11 @@ WimaJoinedAreaData::WimaJoinedAreaData(QObject *parent)
WimaJoinedAreaData::WimaJoinedAreaData(const WimaJoinedAreaData &other,
QObject *parent)
: WimaAreaData(parent) {
*this = other;
}
: WimaAreaData(other, parent) {}
WimaJoinedAreaData::WimaJoinedAreaData(const WimaJoinedArea &other,
QObject *parent)
: WimaAreaData(parent) {
*this = other;
}
: WimaAreaData(other, parent) {}
/*!
* \overload operator=()
......@@ -24,8 +20,7 @@ WimaJoinedAreaData::WimaJoinedAreaData(const WimaJoinedArea &other,
*/
WimaJoinedAreaData &WimaJoinedAreaData::
operator=(const WimaJoinedAreaData &other) {
assign(other);
WimaAreaData::operator=(other);
return *this;
}
......@@ -35,7 +30,7 @@ operator=(const WimaJoinedAreaData &other) {
* Assigns \a other to the invoking object.
*/
WimaJoinedAreaData &WimaJoinedAreaData::operator=(const WimaJoinedArea &other) {
assign(other);
WimaAreaData::operator=(other);
return *this;
}
......@@ -45,14 +40,6 @@ QString WimaJoinedAreaData::mapVisualQML() const {
QString WimaJoinedAreaData::type() const { return this->typeString; }
void WimaJoinedAreaData::assign(const WimaJoinedAreaData &other) {
WimaAreaData::assign(other);
}
void WimaJoinedAreaData::assign(const WimaJoinedArea &other) {
WimaAreaData::assign(other);
}
/*!
* \class WimaAreaData::WimaJoinedAreaData
* \brief Class to store and exchange data of a \c WimaJoinedAreaData Object.
......
......@@ -24,10 +24,4 @@ public:
WimaJoinedAreaData *Clone() const { return new WimaJoinedAreaData(*this); }
static const char *typeString;
protected:
void assign(const WimaJoinedAreaData &other);
void assign(const WimaJoinedArea &other);
private:
};
......@@ -72,7 +72,7 @@ WimaMeasurementArea::WimaMeasurementArea(QObject *parent)
this /* QObject parent */)),
_minTileAreaPercent(SettingsFact(settingsGroup,
_metaDataMap[minTileAreaName],
this /* QObject parent */)),
this /* QObject parent */)),
_showTiles(SettingsFact(settingsGroup, _metaDataMap[showTilesName],
this /* QObject parent */)),
_state(STATE::IDLE) {
......@@ -91,7 +91,7 @@ WimaMeasurementArea::WimaMeasurementArea(const WimaMeasurementArea &other,
this /* QObject parent */)),
_minTileAreaPercent(SettingsFact(settingsGroup,
_metaDataMap[minTileAreaName],
this /* QObject parent */)),
this /* QObject parent */)),
_showTiles(SettingsFact(settingsGroup, _metaDataMap[showTilesName],
this /* QObject parent */)),
_state(STATE::IDLE) {
......@@ -157,12 +157,12 @@ bool WimaMeasurementArea::ready() const { return this->_state == STATE::IDLE; }
void WimaMeasurementArea::saveToJson(QJsonObject &json) {
if (ready()) {
this->WimaArea::saveToJson(json);
json[tileHeightName] = _tileHeight.rawValue().toDouble();
json[tileWidthName] = _tileWidth.rawValue().toDouble();
this->WimaArea::saveToJson(json);
json[tileHeightName] = _tileHeight.rawValue().toDouble();
json[tileWidthName] = _tileWidth.rawValue().toDouble();
json[minTileAreaName] = _minTileAreaPercent.rawValue().toDouble();
json[showTilesName] = _showTiles.rawValue().toBool();
json[areaTypeName] = WimaMeasurementAreaName;
json[showTilesName] = _showTiles.rawValue().toBool();
json[areaTypeName] = WimaMeasurementAreaName;
} else {
qCDebug(WimaMeasurementAreaLog) << "saveToJson(): not ready for saveing.";
}
......@@ -231,70 +231,70 @@ void WimaMeasurementArea::doUpdate() {
using namespace boost::units;
auto start = std::chrono::high_resolution_clock::now();
// Check state.
if (this->_state != STATE::UPDATEING && this->_state != STATE::STOP) {
const auto height = this->_tileHeight.rawValue().toDouble() * si::meter;
const auto width = this->_tileWidth.rawValue().toDouble() * si::meter;
const auto tileArea = width * height;
const auto totalArea = this->area() * si::meter * si::meter;
const auto estNumTiles = totalArea / tileArea;
const auto height = this->_tileHeight.rawValue().toDouble() * si::meter;
const auto width = this->_tileWidth.rawValue().toDouble() * si::meter;
const auto tileArea = width * height;
const auto totalArea = this->area() * si::meter * si::meter;
const auto estNumTiles = totalArea / tileArea;
// Check some conditions.
if (long(std::ceil(estNumTiles.value())) <= SNAKE_MAX_TILES &&
this->count() >= 3 && this->isSimplePolygon()) {
this->count() >= 3 && this->isSimplePolygon()) {
setState(STATE::UPDATEING);
auto polygon = this->coordinateList();
for (auto &v : polygon) {
v.setAltitude(0);
}
const auto minArea =
auto polygon = this->coordinateList();
for (auto &v : polygon) {
v.setAltitude(0);
}
const auto minArea =
this->_minTileAreaPercent.rawValue().toDouble() / 100 * tileArea;
auto *th = this->thread();
auto future = QtConcurrent::run([polygon, th, height, width, minArea] {
auto start = std::chrono::high_resolution_clock::now();
DataPtr pData(new TileData());
// Convert to ENU system.
QGeoCoordinate origin = polygon.first();
FPolygon polygonENU;
areaToEnu(origin, polygon, polygonENU);
std::vector<FPolygon> tilesENU;
BoundingBox bbox;
std::string errorString;
// Generate tiles.
if (snake::tiles(polygonENU, height, width, minArea, tilesENU, bbox,
errorString)) {
// Convert to geo system.
for (const auto &t : tilesENU) {
auto geoTile = new SnakeTile(pData.get());
for (const auto &v : t.outer()) {
QGeoCoordinate geoVertex;
fromENU(origin, v, geoVertex);
geoTile->push_back(geoVertex);
}
pData->tiles.append(geoTile);
// Calculate center.
snake::FPoint center;
snake::polygonCenter(t, center);
QGeoCoordinate geoCenter;
fromENU(origin, center, geoCenter);
pData->tileCenterPoints.append(QVariant::fromValue(geoCenter));
auto *th = this->thread();
auto future = QtConcurrent::run([polygon, th, height, width, minArea] {
auto start = std::chrono::high_resolution_clock::now();
DataPtr pData(new TileData());
// Convert to ENU system.
QGeoCoordinate origin = polygon.first();
FPolygon polygonENU;
areaToEnu(origin, polygon, polygonENU);
std::vector<FPolygon> tilesENU;
BoundingBox bbox;
std::string errorString;
// Generate tiles.
if (snake::tiles(polygonENU, height, width, minArea, tilesENU, bbox,
errorString)) {
// Convert to geo system.
for (const auto &t : tilesENU) {
auto geoTile = new SnakeTile(pData.get());
for (const auto &v : t.outer()) {
QGeoCoordinate geoVertex;
fromENU(origin, v, geoVertex);
geoTile->push_back(geoVertex);
}
pData->tiles.append(geoTile);
// Calculate center.
snake::FPoint center;
snake::polygonCenter(t, center);
QGeoCoordinate geoCenter;
fromENU(origin, center, geoCenter);
pData->tileCenterPoints.append(QVariant::fromValue(geoCenter));
}
pData->moveToThread(th);
}
pData->moveToThread(th);
qCDebug(WimaMeasurementAreaLog)
<< "doUpdate(): update time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start)
.count()
<< " ms";
qCDebug(WimaMeasurementAreaLog)
<< "doUpdate(): update time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start)
.count()
<< " ms";
return pData;
}); // QtConcurrent::run()
return pData;
}); // QtConcurrent::run()
this->_watcher.setFuture(future);
}
this->_watcher.setFuture(future);
}
}
qCDebug(WimaMeasurementAreaLog)
<< "doUpdate(): execution time: "
......
......@@ -106,7 +106,7 @@ private:
SettingsFact _showTiles;
QVector<int> _progress;
// Tile stuff.
// Tile stuff.
mutable QTimer _timer;
using DataPtr = std::shared_ptr<TileData>;
......
......@@ -22,6 +22,7 @@ bool WimaMeasurementAreaData::
operator==(const WimaMeasurementAreaData &other) const {
return this->WimaAreaData::operator==(other) &&
this->_tileData == other.tileData() &&
this->_progress == other.progress() &&
this->center() == other.center();
}
......@@ -33,6 +34,8 @@ operator!=(const WimaMeasurementAreaData &other) const {
void WimaMeasurementAreaData::setTileData(const TileData &d) {
if (this->_tileData != d) {
this->_tileData = d;
this->_progress.fill(0, d.size());
emit progressChanged();
emit tileDataChanged();
}
}
......@@ -51,7 +54,9 @@ void WimaMeasurementAreaData::setProgress(const QVector<int> &d) {
*/
WimaMeasurementAreaData &WimaMeasurementAreaData::
operator=(const WimaMeasurementAreaData &other) {
assign(other);
WimaAreaData::operator=(other);
setTileData(other._tileData);
setProgress(other._progress);
return *this;
}
......@@ -63,7 +68,14 @@ operator=(const WimaMeasurementAreaData &other) {
*/
WimaMeasurementAreaData &WimaMeasurementAreaData::
operator=(const WimaMeasurementArea &other) {
assign(other);
WimaAreaData::operator=(other);
if (other.ready()) {
setTileData(other.tileData());
setProgress(other.progress());
} else {
qWarning() << "WimaMeasurementAreaData::operator=(): WimaMeasurementArea "
"not ready.";
}
return *this;
}
......@@ -102,23 +114,6 @@ const QVector<int> &WimaMeasurementAreaData::progress() const {
QVector<int> &WimaMeasurementAreaData::progress() { return this->_progress; }
void WimaMeasurementAreaData::assign(const WimaMeasurementAreaData &other) {
WimaAreaData::assign(other);
setTileData(other._tileData);
setProgress(other._progress);
}
void WimaMeasurementAreaData::assign(const WimaMeasurementArea &other) {
WimaAreaData::assign(other);
if (other.ready()) {
setTileData(other.tileData());
setProgress(other.progress());
} else {
qWarning()
<< "WimaMeasurementAreaData::assign(): WimaMeasurementArea not ready.";
}
}
bool operator==(const WimaMeasurementAreaData &m1,
const WimaMeasurementArea &m2) {
return operator==(*static_cast<const WimaAreaData *>(&m1),
......
......@@ -50,10 +50,6 @@ signals:
void tileDataChanged();
void progressChanged();
protected:
void assign(const WimaMeasurementAreaData &other);
void assign(const WimaMeasurementArea &other);
private:
TileData _tileData;
QVector<int> _progress;
......
......@@ -7,26 +7,22 @@ WimaServiceAreaData::WimaServiceAreaData(QObject *parent)
WimaServiceAreaData::WimaServiceAreaData(const WimaServiceAreaData &other,
QObject *parent)
: WimaAreaData(parent) {
*this = other;
}
: WimaAreaData(other, parent), _depot(other._depot) {}
WimaServiceAreaData::WimaServiceAreaData(const WimaServiceArea &other,
QObject *parent)
: WimaAreaData(parent) {
*this = other;
}
: WimaAreaData(other, parent), _depot(other.depot()) {}
WimaServiceAreaData &WimaServiceAreaData::
operator=(const WimaServiceAreaData &otherData) {
this->assign(otherData);
WimaAreaData::operator=(otherData);
this->setDepot(otherData.depot());
return *this;
}
WimaServiceAreaData &WimaServiceAreaData::
operator=(const WimaServiceArea &otherArea) {
this->assign(otherArea);
WimaAreaData::operator=(otherArea);
this->setDepot(otherArea.depot());
return *this;
}
......@@ -57,16 +53,6 @@ void WimaServiceAreaData::setDepot(const QGeoCoordinate &newCoordinate) {
}
}
void WimaServiceAreaData::assign(const WimaServiceAreaData &other) {
WimaAreaData::assign(other);
setDepot(other.depot());
}
void WimaServiceAreaData::assign(const WimaServiceArea &other) {
WimaAreaData::assign(other);
setDepot(other.depot());
}
/*!
* \class WimaAreaData::WimaServiceAreaData
* \brief Class to store and exchange data of a \c WimaServiceArea Object.
......
......@@ -31,10 +31,6 @@ signals:
public slots:
void setDepot(const QGeoCoordinate &newCoordinate);
protected:
void assign(const WimaServiceAreaData &other);
void assign(const WimaServiceArea &other);
private:
// see WimaServieArea.h for explanation
QGeoCoordinate _depot;
......
......@@ -5,7 +5,7 @@
#include <QDebug>
#include "QGCLoggingCategory.h"
QGC_LOGGING_CATEGORY(RoutingWorkerLog, "RoutingWorkerLog")
QGC_LOGGING_CATEGORY(RoutingThreadLog, "RoutingThreadLog")
RoutingThread::RoutingThread(QObject *parent)
: QThread(parent), _calculating(false), _stop(false), _restart(false) {
......@@ -44,10 +44,10 @@ void RoutingThread::route(const RoutingParameter &par,
}
void RoutingThread::run() {
qCWarning(RoutingWorkerLog) << "run(): thread start.";
qCDebug(RoutingThreadLog) << "run(): thread start.";
while (!this->_stop) {
qCWarning(RoutingWorkerLog) << "run(): calculation "
"started.";
qCDebug(RoutingThreadLog) << "run(): calculation "
"started.";
// Copy input.
auto start = std::chrono::high_resolution_clock::now();
......@@ -59,7 +59,7 @@ void RoutingThread::run() {
lk.unlock();
auto safeAreaENU = par.safeArea;
auto numRuns = par.numRuns;
auto numSolutionsPerRun = par.numSolutionsPerRun;
auto numSolutionsPerRun = par.numSolutions;
PtrRoutingData pRouteData(new RoutingData());
auto &transectsENU = pRouteData->transects;
......@@ -67,8 +67,8 @@ void RoutingThread::run() {
if (generator(transectsENU)) {
// Check if generation was successful.
if (transectsENU.size() == 0) {
qCWarning(RoutingWorkerLog) << "run(): "
"not able to generate transects.";
qCDebug(RoutingThreadLog) << "run(): "
"not able to generate transects.";
} else {
// Prepare data for routing.
auto &solutionVector = pRouteData->solutionVector;
......@@ -93,24 +93,24 @@ void RoutingThread::run() {
// Check if routing was successful.
if ((!success || solutionVector.size() < 1) && !this->_restart) {
qCWarning(RoutingWorkerLog) << "run(): "
"routing failed. "
<< snakePar.errorString.c_str();
qCDebug(RoutingThreadLog) << "run(): "
"routing failed. "
<< snakePar.errorString.c_str();
} else if (this->_restart) {
qCWarning(RoutingWorkerLog) << "run(): "
"restart requested.";
qCDebug(RoutingThreadLog) << "run(): "
"restart requested.";
} else {
// Notify main thread.
emit result(pRouteData);
qCWarning(RoutingWorkerLog) << "run(): "
"concurrent update success.";
qCDebug(RoutingThreadLog) << "run(): "
"concurrent update success.";
}
}
} // end calculation
else {
qCWarning(RoutingWorkerLog) << "run(): generator() failed.";
qCDebug(RoutingThreadLog) << "run(): generator() failed.";
}
qCWarning(RoutingWorkerLog)
qCDebug(RoutingThreadLog)
<< "run(): execution time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start)
......@@ -125,5 +125,5 @@ void RoutingThread::run() {
}
this->_restart = false;
} // main loop
qCWarning(RoutingWorkerLog) << "run(): thread end.";
qCDebug(RoutingThreadLog) << "run(): thread end.";
}
......@@ -17,9 +17,9 @@ struct RoutingData {
};
struct RoutingParameter {
RoutingParameter() : numSolutionsPerRun(1), numRuns(1) {}
RoutingParameter() : numSolutions(1), numRuns(1) {}
snake::FPolygon safeArea;
std::size_t numSolutionsPerRun;
std::size_t numSolutions;
std::size_t numRuns;
};
//!
......@@ -31,7 +31,7 @@ class RoutingThread : public QThread {
using Lock = std::unique_lock<std::mutex>;
public:
using PtrRoutingData = QSharedPointer<RoutingData>;
using PtrRoutingData = shared_ptr<RoutingData>;
using Generator = std::function<bool(snake::Transects &)>;
using Consumer = std::function<void(const RoutingData &)>;
......
#include "CircularGenerator.h"
#include "QGCLoggingCategory.h"
QGC_LOGGING_CATEGORY(CircularGeneratorLog, "CircularGeneratorLog")
#define CLIPPER_SCALE 1000000
#include "Wima/Geometry/GenericCircle.h"
#include "clipper/clipper.hpp"
using namespace ClipperLib;
template <> inline auto get<0>(const IntPoint &p) { return p.X; }
template <> inline auto get<1>(const IntPoint &p) { return p.Y; }
#include "SnakeTile.h"
#include "Wima/RoutingThread.h"
namespace routing {
bool circularTransects(const snake::FPoint &reference,
const snake::FPolygon &polygon,
const std::vector<snake::FPolygon> &tiles,
snake::Length deltaR, snake::Angle deltaAlpha,
snake::Length minLength, snake::Transects &transects);
const char *CircularGenerator::settingsGroup = "CircularGenerator";
const char *CircularGenerator::distanceName = "TransectDistance";
const char *CircularGenerator::deltaAlphaName = "DeltaAlpha";
const char *CircularGenerator::minLengthName = "MinLength";
const char *CircularGenerator::refPointLatitudeName = "ReferencePointLat";
const char *CircularGenerator::refPointLongitudeName = "ReferencePointLong";
const char *CircularGenerator::refPointAltitudeName = "ReferencePointAlt";
CircularGenerator::CircularGenerator(QObject *parent)
: CircularGenerator(nullptr, parent) {}
CircularGenerator::CircularGenerator(GeneratorBase::Data d, QObject *parent)
: GeneratorBase(d, parent), _connectionsEstablished(false),
_metaDataMap(FactMetaData::createMapFromJsonFile(
QStringLiteral(":/json/CircularGenerator.SettingsGroup.json"), this)),
_distance(settingsGroup, _metaDataMap[distanceName]),
_deltaAlpha(settingsGroup, _metaDataMap[deltaAlphaName]),
_minLength(settingsGroup, _metaDataMap[minLengthName]) {
establishConnections();
}
QString CircularGenerator::editorQml() {
return QStringLiteral("CircularGeneratorEditor.qml");
}
QString CircularGenerator::mapVisualQml() {
return QStringLiteral("CircularGeneratorMapVisual.qml");
}
QString CircularGenerator::name() {
return QStringLiteral("Circular Generator");
}
QString CircularGenerator::abbreviation() { return QStringLiteral("C. Gen."); }
bool CircularGenerator::get(Generator &generator) {
if (this->_d) {
if (this->_d->isValid()) {
// Prepare data.
auto origin = this->_d->origin();
origin.setAltitude(0);
if (!origin.isValid()) {
qCDebug(CircularGeneratorLog) << "get(): origin invalid." << origin;
return false;
}
auto ref = this->_reference;
ref.setAltitude(0);
if (!ref.isValid()) {
qCDebug(CircularGeneratorLog) << "get(): reference invalid." << ref;
return false;
}
snake::FPoint reference;
snake::toENU(origin, ref, reference);
auto geoPolygon = this->_d->measurementArea().coordinateList();
for (auto &v : geoPolygon) {
if (v.isValid()) {
v.setAltitude(0);
} else {
qCDebug(CircularGeneratorLog) << "get(): measurement area invalid.";
for (const auto &w : geoPolygon) {
qCDebug(CircularGeneratorLog) << w;
}
return false;
}
}
auto pPolygon = std::make_shared<snake::FPolygon>();
snake::areaToEnu(origin, geoPolygon, *pPolygon);
// Progress and tiles.
const auto &progress = this->_d->measurementArea().progress();
const auto *tiles = this->_d->measurementArea().tiles();
auto pTiles = std::make_shared<std::vector<snake::FPolygon>>();
if (progress.size() == tiles->count()) {
for (int i = 0; i < tiles->count(); ++i) {
if (progress[i] == 100) {
const auto *tile = tiles->value<const SnakeTile *>(i);
if (tile != nullptr) {
snake::FPolygon tileENU;
snake::areaToEnu(origin, tile->coordinateList(), tileENU);
pTiles->push_back(std::move(tileENU));
} else {
qCDebug(CircularGeneratorLog)
<< "get(): progress.size() != tiles->count().";
return false;
}
}
}
} else {
qCDebug(CircularGeneratorLog)
<< "get(): progress.size() != tiles->count().";
return false;
}
auto geoDepot = this->_d->serviceArea().depot();
if (!geoDepot.isValid()) {
qCDebug(CircularGeneratorLog) << "get(): depot invalid." << geoDepot;
return false;
}
snake::FPoint depot;
snake::toENU(origin, geoDepot, depot);
// Fetch transect parameter.
auto distance =
snake::Length(this->_distance.rawValue().toDouble() * bu::si::meter);
auto minLength =
snake::Length(this->_minLength.rawValue().toDouble() * bu::si::meter);
auto alpha = snake::Angle(this->_deltaAlpha.rawValue().toDouble() *
bu::degree::degree);
generator = [reference, depot, pPolygon, pTiles, distance, alpha,
minLength](snake::Transects &transects) -> bool {
bool value = circularTransects(reference, *pPolygon, *pTiles, distance,
alpha, minLength, transects);
transects.insert(transects.begin(), snake::FLineString{depot});
return value;
};
return true;
} else {
qCDebug(CircularGeneratorLog) << "get(): data invalid.";
return false;
}
} else {
qCDebug(CircularGeneratorLog) << "get(): data member not set.";
return false;
}
}
QGeoCoordinate CircularGenerator::reference() const { return _reference; }
void CircularGenerator::setReference(const QGeoCoordinate &reference) {
if (_reference != reference) {
_reference = reference;
emit referenceChanged();
}
}
void CircularGenerator::resetReferenceIfInvalid() {
if (!this->_reference.isValid()) {
resetReference();
}
}
void CircularGenerator::resetReference() {
if (this->_d->measurementArea().center().isValid()) {
setReference(this->_d->measurementArea().center());
} else {
qCWarning(CircularGeneratorLog)
<< "measurement area center" << this->_d->measurementArea().center();
}
}
void CircularGenerator::establishConnections() {
if (this->_d && !this->_connectionsEstablished) {
connect(this->_d.get(), &WimaPlanData::originChanged, this,
&GeneratorBase::generatorChanged);
connect(&this->_d->measurementArea(),
&WimaMeasurementAreaData::progressChanged, this,
&GeneratorBase::generatorChanged);
connect(&this->_d->measurementArea(),
&WimaMeasurementAreaData::tileDataChanged, this,
&GeneratorBase::generatorChanged);
connect(&this->_d->measurementArea(),
&WimaMeasurementAreaData::centerChanged, this,
&CircularGenerator::resetReferenceIfInvalid);
connect(&this->_d->measurementArea(), &WimaMeasurementAreaData::pathChanged,
this, &GeneratorBase::generatorChanged);
connect(&this->_d->serviceArea(), &WimaServiceAreaData::depotChanged, this,
&GeneratorBase::generatorChanged);
connect(&this->_d->joinedArea(), &WimaJoinedAreaData::pathChanged, this,
&GeneratorBase::generatorChanged);
connect(this->distance(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
connect(this->deltaAlpha(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
connect(this->minLength(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
connect(this, &CircularGenerator::referenceChanged, this,
&GeneratorBase::generatorChanged);
this->_connectionsEstablished = true;
}
}
void CircularGenerator::deleteConnections() {
if (this->_d && this->_connectionsEstablished) {
disconnect(this->_d.get(), &WimaPlanData::originChanged, this,
&GeneratorBase::generatorChanged);
disconnect(&this->_d->measurementArea(),
&WimaMeasurementAreaData::progressChanged, this,
&GeneratorBase::generatorChanged);
disconnect(&this->_d->measurementArea(),
&WimaMeasurementAreaData::tileDataChanged, this,
&GeneratorBase::generatorChanged);
disconnect(&this->_d->measurementArea(), &WimaMeasurementAreaData::center,
this, &CircularGenerator::resetReferenceIfInvalid);
disconnect(&this->_d->measurementArea(),
&WimaMeasurementAreaData::pathChanged, this,
&GeneratorBase::generatorChanged);
disconnect(&this->_d->serviceArea(), &WimaServiceAreaData::depotChanged,
this, &GeneratorBase::generatorChanged);
disconnect(&this->_d->joinedArea(), &WimaJoinedAreaData::pathChanged, this,
&GeneratorBase::generatorChanged);
disconnect(this->distance(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
disconnect(this->deltaAlpha(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
disconnect(this->minLength(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
disconnect(this, &CircularGenerator::referenceChanged, this,
&GeneratorBase::generatorChanged);
this->_connectionsEstablished = false;
}
}
Fact *CircularGenerator::distance() { return &_distance; }
Fact *CircularGenerator::deltaAlpha() { return &_deltaAlpha; }
Fact *CircularGenerator::minLength() { return &_minLength; }
bool circularTransects(const snake::FPoint &reference,
const snake::FPolygon &polygon,
const std::vector<snake::FPolygon> &tiles,
snake::Length deltaR, snake::Angle deltaAlpha,
snake::Length minLength, snake::Transects &transects) {
auto s1 = std::chrono::high_resolution_clock::now();
// Check preconitions
if (polygon.outer().size() >= 3) {
using namespace boost::units;
// Convert geo polygon to ENU polygon.
std::string error;
// Check validity.
if (!bg::is_valid(polygon, error)) {
qCDebug(CircularGeneratorLog) << "circularTransects(): "
"invalid polygon.";
qCDebug(CircularGeneratorLog) << error.c_str();
std::stringstream ss;
ss << bg::wkt(polygon);
qCDebug(CircularGeneratorLog) << ss.str().c_str();
} else {
// Calculate polygon distances and angles.
std::vector<snake::Length> distances;
distances.reserve(polygon.outer().size());
std::vector<snake::Angle> angles;
angles.reserve(polygon.outer().size());
//#ifdef DEBUG_CIRCULAR_SURVEY
// qCDebug(CircularGeneratorLog) << "circularTransects():";
//#endif
for (const auto &p : polygon.outer()) {
snake::Length distance = bg::distance(reference, p) * si::meter;
distances.push_back(distance);
snake::Angle alpha = (std::atan2(p.get<1>(), p.get<0>())) * si::radian;
alpha = alpha < 0 * si::radian ? alpha + 2 * M_PI * si::radian : alpha;
angles.push_back(alpha);
//#ifdef DEBUG_CIRCULAR_SURVEY
// qCDebug(CircularGeneratorLog) << "distances, angles,
// coordinates:"; qCDebug(CircularGeneratorLog) <<
// to_string(distance).c_str(); qCDebug(CircularGeneratorLog)
// << to_string(snake::Degree(alpha)).c_str();
// qCDebug(CircularGeneratorLog) << "x = " << p.get<0>() << "y
// = "
// << p.get<1>();
//#endif
}
auto rMin = deltaR; // minimal circle radius
snake::Angle alpha1(0 * degree::degree);
snake::Angle alpha2(360 * degree::degree);
// Determine r_min by successive approximation
if (!bg::within(reference, polygon.outer())) {
rMin = bg::distance(reference, polygon) * si::meter;
}
auto rMax = (*std::max_element(distances.begin(),
distances.end())); // maximal circle radius
// Scale parameters and coordinates.
const auto rMinScaled =
ClipperLib::cInt(std::round(rMin.value() * CLIPPER_SCALE));
const auto deltaRScaled =
ClipperLib::cInt(std::round(deltaR.value() * CLIPPER_SCALE));
auto referenceScaled = ClipperLib::IntPoint{
ClipperLib::cInt(std::round(reference.get<0>() * CLIPPER_SCALE)),
ClipperLib::cInt(std::round(reference.get<1>() * CLIPPER_SCALE))};
// Generate circle sectors.
auto rScaled = rMinScaled;
const auto nTran = long(std::ceil(((rMax - rMin) / deltaR).value()));
vector<ClipperLib::Path> sectors(nTran, ClipperLib::Path());
const auto nSectors =
long(std::round(((alpha2 - alpha1) / deltaAlpha).value()));
//#ifdef DEBUG_CIRCULAR_SURVEY
// qCDebug(CircularGeneratorLog) << "circularTransects(): sector
// parameres:"; qCDebug(CircularGeneratorLog) << "alpha1: " <<
// to_string(snake::Degree(alpha1)).c_str();
// qCDebug(CircularGeneratorLog) << "alpha2:
// "
// << to_string(snake::Degree(alpha2)).c_str();
// qCDebug(CircularGeneratorLog) << "n: "
// << to_string((alpha2 - alpha1) / deltaAlpha).c_str();
// qCDebug(CircularGeneratorLog)
// << "nSectors: " << nSectors; qCDebug(CircularGeneratorLog) <<
// "rMin: " << to_string(rMin).c_str();
// qCDebug(CircularGeneratorLog)
// << "rMax: " << to_string(rMax).c_str();
// qCDebug(CircularGeneratorLog) << "nTran: " << nTran;
//#endif
using ClipperCircle =
GenericCircle<ClipperLib::cInt, ClipperLib::IntPoint>;
for (auto &sector : sectors) {
ClipperCircle circle(rScaled, referenceScaled);
approximate(circle, nSectors, sector);
rScaled += deltaRScaled;
}
// Clip sectors to polygonENU.
ClipperLib::Path polygonClipper;
snake::FPolygon shrinked;
snake::offsetPolygon(polygon, shrinked, -0.3);
auto &outer = shrinked.outer();
polygonClipper.reserve(outer.size());
for (auto it = outer.begin(); it < outer.end() - 1; ++it) {
auto x = ClipperLib::cInt(std::round(it->get<0>() * CLIPPER_SCALE));
auto y = ClipperLib::cInt(std::round(it->get<1>() * CLIPPER_SCALE));
polygonClipper.push_back(ClipperLib::IntPoint{x, y});
}
ClipperLib::Clipper clipper;
clipper.AddPath(polygonClipper, ClipperLib::ptClip, true);
clipper.AddPaths(sectors, ClipperLib::ptSubject, false);
ClipperLib::PolyTree transectsClipper;
clipper.Execute(ClipperLib::ctIntersection, transectsClipper,
ClipperLib::pftNonZero, ClipperLib::pftNonZero);
// Subtract holes.
if (tiles.size() > 0) {
vector<ClipperLib::Path> processedTiles;
for (const auto &tile : tiles) {
ClipperLib::Path path;
for (const auto &v : tile.outer()) {
path.push_back(ClipperLib::IntPoint{
static_cast<ClipperLib::cInt>(v.get<0>() * CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(v.get<1>() * CLIPPER_SCALE)});
}
processedTiles.push_back(std::move(path));
}
clipper.Clear();
for (const auto &child : transectsClipper.Childs) {
clipper.AddPath(child->Contour, ClipperLib::ptSubject, false);
}
clipper.AddPaths(processedTiles, ClipperLib::ptClip, true);
transectsClipper.Clear();
clipper.Execute(ClipperLib::ctDifference, transectsClipper,
ClipperLib::pftNonZero, ClipperLib::pftNonZero);
}
// Extract transects from PolyTree and convert them to
// BoostLineString
for (const auto &child : transectsClipper.Childs) {
snake::FLineString transect;
transect.reserve(child->Contour.size());
for (const auto &vertex : child->Contour) {
auto x = static_cast<double>(vertex.X) / CLIPPER_SCALE;
auto y = static_cast<double>(vertex.Y) / CLIPPER_SCALE;
transect.push_back(snake::FPoint(x, y));
}
transects.push_back(transect);
}
// Join sectors which where slit due to clipping.
const double th = 0.01;
for (auto ito = transects.begin(); ito < transects.end(); ++ito) {
for (auto iti = ito + 1; iti < transects.end(); ++iti) {
auto dist1 = bg::distance(ito->front(), iti->front());
if (dist1 < th) {
snake::FLineString temp;
for (auto it = iti->end() - 1; it >= iti->begin(); --it) {
temp.push_back(*it);
}
temp.insert(temp.end(), ito->begin(), ito->end());
*ito = temp;
transects.erase(iti);
break;
}
auto dist2 = bg::distance(ito->front(), iti->back());
if (dist2 < th) {
snake::FLineString temp;
temp.insert(temp.end(), iti->begin(), iti->end());
temp.insert(temp.end(), ito->begin(), ito->end());
*ito = temp;
transects.erase(iti);
break;
}
auto dist3 = bg::distance(ito->back(), iti->front());
if (dist3 < th) {
snake::FLineString temp;
temp.insert(temp.end(), ito->begin(), ito->end());
temp.insert(temp.end(), iti->begin(), iti->end());
*ito = temp;
transects.erase(iti);
break;
}
auto dist4 = bg::distance(ito->back(), iti->back());
if (dist4 < th) {
snake::FLineString temp;
temp.insert(temp.end(), ito->begin(), ito->end());
for (auto it = iti->end() - 1; it >= iti->begin(); --it) {
temp.push_back(*it);
}
*ito = temp;
transects.erase(iti);
break;
}
}
}
// Remove short transects
for (auto it = transects.begin(); it < transects.end();) {
if (bg::length(*it) < minLength.value()) {
it = transects.erase(it);
} else {
++it;
}
}
qCDebug(CircularGeneratorLog)
<< "circularTransects(): transect gen. time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - s1)
.count()
<< " ms";
return true;
}
}
return false;
}
} // namespace routing
#include "GeneratorBase.h"
#include <QGeoCoordinate>
namespace routing {
class CircularGenerator : public GeneratorBase {
Q_OBJECT
public:
CircularGenerator(QObject *parent = nullptr);
CircularGenerator(Data d, QObject *parent = nullptr);
Q_PROPERTY(QGeoCoordinate reference READ reference WRITE setReference NOTIFY
referenceChanged)
Q_PROPERTY(Fact *distance READ distance CONSTANT)
Q_PROPERTY(Fact *deltaAlpha READ deltaAlpha CONSTANT)
Q_PROPERTY(Fact *minLength READ minLength CONSTANT)
virtual QString editorQml() override;
virtual QString mapVisualQml() override;
virtual QString name() override;
virtual QString abbreviation() override;
virtual bool get(Generator &generator) override;
QGeoCoordinate reference() const;
Fact *distance();
Fact *deltaAlpha();
Fact *minLength();
void setReference(const QGeoCoordinate &reference);
static const char *settingsGroup;
static const char *distanceName;
static const char *deltaAlphaName;
static const char *minLengthName;
static const char *refPointLongitudeName;
static const char *refPointLatitudeName;
static const char *refPointAltitudeName;
signals:
void referenceChanged();
public slots:
Q_INVOKABLE void resetReferenceIfInvalid();
Q_INVOKABLE void resetReference();
protected:
virtual void establishConnections() override;
virtual void deleteConnections() override;
private:
bool _connectionsEstablished;
QGeoCoordinate _reference;
QMap<QString, FactMetaData *> _metaDataMap;
SettingsFact _distance;
SettingsFact _deltaAlpha;
SettingsFact _minLength;
};
} // namespace routing
#include "GeneratorBase.h"
namespace routing {
GeneratorBase::GeneratorBase(QObject *parent)
: GeneratorBase(nullptr, parent) {}
GeneratorBase::GeneratorBase(GeneratorBase::Data d, QObject *parent)
: QObject(parent), _d(d) {
establishConnections();
}
GeneratorBase::~GeneratorBase() {}
QString GeneratorBase::editorQml() { return QStringLiteral(""); }
QString GeneratorBase::mapVisualQml() { return QStringLiteral(""); }
GeneratorBase::Data GeneratorBase::data() const { return _d; }
void GeneratorBase::setData(const Data &d) {
deleteConnections();
_d = d;
establishConnections();
}
void GeneratorBase::establishConnections() {}
void GeneratorBase::deleteConnections() {}
} // namespace routing
#pragma once
#include <QObject>
#include <functional>
#include <memory>
#include "snake.h"
#include "Wima/WimaPlanData.h"
namespace routing {
class GeneratorBase : public QObject {
Q_OBJECT
public:
using Data = std::shared_ptr<WimaPlanData>;
using Generator = std::function<bool(snake::Transects &)>;
explicit GeneratorBase(QObject *parent = nullptr);
explicit GeneratorBase(Data d, QObject *parent = nullptr);
~GeneratorBase();
Q_PROPERTY(QString editorQml READ editorQml CONSTANT)
Q_PROPERTY(QString mapVisualQml READ mapVisualQml CONSTANT)
virtual QString editorQml();
virtual QString mapVisualQml();
virtual QString name() = 0;
virtual QString abbreviation() = 0;
virtual bool get(Generator &generator) = 0;
Data data() const;
void setData(const Data &d);
signals:
void generatorChanged();
protected:
virtual void establishConnections();
virtual void deleteConnections();
Data _d;
};
} // namespace routing
#include "LinearGenerator.h"
#include "QGCLoggingCategory.h"
QGC_LOGGING_CATEGORY(LinearGeneratorLog, "LinearGeneratorLog")
#define CLIPPER_SCALE 1000000
#include "clipper/clipper.hpp"
#include "SnakeTile.h"
#include "Wima/RoutingThread.h"
namespace routing {
bool linearTransects(const snake::FPolygon &polygon,
const std::vector<snake::FPolygon> &tiles,
snake::Length distance, snake::Angle angle,
snake::Length minLength, snake::Transects &transects);
const char *LinearGenerator::settingsGroup = "LinearGenerator";
const char *LinearGenerator::distanceName = "TransectDistance";
const char *LinearGenerator::alphaName = "Alpha";
const char *LinearGenerator::minLengthName = "MinLength";
LinearGenerator::LinearGenerator(QObject *parent)
: LinearGenerator(nullptr, parent) {}
LinearGenerator::LinearGenerator(GeneratorBase::Data d, QObject *parent)
: GeneratorBase(d, parent),
_metaDataMap(FactMetaData::createMapFromJsonFile(
QStringLiteral(":/json/LinearGenerator.SettingsGroup.json"), this)),
_distance(settingsGroup, _metaDataMap[distanceName]),
_alpha(settingsGroup, _metaDataMap[alphaName]),
_minLength(settingsGroup, _metaDataMap[minLengthName]) {
establishConnections();
}
QString LinearGenerator::editorQml() {
return QStringLiteral("LinearGeneratorEditor.qml");
}
QString LinearGenerator::name() { return QStringLiteral("Linear Generator"); }
QString LinearGenerator::abbreviation() { return QStringLiteral("L. Gen."); }
bool LinearGenerator::get(Generator &generator) {
if (_d) {
if (this->_d->isValid()) {
// Prepare data.
auto origin = this->_d->origin();
origin.setAltitude(0);
if (!origin.isValid()) {
qCDebug(LinearGeneratorLog) << "get(): origin invalid." << origin;
}
auto geoPolygon = this->_d->measurementArea().coordinateList();
for (auto &v : geoPolygon) {
if (v.isValid()) {
v.setAltitude(0);
} else {
qCDebug(LinearGeneratorLog) << "get(): measurement area invalid.";
for (const auto &w : geoPolygon) {
qCDebug(LinearGeneratorLog) << w;
}
return false;
}
}
auto pPolygon = std::make_shared<snake::FPolygon>();
snake::areaToEnu(origin, geoPolygon, *pPolygon);
// Progress and tiles.
const auto &progress = this->_d->measurementArea().progress();
const auto *tiles = this->_d->measurementArea().tiles();
auto pTiles = std::make_shared<std::vector<snake::FPolygon>>();
if (progress.size() == tiles->count()) {
for (int i = 0; i < tiles->count(); ++i) {
if (progress[i] == 100) {
const auto *tile = tiles->value<const SnakeTile *>(i);
if (tile != nullptr) {
snake::FPolygon tileENU;
snake::areaToEnu(origin, tile->coordinateList(), tileENU);
pTiles->push_back(std::move(tileENU));
} else {
qCDebug(LinearGeneratorLog) << "get(): tile == nullptr";
return false;
}
}
}
} else {
qCDebug(LinearGeneratorLog)
<< "get(): progress.size() != tiles->count().";
return false;
}
auto geoDepot = this->_d->serviceArea().depot();
if (!geoDepot.isValid()) {
qCDebug(LinearGeneratorLog) << "get(): depot invalid." << geoDepot;
return false;
}
snake::FPoint depot;
snake::toENU(origin, geoDepot, depot);
// Fetch transect parameter.
auto distance =
snake::Length(this->_distance.rawValue().toDouble() * bu::si::meter);
auto minLength =
snake::Length(this->_minLength.rawValue().toDouble() * bu::si::meter);
auto alpha =
snake::Angle(this->_alpha.rawValue().toDouble() * bu::degree::degree);
generator = [depot, pPolygon, pTiles, distance, alpha,
minLength](snake::Transects &transects) -> bool {
bool value = linearTransects(*pPolygon, *pTiles, distance, alpha,
minLength, transects);
transects.insert(transects.begin(), snake::FLineString{depot});
return value;
};
return true;
} else {
qCDebug(LinearGeneratorLog) << "get(): data invalid.";
return false;
}
} else {
qCDebug(LinearGeneratorLog) << "get(): data member not set.";
return false;
}
}
Fact *LinearGenerator::distance() { return &_distance; }
Fact *LinearGenerator::alpha() { return &_alpha; }
Fact *LinearGenerator::minLength() { return &_minLength; }
void LinearGenerator::establishConnections() {
if (this->_d && !this->_connectionsEstablished) {
connect(this->_d.get(), &WimaPlanData::originChanged, this,
&GeneratorBase::generatorChanged);
connect(&this->_d->measurementArea(),
&WimaMeasurementAreaData::progressChanged, this,
&GeneratorBase::generatorChanged);
connect(&this->_d->measurementArea(),
&WimaMeasurementAreaData::tileDataChanged, this,
&GeneratorBase::generatorChanged);
connect(&this->_d->measurementArea(), &WimaMeasurementAreaData::pathChanged,
this, &GeneratorBase::generatorChanged);
connect(&this->_d->serviceArea(), &WimaServiceAreaData::depotChanged, this,
&GeneratorBase::generatorChanged);
connect(&this->_d->joinedArea(), &WimaJoinedAreaData::pathChanged, this,
&GeneratorBase::generatorChanged);
connect(this->distance(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
connect(this->alpha(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
connect(this->minLength(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
this->_connectionsEstablished = true;
}
}
void LinearGenerator::deleteConnections() {
if (this->_d && this->_connectionsEstablished) {
connect(this->_d.get(), &WimaPlanData::originChanged, this,
&GeneratorBase::generatorChanged);
connect(&this->_d->measurementArea(),
&WimaMeasurementAreaData::progressChanged, this,
&GeneratorBase::generatorChanged);
connect(&this->_d->measurementArea(),
&WimaMeasurementAreaData::tileDataChanged, this,
&GeneratorBase::generatorChanged);
connect(&this->_d->measurementArea(), &WimaMeasurementAreaData::pathChanged,
this, &GeneratorBase::generatorChanged);
connect(&this->_d->serviceArea(), &WimaServiceAreaData::depotChanged, this,
&GeneratorBase::generatorChanged);
connect(&this->_d->joinedArea(), &WimaJoinedAreaData::pathChanged, this,
&GeneratorBase::generatorChanged);
connect(this->distance(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
connect(this->alpha(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
connect(this->minLength(), &Fact::rawValueChanged, this,
&GeneratorBase::generatorChanged);
this->_connectionsEstablished = false;
}
}
bool linearTransects(const snake::FPolygon &polygon,
const std::vector<snake::FPolygon> &tiles,
snake::Length distance, snake::Angle angle,
snake::Length minLength, snake::Transects &transects) {
namespace tr = bg::strategy::transform;
auto s1 = std::chrono::high_resolution_clock::now();
// Check preconitions
if (polygon.outer().size() >= 3) {
// Convert to ENU system.
std::string error;
// Check validity.
if (!bg::is_valid(polygon, error)) {
std::stringstream ss;
ss << bg::wkt(polygon);
qCDebug(LinearGeneratorLog) << "linearTransects(): "
"invalid polygon. "
<< error.c_str() << ss.str().c_str();
} else {
tr::rotate_transformer<bg::degree, double, 2, 2> rotate(angle.value() *
180 / M_PI);
// Rotate polygon by angle and calculate bounding box.
snake::FPolygon polygonENURotated;
bg::transform(polygon.outer(), polygonENURotated.outer(), rotate);
snake::FBox box;
boost::geometry::envelope(polygonENURotated, box);
double x0 = box.min_corner().get<0>();
double y0 = box.min_corner().get<1>();
double x1 = box.max_corner().get<0>();
double y1 = box.max_corner().get<1>();
// Generate transects and convert them to clipper path.
size_t num_t = ceil((y1 - y0) / distance.value()); // number of transects
vector<ClipperLib::Path> transectsClipper;
transectsClipper.reserve(num_t);
for (size_t i = 0; i < num_t; ++i) {
// calculate transect
snake::FPoint v1{x0, y0 + i * distance.value()};
snake::FPoint v2{x1, y0 + i * distance.value()};
snake::FLineString transect;
transect.push_back(v1);
transect.push_back(v2);
// transform back
snake::FLineString temp_transect;
tr::rotate_transformer<bg::degree, double, 2, 2> rotate_back(
-angle.value() * 180 / M_PI);
bg::transform(transect, temp_transect, rotate_back);
// to clipper
ClipperLib::IntPoint c1{static_cast<ClipperLib::cInt>(
temp_transect[0].get<0>() * CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(
temp_transect[0].get<1>() * CLIPPER_SCALE)};
ClipperLib::IntPoint c2{static_cast<ClipperLib::cInt>(
temp_transect[1].get<0>() * CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(
temp_transect[1].get<1>() * CLIPPER_SCALE)};
ClipperLib::Path path{c1, c2};
transectsClipper.push_back(path);
}
if (transectsClipper.size() == 0) {
std::stringstream ss;
ss << "Not able to generate transects. Parameter: distance = "
<< distance << std::endl;
qCDebug(LinearGeneratorLog)
<< "linearTransects(): " << ss.str().c_str();
return false;
}
// Convert measurement area to clipper path.
snake::FPolygon shrinked;
snake::offsetPolygon(polygon, shrinked, -0.2);
auto &outer = shrinked.outer();
ClipperLib::Path polygonClipper;
for (auto vertex : outer) {
polygonClipper.push_back(ClipperLib::IntPoint{
static_cast<ClipperLib::cInt>(vertex.get<0>() * CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(vertex.get<1>() * CLIPPER_SCALE)});
}
// Perform clipping.
// Clip transects to measurement area.
ClipperLib::Clipper clipper;
clipper.AddPath(polygonClipper, ClipperLib::ptClip, true);
clipper.AddPaths(transectsClipper, ClipperLib::ptSubject, false);
ClipperLib::PolyTree clippedTransecs;
clipper.Execute(ClipperLib::ctIntersection, clippedTransecs,
ClipperLib::pftNonZero, ClipperLib::pftNonZero);
// Subtract holes.
if (tiles.size() > 0) {
vector<ClipperLib::Path> processedTiles;
for (const auto &tile : tiles) {
ClipperLib::Path path;
for (const auto &v : tile.outer()) {
path.push_back(ClipperLib::IntPoint{
static_cast<ClipperLib::cInt>(v.get<0>() * CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(v.get<1>() * CLIPPER_SCALE)});
}
processedTiles.push_back(std::move(path));
}
clipper.Clear();
for (const auto &child : clippedTransecs.Childs) {
clipper.AddPath(child->Contour, ClipperLib::ptSubject, false);
}
clipper.AddPaths(processedTiles, ClipperLib::ptClip, true);
clippedTransecs.Clear();
clipper.Execute(ClipperLib::ctDifference, clippedTransecs,
ClipperLib::pftNonZero, ClipperLib::pftNonZero);
}
// Extract transects from PolyTree and convert them to BoostLineString
for (const auto &child : clippedTransecs.Childs) {
const auto &clipperTransect = child->Contour;
snake::FPoint v1{
static_cast<double>(clipperTransect[0].X) / CLIPPER_SCALE,
static_cast<double>(clipperTransect[0].Y) / CLIPPER_SCALE};
snake::FPoint v2{
static_cast<double>(clipperTransect[1].X) / CLIPPER_SCALE,
static_cast<double>(clipperTransect[1].Y) / CLIPPER_SCALE};
snake::FLineString transect{v1, v2};
if (bg::length(transect) >= minLength.value()) {
transects.push_back(transect);
}
}
if (transects.size() == 0) {
std::stringstream ss;
ss << "Not able to generatetransects. Parameter: minLength = "
<< minLength << std::endl;
qCDebug(LinearGeneratorLog)
<< "linearTransects(): " << ss.str().c_str();
return false;
}
qCDebug(LinearGeneratorLog)
<< "linearTransects(): time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - s1)
.count()
<< " ms";
return true;
}
}
return false;
}
} // namespace routing
#include "GeneratorBase.h"
#include <QGeoCoordinate>
namespace routing {
class LinearGenerator : public GeneratorBase {
Q_OBJECT
public:
LinearGenerator(QObject *parent = nullptr);
LinearGenerator(Data d, QObject *parent = nullptr);
Q_PROPERTY(Fact *distance READ distance CONSTANT)
Q_PROPERTY(Fact *alpha READ alpha CONSTANT)
Q_PROPERTY(Fact *minLength READ minLength CONSTANT)
virtual QString editorQml() override;
virtual QString name() override;
virtual QString abbreviation() override;
virtual bool get(Generator &generator) override;
Fact *distance();
Fact *alpha();
Fact *minLength();
static const char *settingsGroup;
static const char *distanceName;
static const char *alphaName;
static const char *minLengthName;
protected:
virtual void establishConnections() override;
virtual void deleteConnections() override;
private:
bool _connectionsEstablished;
QMap<QString, FactMetaData *> _metaDataMap;
SettingsFact _distance;
SettingsFact _alpha;
SettingsFact _minLength;
};
} // namespace routing
......@@ -2,6 +2,7 @@
#include "SnakeTilesLocal.h"
#include "QGCApplication.h"
#include "QGCLoggingCategory.h"
#include "QGCToolbox.h"
#include "SettingsFact.h"
#include "SettingsManager.h"
......@@ -26,6 +27,8 @@
#include "ros_bridge/rapidjson/include/rapidjson/ostreamwrapper.h"
#include "ros_bridge/rapidjson/include/rapidjson/writer.h"
QGC_LOGGING_CATEGORY(NemoInterfaceLog, "NemoInterfaceLog")
#define EVENT_TIMER_INTERVAL 100 // ms
auto static timeoutInterval = std::chrono::milliseconds(3000);
......@@ -160,28 +163,28 @@ void NemoInterface::Impl::setTileData(const TileData &tileData) {
if (tile != nullptr) {
if (tile->coordinateList().size() > 0) {
if (tile->coordinateList().first().isValid()) {
this->ENUOrigin = tile->coordinateList().first();
const auto &origin = this->ENUOrigin;
this->tilesENU.polygons().clear();
for (int i = 0; i < tileData.tiles.count(); ++i) {
obj = tileData.tiles.get(i);
tile = qobject_cast<const SnakeTile *>(obj);
if (tile != nullptr) {
SnakeTileLocal tileENU;
snake::areaToEnu(origin, tile->coordinateList(), tileENU.path());
this->tilesENU.polygons().push_back(std::move(tileENU));
} else {
qWarning() << "NemoInterface::Impl::setTileData(): nullptr.";
break;
}
this->ENUOrigin = tile->coordinateList().first();
const auto &origin = this->ENUOrigin;
this->tilesENU.polygons().clear();
for (int i = 0; i < tileData.tiles.count(); ++i) {
obj = tileData.tiles.get(i);
tile = qobject_cast<const SnakeTile *>(obj);
if (tile != nullptr) {
SnakeTileLocal tileENU;
snake::areaToEnu(origin, tile->coordinateList(), tileENU.path());
this->tilesENU.polygons().push_back(std::move(tileENU));
} else {
qCDebug(NemoInterfaceLog) << "Impl::setTileData(): nullptr.";
break;
}
} else {
qWarning() << "NemoInterface::Impl::setTileData(): Origin invalid.";
}
} else {
qWarning() << "NemoInterface::Impl::setTileData(): tile empty.";
qCDebug(NemoInterfaceLog) << "Impl::setTileData(): Origin invalid.";
}
} else {
qCDebug(NemoInterfaceLog) << "Impl::setTileData(): tile empty.";
}
}
} else {
this->tileData.clear();
......@@ -300,12 +303,17 @@ void NemoInterface::Impl::doTopicServiceSetup() {
std::make_unique<rapidjson::Document>(rapidjson::kObjectType));
auto &origin = this->ENUOrigin;
rapidjson::Value jOrigin(rapidjson::kObjectType);
bool ret = geographic_msgs::geo_point::toJson(origin, jOrigin,
pDoc->GetAllocator());
lk.unlock();
Q_ASSERT(ret);
(void)ret;
if (geographic_msgs::geo_point::toJson(origin, jOrigin,
pDoc->GetAllocator())) {
lk.unlock();
pDoc->AddMember("origin", jOrigin, pDoc->GetAllocator());
} else {
lk.unlock();
qCWarning(NemoInterfaceLog)
<< "/snake/get_origin service: could not create json document.";
}
return pDoc;
});
......@@ -318,11 +326,17 @@ void NemoInterface::Impl::doTopicServiceSetup() {
JsonDocUPtr pDoc(
std::make_unique<rapidjson::Document>(rapidjson::kObjectType));
rapidjson::Value jSnakeTiles(rapidjson::kObjectType);
bool ret = jsk_recognition_msgs::polygon_array::toJson(
this->tilesENU, jSnakeTiles, pDoc->GetAllocator());
Q_ASSERT(ret);
(void)ret;
if (jsk_recognition_msgs::polygon_array::toJson(
this->tilesENU, jSnakeTiles, pDoc->GetAllocator())) {
lk.unlock();
pDoc->AddMember("tiles", jSnakeTiles, pDoc->GetAllocator());
} else {
lk.unlock();
qCWarning(NemoInterfaceLog)
<< "/snake/get_tiles service: could not create json document.";
}
return pDoc;
});
}
......@@ -336,7 +350,7 @@ void NemoInterface::Impl::loop() {
} else if (this->pRosBridge->isRunning() && this->pRosBridge->connected() &&
!this->topicServiceSetupDone) {
this->doTopicServiceSetup();
this->topicServiceSetupDone = true;
this->topicServiceSetupDone = true;
this->setStatus(STATUS::WEBSOCKET_DETECTED);
} else if (this->pRosBridge->isRunning() &&
......@@ -379,22 +393,26 @@ void NemoInterface::Impl::publishTilesENU() {
using namespace ros_bridge::messages;
JsonDocUPtr jSnakeTiles(
std::make_unique<rapidjson::Document>(rapidjson::kObjectType));
bool ret = jsk_recognition_msgs::polygon_array::toJson(
this->tilesENU, *jSnakeTiles, jSnakeTiles->GetAllocator());
Q_ASSERT(ret);
(void)ret;
if (jsk_recognition_msgs::polygon_array::toJson(
this->tilesENU, *jSnakeTiles, jSnakeTiles->GetAllocator())) {
this->pRosBridge->publish(std::move(jSnakeTiles), "/snake/tiles");
} else {
qCWarning(NemoInterfaceLog)
<< "Impl::publishTilesENU: could not create json document.";
}
}
void NemoInterface::Impl::publishENUOrigin() {
using namespace ros_bridge::messages;
JsonDocUPtr jOrigin(
std::make_unique<rapidjson::Document>(rapidjson::kObjectType));
bool ret = geographic_msgs::geo_point::toJson(this->ENUOrigin, *jOrigin,
jOrigin->GetAllocator());
Q_ASSERT(ret);
(void)ret;
if (geographic_msgs::geo_point::toJson(this->ENUOrigin, *jOrigin,
jOrigin->GetAllocator())) {
this->pRosBridge->publish(std::move(jOrigin), "/snake/origin");
} else {
qCWarning(NemoInterfaceLog)
<< "Impl::publishENUOrigin: could not create json document.";
}
}
bool NemoInterface::Impl::setStatus(NemoInterface::STATUS s) {
......@@ -421,7 +439,7 @@ void NemoInterface::stop() { this->pImpl->stop(); }
void NemoInterface::publishTileData() { this->pImpl->publishTileData(); }
void NemoInterface::requestProgress() {
qWarning() << "NemoInterface::requestProgress(): dummy.";
qCWarning(NemoInterfaceLog) << "requestProgress(): dummy.";
}
void NemoInterface::setTileData(const TileData &tileData) {
......
......@@ -18,8 +18,6 @@ QString SnakeTile::type() const { return "Tile"; }
SnakeTile *SnakeTile::Clone() const { return new SnakeTile(*this); }
SnakeTile &SnakeTile::operator=(const SnakeTile &other) {
this->assign(other);
this->WimaAreaData::operator=(other);
return *this;
}
void SnakeTile::assign(const SnakeTile &other) { WimaAreaData::assign(other); }
[
{
"name": "TransectDistance",
"shortDescription": "The distance between transects.",
"type": "double",
"units": "m",
"min": 0.3,
"decimalPlaces": 1,
"defaultValue": 5.0
},
{
"name": "DeltaAlpha",
"shortDescription": "Angle discretisation.",
"type": "double",
"units": "Deg",
"min": 0.3,
"max": 90,
"decimalPlaces": 1,
"defaultValue": 5.0
},
{
"name": "MinLength",
"shortDescription": "The minimal transect length.",
"type": "double",
"units": "m",
"min": 0.3,
"decimalPlaces": 1,
"defaultValue": 5.0
}
]
[
{
"name": "TransectDistance",
"shortDescription": "The distance between transects.",
"type": "double",
"units": "m",
"min": 0.3,
"decimalPlaces": 1,
"defaultValue": 5.0
},
{
"name": "Alpha",
"shortDescription": "Transect angle.",
"type": "double",
"units": "Deg",
"min": 0,
"max": 180,
"decimalPlaces": 1,
"defaultValue": 0.0
},
{
"name": "MinLength",
"shortDescription": "The minimal transect length.",
"type": "double",
"units": "m",
"min": 0.3,
"decimalPlaces": 1,
"defaultValue": 5.0
}
]
......@@ -760,7 +760,17 @@ bool route(const FPolygon &area, const Transects &transects,
if (std::isinf(dist)) {
std::vector<std::size_t> route;
if (!dijkstraAlgorithm(n, i, j, route, dist, distLambda)) {
par.errorString = "Distance matrix calculation failed.";
std::stringstream ss;
ss << "Distance matrix calculation failed. connection graph: "
<< connectionGraph << std::endl;
ss << "area: " << bg::wkt(area) << std::endl;
ss << "transects:" << std::endl;
for (const auto &t : transects) {
ss << bg::wkt(t) << std::endl;
}
par.errorString = ss.str();
return false;
}
(void)route;
......
......@@ -230,74 +230,53 @@ void WimaController::planDataChangedHandler() {
_serviceArea = WimaServiceAreaData();
_corridor = WimaCorridorData();
_joinedArea = WimaJoinedAreaData();
_planDataValid = false;
emit visualItemsChanged();
emit missionItemsChanged();
emit waypointPathChanged();
_planDataValid = false;
// Extract areas.
auto planData = WimaBridge::instance()->planData();
// extract list with WimaAreas
QList<const WimaAreaData *> areaList = planData.areaList();
int areaCounter = 0;
const int numAreas = 4; // extract only numAreas Areas, if there are more
// they are invalid and ignored
for (int i = 0; i < areaList.size(); i++) {
const WimaAreaData *areaData = areaList[i];
if (areaData->type() ==
WimaServiceAreaData::typeString) { // is it a service area?
_serviceArea = *qobject_cast<const WimaServiceAreaData *>(areaData);
areaCounter++;
_areas.append(&_serviceArea);
continue;
}
if (areaData->type() ==
WimaMeasurementAreaData::typeString) { // is it a measurement area?
_measurementArea =
*qobject_cast<const WimaMeasurementAreaData *>(areaData);
areaCounter++;
_areas.append(&_measurementArea);
// Measurement Area.
if (planData.measurementArea().coordinateList().size() >= 3) {
_measurementArea = planData.measurementArea();
_areas.append(&_measurementArea);
continue;
}
// Service Area.
if (planData.serviceArea().coordinateList().size() >= 3) {
_serviceArea = planData.serviceArea();
_areas.append(&_serviceArea);
if (areaData->type() == WimaCorridorData::typeString) { // is it a corridor?
_corridor = *qobject_cast<const WimaCorridorData *>(areaData);
areaCounter++;
//_visualItems.append(&_corridor); // not needed
_WMSettings.setHomePosition(
QGeoCoordinate(_serviceArea.depot().latitude(),
_serviceArea.depot().longitude(), 0));
continue;
}
// Joined Area.
if (planData.joinedArea().coordinateList().size() >= 3) {
_joinedArea = planData.joinedArea();
_areas.append(&_joinedArea);
if (areaData->type() ==
WimaJoinedAreaData::typeString) { // is it a corridor?
_joinedArea = *qobject_cast<const WimaJoinedAreaData *>(areaData);
areaCounter++;
_areas.append(&_joinedArea);
_planDataValid = true;
continue;
// Corridor.
if (planData.corridor().coordinateList().size() >= 3) {
_corridor = planData.corridor();
}
}
}
if (areaCounter >= numAreas)
break;
}
if (areaCounter != numAreas) {
Q_ASSERT(false);
return;
if (_planDataValid) {
emit visualItemsChanged();
} else {
_areas.clear();
_measurementArea = WimaMeasurementAreaData();
_serviceArea = WimaServiceAreaData();
_corridor = WimaCorridorData();
_joinedArea = WimaJoinedAreaData();
}
emit visualItemsChanged();
_WMSettings.setHomePosition(QGeoCoordinate(
_serviceArea.depot().latitude(), _serviceArea.depot().longitude(), 0));
_planDataValid = true;
}
void WimaController::progressChangedHandler() {
......
......@@ -7,94 +7,116 @@ WimaPlanData::WimaPlanData(const WimaPlanData &other, QObject *parent)
*this = other;
}
/*!
* \fn WimaPlanData &WimaPlanData::operator=(const WimaPlanData &other)
*
* Copies the data area list of \a other to the calling \c WimaPlanData object.
* Returns a reference to the calling \c WimaPlanData object.
*/
WimaPlanData &WimaPlanData::operator=(const WimaPlanData &other) {
// copy wima areas
QList<const WimaAreaData *> areaList = other.areaList();
_areaList.clear();
for (int i = 0; i < areaList.size(); i++) {
const WimaAreaData *areaData = areaList[i];
// determine area type and append
if (areaData->type() == WimaJoinedAreaData::typeString) {
this->append(*qobject_cast<const WimaJoinedAreaData *>(areaData));
} else if (areaData->type() == WimaServiceAreaData::typeString) {
this->append(*qobject_cast<const WimaServiceAreaData *>(areaData));
} else if (areaData->type() == WimaMeasurementAreaData::typeString) {
this->append(*qobject_cast<const WimaMeasurementAreaData *>(areaData));
} else if (areaData->type() == WimaCorridorData::typeString) {
this->append(*qobject_cast<const WimaCorridorData *>(areaData));
}
}
this->set(other.measurementArea());
this->set(other.serviceArea());
this->set(other.joinedArea());
this->set(other.corridor());
return *this;
}
/*!
* \fn void WimaPlanData::append(const WimaAreaData &areaData)
*
* Adds a WimaAreaData item.
*/
void WimaPlanData::append(const WimaJoinedAreaData &areaData) {
_joinedArea = areaData;
void WimaPlanData::set(const WimaJoinedAreaData &areaData) {
if (_joinedArea != areaData) {
_joinedArea = areaData;
emit joinedAreaChanged();
}
}
void WimaPlanData::set(const WimaServiceAreaData &areaData) {
if (_serviceArea != areaData) {
_serviceArea = areaData;
emit serviceAreaChanged();
}
}
if (!_areaList.contains(&_joinedArea)) {
_areaList.append(&_joinedArea);
void WimaPlanData::set(const WimaCorridorData &areaData) {
if (_corridor != areaData) {
_corridor = areaData;
emit corridorChanged();
}
}
/*!
* \fn void WimaPlanData::append(const WimaServiceAreaData &areaData)
*
* Adds a WimaServiceAreaData item.
*/
void WimaPlanData::append(const WimaServiceAreaData &areaData) {
_serviceArea = areaData;
void WimaPlanData::set(const WimaMeasurementAreaData &areaData) {
if (_measurementArea != areaData) {
_measurementArea = areaData;
emit measurementAreaChanged();
if (!_areaList.contains(&_serviceArea)) {
_areaList.append(&_serviceArea);
if (_measurementArea.coordinateList().size() > 0) {
setOrigin(_measurementArea.coordinateList().first());
} else {
setOrigin(QGeoCoordinate());
}
}
}
/*!
* \fn void WimaPlanData::append(const WimaServiceAreaData &areaData)
*
* Adds a WimaCorridorData item.
*/
void WimaPlanData::append(const WimaCorridorData &areaData) {
_corridor = areaData;
void WimaPlanData::set(const WimaJoinedArea &areaData) {
if (_joinedArea != areaData) {
_joinedArea = areaData;
emit joinedAreaChanged();
}
}
if (!_areaList.contains(&_corridor)) {
_areaList.append(&_corridor);
void WimaPlanData::set(const WimaServiceArea &areaData) {
if (_serviceArea != areaData) {
_serviceArea = areaData;
emit serviceAreaChanged();
}
}
/*!
* \fn void WimaPlanData::append(const WimaServiceAreaData &areaData)
*
* Adds a WimaMeasurementAreaData item.
*/
void WimaPlanData::append(const WimaMeasurementAreaData &areaData) {
_measurementArea = areaData;
void WimaPlanData::set(const WimaCorridor &areaData) {
if (_corridor != areaData) {
_corridor = areaData;
emit corridorChanged();
}
}
if (!_areaList.contains(&_measurementArea)) {
_areaList.append(&_measurementArea);
void WimaPlanData::set(const WimaMeasurementArea &areaData) {
if (_measurementArea != areaData) {
_measurementArea = areaData;
emit measurementAreaChanged();
if (_measurementArea.coordinateList().size() > 0) {
setOrigin(_measurementArea.coordinateList().first());
} else {
setOrigin(QGeoCoordinate());
}
}
}
/*!
* \fn void WimaPlanData::append(const WimaServiceAreaData &areaData)
*
* Clears all stored objects
*/
void WimaPlanData::clear() { _areaList.clear(); }
void WimaPlanData::clear() { *this = WimaPlanData(); }
QGeoCoordinate WimaPlanData::origin() { return _origin; }
bool WimaPlanData::isValid() {
return _measurementArea.coordinateList().size() >= 3 &&
_serviceArea.coordinateList().size() >= 3 && _origin.isValid();
}
const WimaJoinedAreaData &WimaPlanData::joinedArea() const {
return this->_joinedArea;
}
const WimaServiceAreaData &WimaPlanData::serviceArea() const {
return this->_serviceArea;
}
const WimaCorridorData &WimaPlanData::corridor() const {
return this->_corridor;
}
const QList<const WimaAreaData *> &WimaPlanData::areaList() const {
return _areaList;
const WimaMeasurementAreaData &WimaPlanData::measurementArea() const {
return this->_measurementArea;
}
WimaJoinedAreaData &WimaPlanData::joinedArea() { return this->_joinedArea; }
WimaServiceAreaData &WimaPlanData::serviceArea() { return this->_serviceArea; }
WimaCorridorData &WimaPlanData::corridor() { return this->_corridor; }
WimaMeasurementAreaData &WimaPlanData::measurementArea() {
return this->_measurementArea;
}
bool WimaPlanData::operator==(const WimaPlanData &other) const {
......@@ -107,14 +129,9 @@ bool WimaPlanData::operator!=(const WimaPlanData &other) const {
return !(*this == other);
}
/*!
* \class WimaPlanData
* \brief Class storing data generated by the \c WimaPlaner class.
*
* This class is designed to store data generated by the \c WimaPlaner class and
* meant for data exchange between the \c WimaController and the \c WimaPlanner.
* It stores a QList of \c WimaAreaData objects, called area data list,
* containing the data of serveral \c WimaAreas generated by the \c WimaPlaner.
*
* \sa QList
*/
void WimaPlanData::setOrigin(const QGeoCoordinate &origin) {
if (this->_origin != origin) {
this->_origin = origin;
emit originChanged();
}
}
......@@ -18,33 +18,47 @@ public:
WimaPlanData &operator=(const WimaPlanData &other);
// Member Methodes
void append(const WimaJoinedAreaData &areaData);
void append(const WimaServiceAreaData &areaData);
void append(const WimaCorridorData &areaData);
void append(const WimaMeasurementAreaData &areaData);
void setTransects(const QList<QList<QGeoCoordinate>> &transects);
//!
//! \brief append
//! \param missionItems
//! \note Takes owenership of MissionItems*
void append(const QList<MissionItem *> &missionItems);
void set(const WimaJoinedAreaData &areaData);
void set(const WimaServiceAreaData &areaData);
void set(const WimaCorridorData &areaData);
void set(const WimaMeasurementAreaData &areaData);
void set(const WimaJoinedArea &areaData);
void set(const WimaServiceArea &areaData);
void set(const WimaCorridor &areaData);
void set(const WimaMeasurementArea &areaData);
void clear();
const QList<const WimaAreaData *> &areaList() const;
const QList<QList<QGeoCoordinate>> &transects() const;
const QList<MissionItem *> &missionItems() const;
const WimaJoinedAreaData &joinedArea() const;
const WimaServiceAreaData &serviceArea() const;
const WimaCorridorData &corridor() const;
const WimaMeasurementAreaData &measurementArea() const;
WimaJoinedAreaData &joinedArea();
WimaServiceAreaData &serviceArea();
WimaCorridorData &corridor();
WimaMeasurementAreaData &measurementArea();
QGeoCoordinate origin();
bool isValid();
bool operator==(const WimaPlanData &other) const;
bool operator!=(const WimaPlanData &other) const;
signals:
void areaListChanged();
void joinedAreaChanged();
void serviceAreaChanged();
void corridorChanged();
void measurementAreaChanged();
void originChanged();
private:
void setOrigin(const QGeoCoordinate &origin);
WimaJoinedAreaData _joinedArea;
WimaServiceAreaData _serviceArea;
WimaCorridorData _corridor;
WimaMeasurementAreaData _measurementArea;
QList<const WimaAreaData *> _areaList;
QGeoCoordinate _origin;
};
#include "WimaPlanData.h"
WimaPlanData::WimaPlanData(QObject *parent) : QObject(parent) {}
WimaPlanData::WimaPlanData(const WimaPlanData &other, QObject *parent)
: QObject(parent) {
*this = other;
}
/*!
* \fn WimaPlanData &WimaPlanData::operator=(const WimaPlanData &other)
*
* Copies the data area list of \a other to the calling \c WimaPlanData object.
* Returns a reference to the calling \c WimaPlanData object.
*/
WimaPlanData &WimaPlanData::operator=(const WimaPlanData &other) {
// copy wima areas
QList<const WimaAreaData *> areaList = other.areaList();
_areaList.clear();
for (int i = 0; i < areaList.size(); i++) {
const WimaAreaData *areaData = areaList[i];
// determine area type and append
if (areaData->type() == WimaJoinedAreaData::typeString) {
this->append(*qobject_cast<const WimaJoinedAreaData *>(areaData));
} else if (areaData->type() == WimaServiceAreaData::typeString) {
this->append(*qobject_cast<const WimaServiceAreaData *>(areaData));
} else if (areaData->type() == WimaMeasurementAreaData::typeString) {
this->append(*qobject_cast<const WimaMeasurementAreaData *>(areaData));
} else if (areaData->type() == WimaCorridorData::typeString) {
this->append(*qobject_cast<const WimaCorridorData *>(areaData));
}
}
// copy mission items
_missionItems = other.missionItems();
return *this;
}
/*!
* \fn void WimaPlanData::append(const WimaAreaData &areaData)
*
* Adds a WimaAreaData item.
*/
void WimaPlanData::append(const WimaJoinedAreaData &areaData) {
_joinedArea = areaData;
if (!_areaList.contains(&_joinedArea)) {
_areaList.append(&_joinedArea);
}
}
/*!
* \fn void WimaPlanData::append(const WimaServiceAreaData &areaData)
*
* Adds a WimaServiceAreaData item.
*/
void WimaPlanData::append(const WimaServiceAreaData &areaData) {
_serviceArea = areaData;
if (!_areaList.contains(&_serviceArea)) {
_areaList.append(&_serviceArea);
}
}
/*!
* \fn void WimaPlanData::append(const WimaServiceAreaData &areaData)
*
* Adds a WimaCorridorData item.
*/
void WimaPlanData::append(const WimaCorridorData &areaData) {
_corridor = areaData;
if (!_areaList.contains(&_corridor)) {
_areaList.append(&_corridor);
}
}
/*!
* \fn void WimaPlanData::append(const WimaServiceAreaData &areaData)
*
* Adds a WimaMeasurementAreaData item.
*/
void WimaPlanData::append(const WimaMeasurementAreaData &areaData) {
_measurementArea = areaData;
if (!_areaList.contains(&_measurementArea)) {
_areaList.append(&_measurementArea);
}
}
void WimaPlanData::append(const QList<MissionItem *> &missionItems) {
for (auto *item : missionItems) {
item->setParent(this);
_missionItems.append(item);
}
}
/*!
* \fn void WimaPlanData::append(const WimaServiceAreaData &areaData)
*
* Clears all stored objects
*/
void WimaPlanData::clear() {
_areaList.clear();
_missionItems.clear();
}
const QList<const WimaAreaData *> &WimaPlanData::areaList() const {
return _areaList;
}
const QList<MissionItem> &WimaPlanData::missionItems() const {
return _missionItems;
}
/*!
* \class WimaPlanData
* \brief Class storing data generated by the \c WimaPlaner class.
*
* This class is designed to store data generated by the \c WimaPlaner class and
* meant for data exchange between the \c WimaController and the \c WimaPlanner.
* It stores a QList of \c WimaAreaData objects, called area data list,
* containing the data of serveral \c WimaAreas generated by the \c WimaPlaner.
*
* \sa QList
*/
......@@ -38,9 +38,7 @@ const char *WimaPlaner::missionItemsName = "MissionItems";
WimaPlaner::WimaPlaner(QObject *parent)
: QObject(parent), _masterController(nullptr), _missionController(nullptr),
_currentAreaIndex(-1), _copyMAreaToSurvey(true), _copySAreaToSurvey(true),
_corridorChanged(true), _joinedArea(this), _arrivalPathLength(0),
_returnPathLength(0), _survey(nullptr), _surveyChanged(true),
_currentAreaIndex(-1), _joinedArea(this), _survey(nullptr),
_synchronized(false), _nemoInterface(this),
_stateMachine(new StateMachine), _areasMonitored(false),
_missionControllerMonitored(false), _progressLocked(false) {
......@@ -246,7 +244,7 @@ void WimaPlaner::removeAll() {
removeArea(0);
changesApplied = true;
}
// Reset Items.
_measurementArea = WimaMeasurementArea();
_joinedArea = WimaJoinedArea();
_serviceArea = WimaServiceArea();
......@@ -356,8 +354,6 @@ void WimaPlaner::_update() {
}
// establish connections
_survey->setRefPoint(_measurementArea.center());
_survey->setHidePolygon(true);
connect(_survey, &CircularSurvey::calculatingChanged, this,
&WimaPlaner::CSCalculatingChangedHandler);
connect(_survey, &CircularSurvey::missionItemReady, this,
......@@ -366,17 +362,7 @@ void WimaPlaner::_update() {
&WimaPlaner::CSDestroyedHandler);
}
// update survey area
disconnect(_survey, &CircularSurvey::calculatingChanged, this,
&WimaPlaner::CSCalculatingChangedHandler);
_survey->setMeasurementArea(this->_measurementArea);
_survey->setJoinedArea(this->_joinedArea);
_survey->setDepot(this->_serviceArea.depot());
connect(_survey, &CircularSurvey::calculatingChanged, this,
&WimaPlaner::CSCalculatingChangedHandler);
// Folloing statement just for completeness.
this->_stateMachine->updateState(EVENT::SURVEY_UPDATE_TRIGGERED);
(void)toPlanData(this->_survey->planData());
} break; // STATE::NEEDS_SURVEY_UPDATE
case STATE::WAITING_FOR_SURVEY_UPDATE: {
......@@ -444,7 +430,7 @@ void WimaPlaner::_update() {
.data());
return;
}
_arrivalPathLength = path.size() - 1;
for (int i = 1; i < path.count() - 1; i++) {
(void)_missionController->insertSimpleMissionItem(
path[i], missionItems->count() - 1);
......@@ -462,8 +448,7 @@ void WimaPlaner::_update() {
.data());
return;
}
_returnPathLength =
path.size() - 1; // -1: fist item is last measurement point
for (int i = 1; i < path.count() - 1; i++) {
(void)_missionController->insertSimpleMissionItem(
path[i], missionItems->count());
......@@ -772,7 +757,6 @@ bool WimaPlaner::loadFromFile(const QString &filename) {
for (int i = 0; i < missionItems->count(); i++) {
_survey = missionItems->value<CircularSurvey *>(i);
if (_survey != nullptr) {
_survey->setHidePolygon(true);
connect(_survey, &CircularSurvey::calculatingChanged, this,
&WimaPlaner::CSCalculatingChangedHandler);
connect(_survey, &CircularSurvey::missionItemReady, this,
......@@ -953,13 +937,11 @@ void WimaPlaner::setInteractive() {
* \sa WimaController, WimaPlanData
*/
bool WimaPlaner::toPlanData(WimaPlanData &planData) {
// store areas
planData.append(WimaMeasurementAreaData(_measurementArea));
planData.append(WimaServiceAreaData(_serviceArea));
planData.append(WimaCorridorData(_corridor));
planData.append(WimaJoinedAreaData(_joinedArea));
return true;
planData.set(_measurementArea);
planData.set(_serviceArea);
planData.set(_corridor);
planData.set(_joinedArea);
return planData.isValid();
}
#ifndef NDEBUG
......
......@@ -172,27 +172,13 @@ private:
int _currentAreaIndex;
QString _currentFile;
bool _joinedAreaValid;
WimaMeasurementArea _measurementArea;
bool _copyMAreaToSurvey;
WimaServiceArea _serviceArea;
bool _copySAreaToSurvey;
WimaCorridor _corridor;
bool _corridorChanged;
// contains all visible areas
QmlObjectListModel _visualItems;
// joined area fromed by _measurementArea, _serviceArea, _corridor
WimaJoinedArea _joinedArea;
// path from takeoff to first measurement point
unsigned long _arrivalPathLength;
// path from last measurement point to land
unsigned long _returnPathLength;
QmlObjectListModel _visualItems; // all areas
CircularSurvey *_survey;
bool _surveyChanged;
// sync stuff
bool _synchronized; // true if planData is synchronized with
// wimaController
#ifndef NDEBUG
QTimer _autoLoadTimer; // timer to auto load mission after some time, prevents
......@@ -206,4 +192,6 @@ private:
bool _areasMonitored;
bool _missionControllerMonitored;
bool _progressLocked;
bool _synchronized; // true if planData is synchronized with
// wimaController
};
import QtQuick 2.0
import QtQuick.Layouts 1.11
import QGroundControl.Controls 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.ScreenTools 1.0
GridLayout {
property var generator // CircularGenerator
property real _margin: ScreenTools.defaultFontPixelWidth / 2
columnSpacing: _margin
rowSpacing: _margin
columns: 2
QGCLabel { text: qsTr("Distance") }
FactTextField {
fact: generator.distance
Layout.fillWidth: true
}
QGCLabel { text: qsTr("Delta Alpha") }
FactTextField {
fact: generator.deltaAlpha
Layout.fillWidth: true
}
QGCLabel { text: qsTr("Min. Length") }
FactTextField {
fact: generator.minLength
Layout.fillWidth: true
}
QGCButton {
text: qsTr("Reset Ref.")
onClicked: generator.resetReference();
Layout.fillWidth: true
Layout.columnSpan: 2
}
}
import QtQuick 2.0
import Wima 1.0
import QGroundControl 1.0
Item {
id: _root
visible: true
// Expects the following properties:
property var map ///< Map control to place item in
property var qgcView ///< QGCView to use for popping dialogs
property var generator
property bool checked: false
property var _referenceComponent: undefined
signal clicked()
onVisibleChanged: {
if (visible){
_addRefPoint()
} else {
_destroyRefPoint()
}
}
Component.onCompleted: {
if (visible){
_addRefPoint()
}
}
Component.onDestruction: {
_destroyRefPoint()
}
function _addRefPoint(){
if (!_referenceComponent){
_referenceComponent = refPointComponent.createObject(_root)
map.addMapItem(_referenceComponent)
}
}
function _destroyRefPoint(){
if (_referenceComponent){
map.removeMapItem(_referenceComponent)
_referenceComponent.destroy()
_referenceComponent = undefined
}
}
// Ref. point (Base Station)
Component {
id: refPointComponent
DragCoordinate {
id: dragCoordinate
property var ref: _root.generator.reference
map: _root.map
qgcView: _root.qgcView
z: QGroundControl.zOrderMapItems
checked: _root.checked
coordinate: ref
onDragReleased: {
syncAndBind()
}
Component.onCompleted: {
syncAndBind()
}
onClicked: {
_root.clicked()
}
function syncAndBind(){
if (coordinate.latitude !== ref.latitude ||
coordinate.longitude !== ref.longitude){
_root.generator.reference = coordinate
}
coordinate = Qt.binding(function(){return _root.generator.reference})
}
}
}
}
......@@ -25,29 +25,24 @@ Rectangle {
//property real availableWidth ///< Width for control
//property var missionItem ///< Mission Item for editor
property real _margin: ScreenTools.defaultFontPixelWidth / 2
property real _fieldWidth: ScreenTools.defaultFontPixelWidth * 10.5
property var _vehicle: QGroundControl.multiVehicleManager.activeVehicle ? QGroundControl.multiVehicleManager.activeVehicle : QGroundControl.multiVehicleManager.offlineEditingVehicle
property real _cameraMinTriggerInterval: missionItem.cameraCalc.minTriggerInterval.rawValue
property real _margin: ScreenTools.defaultFontPixelWidth / 2
function polygonCaptureStarted() {
missionItem.clearPolygon()
}
property var _generator: missionItem.generator
property var _generatorEditor: undefined
function polygonCaptureFinished(coordinates) {
for (var i=0; i<coordinates.length; i++) {
missionItem.addPolygonCoordinate(coordinates[i])
}
}
QGCPalette { id: qgcPal; colorGroupEnabled: true }
function polygonAdjustVertex(vertexIndex, vertexCoordinate) {
missionItem.adjustPolygonCoordinate(vertexIndex, vertexCoordinate)
Component.onCompleted: {
_addGeneratorEditor()
}
Component.onDestruction: {
_destroyGeneratorEditor()
}
function polygonAdjustStarted() { }
function polygonAdjustFinished() { }
QGCPalette { id: qgcPal; colorGroupEnabled: true }
on_GeneratorChanged: {
_destroyGeneratorEditor()
_addGeneratorEditor()
}
Column {
id: editorColumn
......@@ -95,31 +90,24 @@ Rectangle {
}
QGCLabel {
text: qsTr("Type")
text: qsTr("Generator Type")
Layout.columnSpan: 2
}
Repeater{
id: typeRepeater
property var typeFact: missionItem.type
property int type: typeFact.value
property var names: ["Circular", "Linear"]
QGCComboBox {
property var names: missionItem.generatorNameList
property int length: names.length
model: missionItem.typeCount
QGCRadioButton {
checked: index === typeRepeater.type
text: qsTr(typeRepeater.names[index])
anchors.margins: ScreenTools.defaultFontPixelWidth
currentIndex: missionItem.generatorIndex
Layout.columnSpan: 2
model: missionItem.generatorNameList
onCheckedChanged: {
if (checked){
missionItem.type.value = index
}
checked = Qt.binding(function(){ return index === typeRepeater.type})
}
onActivated: {
missionItem.switchToGenerator(index)
}
}
QGCLabel {
text: qsTr("Variant")
Layout.columnSpan: 2
......@@ -156,73 +144,15 @@ Rectangle {
}
}
// Generator Editor
SectionHeader {
id: transectsHeader
text: qsTr("Transects")
text: qsTr("Generator")
}
GridLayout {
anchors.left: parent.left
anchors.right: parent.right
columnSpacing: _margin
rowSpacing: _margin
columns: 2
visible: transectsHeader.checked
QGCLabel { text: qsTr("Distance") }
FactTextField {
fact: missionItem.transectDistance
Layout.fillWidth: true
}
/*QGCSlider {
id: rSlider
minimumValue: 0.3
maximumValue: 20
stepSize: 0.1
tickmarksEnabled: false
Layout.fillWidth: true
Layout.columnSpan: 2
Layout.preferredHeight: ScreenTools.defaultFontPixelHeight * 1.5
onValueChanged: missionItem.deltaR.value = value
Component.onCompleted: value = missionItem.deltaR.defaultValue
updateValueWhileDragging: true
}*/
QGCLabel { text: qsTr("Alpha") }
FactTextField {
fact: missionItem.alpha
Layout.fillWidth: true
}
QGCLabel { text: qsTr("Min. Length") }
FactTextField {
fact: missionItem.minLength
Layout.fillWidth: true
}
}
GridLayout {
anchors.left: parent.left
anchors.right: parent.right
columnSpacing: _margin
rowSpacing: _margin
columns: 2
visible: transectsHeader.checked
QGCButton {
text: qsTr("Reverse")
onClicked: missionItem.reverse();
Layout.fillWidth: true
}
QGCButton {
text: qsTr("Reset Ref.")
onClicked: missionItem.resetReference();
Layout.fillWidth: true
}
Column{
id:generatorEditorParent
visible: transectsHeader.checked
}
Column{
......@@ -239,7 +169,7 @@ Rectangle {
onCalculatingChanged: {
if(!calculating){
// defer hideing
// defer hiding
timer.restart()
}
}
......@@ -253,4 +183,27 @@ Rectangle {
}
}
} // Column
function _addGeneratorEditor(){
if (_generator.editorQml && !_generatorEditor) {
var component = Qt.createComponent(_generator.editorQml)
if (component.status === Component.Error) {
console.log("Error loading Qml: ",
_generator.editorQml, component.errorString())
} else {
_generatorEditor =
component.createObject(
generatorEditorParent, {
"generator": _root._generator,
})
}
}
}
function _destroyGeneratorEditor(){
if (_generatorEditor){
_generatorEditor.destroy()
_generatorEditor = undefined
}
}
} // Rectangle
......@@ -26,146 +26,34 @@ Item {
property var qgcView ///< QGCView to use for popping dialogs
property var _missionItem: object
property var _mapPolygon: object.surveyAreaPolygon
property var _transectsComponent
property var _entryCoordinate
property var _exitCoordinate
property var _refPoint
property bool showRefPoint: _missionItem.type.value === 0 // type == Circular
property var _generator: _missionItem.generator
signal clicked(int sequenceNumber)
function _addTransectsComponent(){
if (!_transectsComponent){
_transectsComponent = visualTransectsComponent.createObject(_root)
map.addMapItem(_transectsComponent)
}
}
function _addExitCoordinate(){
if (!_exitCoordinate){
_exitCoordinate = exitPointComponent.createObject(_root)
map.addMapItem(_exitCoordinate)
}
}
function _addEntryCoordinate(){
if (!_entryCoordinate){
_entryCoordinate = entryPointComponent.createObject(_root)
map.addMapItem(_entryCoordinate)
}
}
function _addRefPoint(){
if (!_refPoint){
_refPoint = refPointComponent.createObject(_root)
map.addMapItem(_refPoint)
}
}
function _destroyEntryCoordinate(){
if (_entryCoordinate){
map.removeMapItem(_entryCoordinate)
_entryCoordinate.destroy()
_entryCoordinate = undefined
}
}
function _destroyExitCoordinate(){
if (_exitCoordinate){
map.removeMapItem(_exitCoordinate)
_exitCoordinate.destroy()
_exitCoordinate = undefined
}
}
function _destroyRefPoint(){
if (_refPoint){
map.removeMapItem(_refPoint)
_refPoint.destroy()
_refPoint = undefined
}
}
function _destroyTransectsComponent(){
if (_transectsComponent){
map.removeMapItem(_transectsComponent)
_transectsComponent.destroy()
_transectsComponent = undefined
}
}
property var _transectsComponent: undefined
property var _entryCoordinate: undefined
property var _exitCoordinate: undefined
property var _generatorVisuals: undefined
/// Add an initial 4 sided polygon if there is none
function _addInitialPolygon() {
if (_mapPolygon.count < 3) {
// Initial polygon is inset to take 2/3rds space
var rect = Qt.rect(map.centerViewport.x, map.centerViewport.y, map.centerViewport.width, map.centerViewport.height)
rect.x += (rect.width * 0.25) / 2
rect.y += (rect.height * 0.25) / 2
rect.width *= 0.75
rect.height *= 0.75
var centerCoord = map.toCoordinate(Qt.point(rect.x + (rect.width / 2), rect.y + (rect.height / 2)), false /* clipToViewPort */)
var topLeftCoord = map.toCoordinate(Qt.point(rect.x, rect.y), false /* clipToViewPort */)
var topRightCoord = map.toCoordinate(Qt.point(rect.x + rect.width, rect.y), false /* clipToViewPort */)
var bottomLeftCoord = map.toCoordinate(Qt.point(rect.x, rect.y + rect.height), false /* clipToViewPort */)
var bottomRightCoord = map.toCoordinate(Qt.point(rect.x + rect.width, rect.y + rect.height), false /* clipToViewPort */)
// Initial polygon has max width and height of 3000 meters
var halfWidthMeters = Math.min(topLeftCoord.distanceTo(topRightCoord), 3000) / 2
var halfHeightMeters = Math.min(topLeftCoord.distanceTo(bottomLeftCoord), 3000) / 2
topLeftCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, -90).atDistanceAndAzimuth(halfHeightMeters, 0)
topRightCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, 90).atDistanceAndAzimuth(halfHeightMeters, 0)
bottomLeftCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, -90).atDistanceAndAzimuth(halfHeightMeters, 180)
bottomRightCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, 90).atDistanceAndAzimuth(halfHeightMeters, 180)
_mapPolygon.appendVertex(topLeftCoord)
_mapPolygon.appendVertex(topRightCoord)
_mapPolygon.appendVertex(bottomRightCoord)
_mapPolygon.appendVertex(bottomLeftCoord)
}
}
property bool _isCurrentItem: _missionItem.isCurrentItem
signal clicked(int sequenceNumber)
Component.onCompleted: {
if ( _mapPolygon.count === 0 ) {
_addInitialPolygon()
_missionItem.resetReference();
}
_addEntryCoordinate()
_addExitCoordinate()
if (showRefPoint){
_addRefPoint()
}
_addTransectsComponent()
_addGeneratorVisuals()
}
Component.onDestruction: {
_destroyEntryCoordinate()
_destroyExitCoordinate()
_destroyRefPoint()
_destroyTransectsComponent()
_destroyGeneratorVisuals()
}
onShowRefPointChanged: {
if (showRefPoint){
_addRefPoint()
} else {
_destroyRefPoint()
}
}
WimaMapPolygonVisuals {
id: mapPolygonVisuals
qgcView: _root.qgcView
mapControl: map
mapPolygon: _mapPolygon
interactive: _missionItem.isCurrentItem
borderWidth: 1
borderColor: "black"
interiorColor: "green"
interiorOpacity: 0.5
visible: !_missionItem.hidePolygon
on_GeneratorChanged: {
_destroyGeneratorVisuals()
_addGeneratorVisuals()
}
// Transect lines
......@@ -220,25 +108,81 @@ Item {
}
}
// Ref. point (Base Station)
Component {
id: refPointComponent
// Generator visuals
function _addGeneratorVisuals(){
if (_generator.mapVisualQml && !_generatorVisuals) {
var component = Qt.createComponent(_generator.mapVisualQml)
if (component.status === Component.Error) {
console.log("Error loading Qml: ",
_generator.mapVisualQml, component.errorString())
} else {
_generatorVisuals =
component.createObject(_root, {
"map": _root.map,
"qgcView": _root.qgcView ,
"generator": _root._generator,
"checked": Qt.binding(
function(){
return _root._isCurrentItem
})
})
_generatorVisuals.clicked.connect(
function(){_root.clicked(_missionItem.sequenceNumber)})
}
}
}
DragCoordinate {
map: _root.map
qgcView: _root.qgcView
z: QGroundControl.zOrderMapItems
checked: _missionItem.isCurrentItem
coordinate: _missionItem.refPoint
function _destroyGeneratorVisuals(){
if(_generatorVisuals){
_generatorVisuals.destroy()
_generatorVisuals = undefined
}
}
onClicked: {
_root.clicked(_missionItem.sequenceNumber)
}
function _addTransectsComponent(){
if (!_transectsComponent){
_transectsComponent = visualTransectsComponent.createObject(_root)
map.addMapItem(_transectsComponent)
}
}
onDragReleased: {
_missionItem.refPoint = coordinate
coordinate = Qt.binding(function (){return _missionItem.refPoint})
}
function _addExitCoordinate(){
if (!_exitCoordinate){
_exitCoordinate = exitPointComponent.createObject(_root)
map.addMapItem(_exitCoordinate)
}
}
function _addEntryCoordinate(){
if (!_entryCoordinate){
_entryCoordinate = entryPointComponent.createObject(_root)
map.addMapItem(_entryCoordinate)
}
}
function _destroyEntryCoordinate(){
if (_entryCoordinate){
map.removeMapItem(_entryCoordinate)
_entryCoordinate.destroy()
_entryCoordinate = undefined
}
}
function _destroyExitCoordinate(){
if (_exitCoordinate){
map.removeMapItem(_exitCoordinate)
_exitCoordinate.destroy()
_exitCoordinate = undefined
}
}
function _destroyTransectsComponent(){
if (_transectsComponent){
map.removeMapItem(_transectsComponent)
_transectsComponent.destroy()
_transectsComponent = undefined
}
}
}
import QtQuick 2.0
import QtQuick.Layouts 1.11
import QGroundControl.Controls 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.ScreenTools 1.0
GridLayout {
property var generator ///< LinearGenerator
property real _margin: ScreenTools.defaultFontPixelWidth / 2
columnSpacing: _margin
rowSpacing: _margin
columns: 2
QGCLabel { text: qsTr("Distance") }
FactTextField {
fact: generator.distance
Layout.fillWidth: true
}
QGCLabel {
text: qsTr("Alpha: ")
Layout.fillWidth: true
}
FactTextField {
fact: generator.alpha
Layout.fillWidth: true
}
QGCSlider {
id: rSlider
minimumValue: 0
maximumValue: 180
stepSize: 0.1
tickmarksEnabled: false
Layout.fillWidth: true
Layout.columnSpan: 2
Layout.preferredHeight: ScreenTools.defaultFontPixelHeight * 1.5
onValueChanged: {
generator.alpha.value = value
value = Qt.binding(function(){return generator.alpha.value})
}
Component.onCompleted: value = generator.alpha.value
updateValueWhileDragging: true
}
QGCLabel { text: qsTr("Min. Length") }
FactTextField {
fact: generator.minLength
Layout.fillWidth: true
}
}
WimaMapVisual 1.0 WimaMapVisual.qml
WimaMeasurementAreaMapVisual 1.0 WimaMeasurementAreaMapVisual.qml
WimaJoinedAreaMapVisual 1.0 WimaJoinedAreaMapVisual.qml
WimaMeasurementAreaEditor 1.0 WimaMeasurementAreaEditor.qml
WimaServiceAreaMapVisual 1.0 WimaServiceAreaMapVisual.qml
WimaAreaMapVisual 1.0 WimaAreaMapVisual.qml
WimaServiceAreaEditor 1.0 WimaServiceAreaEditor.qml
WimaCorridorMapVisual 1.0 WimaCorridorMapVisual.qml
WimaItemEditor 1.0 WimaItemEditor.qml
WimaMapPolygonVisuals 1.0 WimaMapPolygonVisuals.qml
WimaMapPolylineVisuals 1.0 WimaMapPolylineVisuals.qml
CircularSurveyMapVisual 1.0 CircularSurveyMapVisual.qml
DragCoordinate 1.0 DragCoordinate.qml
CoordinateIndicator 1.0 CoordinateIndicator.qml
CoordinateIndicatorDrag 1.0 CoordinateIndicatorDrag.qml
ProgressIndicator 1.0 ProgressIndicator.qml
WimaToolBar 1.0 WimaToolBar.qml
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment