Commit 912e993b authored by Valentin Platzgummer's avatar Valentin Platzgummer

wima planer edited

parent 6fd60bb5
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"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.76779208273835,
16.53052025186404,
5
],
"type": "SimpleItem"
},
{
"DeltaAlpha": 3,
"DeltaR": 10,
"ReferencePointAlt": 0,
"ReferencePointLat": 47.77087170283815,
"ReferencePointLong": 16.53120355954269,
"TransectMinLength": 1,
"TransectStyleComplexItem": {
"CameraCalc": {
"AdjustedFootprintFrontal": 25,
"AdjustedFootprintSide": 25,
"CameraName": "Manual (no camera specs)",
"DistanceToSurface": 15,
"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.76787911538782,
16.530373143053875,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 3,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76787112287341,
16.530432237754336,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 4,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76785187605887,
16.530627484718586,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 5,
"frame": 3,
"params": [
0,
0,
0,
null,
47.767925215533104,
16.530875349994385,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 6,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76793716779096,
16.530684010368297,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 7,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76795974224912,
16.53045501678237,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 8,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76797500239839,
16.530342187419713,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 9,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76807772170158,
16.530260710744177,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 10,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76804836071953,
16.53047779455375,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 11,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76802647332397,
16.530699820729467,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 12,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768012516370526,
16.530923248770208,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 13,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76800652762542,
16.531147458440163,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 14,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76800655280982,
16.53115024528538,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 15,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76809756799416,
16.531107700703668,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 16,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76810225985858,
16.5309320464106,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 17,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76811577885341,
16.530715631144773,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 18,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768136979184064,
16.530500573736578,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 19,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76815245701991,
16.530386140459395,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 20,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76822214416695,
16.53055838419157,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 21,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76820508527868,
16.5307314416142,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 22,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76819200424394,
16.53094084541531,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 23,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768188800809625,
16.531060776248225,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 24,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76828003270505,
16.53101385296271,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 25,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76828174772784,
16.53094964311624,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 26,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76829404005899,
16.530752861881787,
15
],
"type": "SimpleItem"
}
],
"Refly90Degrees": false,
"TurnAroundDistance": 10,
"VisualTransectPoints": [
[
47.76787911538782,
16.530373143053875
],
[
47.76787112287341,
16.530432237754336
],
[
47.76785187605887,
16.530627484718586
],
[
47.767925215533104,
16.530875349994385
],
[
47.76793716779096,
16.530684010368297
],
[
47.76795974224912,
16.53045501678237
],
[
47.76797500239839,
16.530342187419713
],
[
47.76807772170158,
16.530260710744177
],
[
47.76804836071953,
16.53047779455375
],
[
47.76802647332397,
16.530699820729467
],
[
47.768012516370526,
16.530923248770208
],
[
47.76800652762542,
16.531147458440163
],
[
47.76800655280982,
16.53115024528538
],
[
47.76809756799416,
16.531107700703668
],
[
47.76810225985858,
16.5309320464106
],
[
47.76811577885341,
16.530715631144773
],
[
47.768136979184064,
16.530500573736578
],
[
47.76815245701991,
16.530386140459395
],
[
47.76822214416695,
16.53055838419157
],
[
47.76820508527868,
16.5307314416142
],
[
47.76819200424394,
16.53094084541531
],
[
47.768188800809625,
16.531060776248225
],
[
47.76828003270505,
16.53101385296271
],
[
47.76828174772784,
16.53094964311624
],
[
47.76829404005899,
16.530752861881787
]
],
"version": 1
},
"complexItemType": "CircularSurvey",
"polygon": [
[
47.76809580679245,
16.530246122817612
],
[
47.768239336013224,
16.53060087654427
],
[
47.7683711160486,
16.530967006195464
],
[
47.7680076482754,
16.531153949077463
],
[
47.7677855557718,
16.530403347547246
],
[
47.76797785674764,
16.530341265362296
]
],
"type": "ComplexItem",
"version": 1
}
],
"plannedHomePosition": [
47.76779208273835,
16.530520251864044,
178
],
"vehicleType": 2,
"version": 2
},
"rallyPoints": {
"points": [
],
"version": 2
},
"version": 1
}
{
"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.76779208273835,
16.53052025186404,
5
],
"type": "SimpleItem"
},
{
"DeltaAlpha": 3,
"DeltaR": 10,
"ReferencePointAlt": 0,
"ReferencePointLat": 47.77087170283815,
"ReferencePointLong": 16.53120355954269,
"TransectMinLength": 1,
"TransectStyleComplexItem": {
"CameraCalc": {
"AdjustedFootprintFrontal": 25,
"AdjustedFootprintSide": 25,
"CameraName": "Manual (no camera specs)",
"DistanceToSurface": 15,
"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.76787911538782,
16.530373143053875,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 3,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76787112287341,
16.530432237754336,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 4,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76785187605887,
16.530627484718586,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 5,
"frame": 3,
"params": [
0,
0,
0,
null,
47.767925215533104,
16.530875349994385,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 6,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76793716779096,
16.530684010368297,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 7,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76795974224912,
16.53045501678237,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 8,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76797500239839,
16.530342187419713,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 9,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76807772170158,
16.530260710744177,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 10,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76804836071953,
16.53047779455375,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 11,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76802647332397,
16.530699820729467,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 12,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768012516370526,
16.530923248770208,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 13,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76800652762542,
16.531147458440163,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 14,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76800655280982,
16.53115024528538,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 15,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76809756799416,
16.531107700703668,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 16,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76810225985858,
16.5309320464106,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 17,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76811577885341,
16.530715631144773,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 18,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768136979184064,
16.530500573736578,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 19,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76815245701991,
16.530386140459395,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 20,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76822214416695,
16.53055838419157,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 21,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76820508527868,
16.5307314416142,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 22,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76819200424394,
16.53094084541531,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 23,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768188800809625,
16.531060776248225,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 24,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76828003270505,
16.53101385296271,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 25,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76828174772784,
16.53094964311624,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 26,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76829404005899,
16.530752861881787,
15
],
"type": "SimpleItem"
}
],
"Refly90Degrees": false,
"TurnAroundDistance": 10,
"VisualTransectPoints": [
[
47.76787911538782,
16.530373143053875
],
[
47.76787112287341,
16.530432237754336
],
[
47.76785187605887,
16.530627484718586
],
[
47.767925215533104,
16.530875349994385
],
[
47.76793716779096,
16.530684010368297
],
[
47.76795974224912,
16.53045501678237
],
[
47.76797500239839,
16.530342187419713
],
[
47.76807772170158,
16.530260710744177
],
[
47.76804836071953,
16.53047779455375
],
[
47.76802647332397,
16.530699820729467
],
[
47.768012516370526,
16.530923248770208
],
[
47.76800652762542,
16.531147458440163
],
[
47.76800655280982,
16.53115024528538
],
[
47.76809756799416,
16.531107700703668
],
[
47.76810225985858,
16.5309320464106
],
[
47.76811577885341,
16.530715631144773
],
[
47.768136979184064,
16.530500573736578
],
[
47.76815245701991,
16.530386140459395
],
[
47.76822214416695,
16.53055838419157
],
[
47.76820508527868,
16.5307314416142
],
[
47.76819200424394,
16.53094084541531
],
[
47.768188800809625,
16.531060776248225
],
[
47.76828003270505,
16.53101385296271
],
[
47.76828174772784,
16.53094964311624
],
[
47.76829404005899,
16.530752861881787
]
],
"version": 1
},
"complexItemType": "CircularSurvey",
"polygon": [
[
47.76809580679245,
16.530246122817612
],
[
47.768239336013224,
16.53060087654427
],
[
47.7683711160486,
16.530967006195464
],
[
47.7680076482754,
16.531153949077463
],
[
47.7677855557718,
16.530403347547246
],
[
47.76797785674764,
16.530341265362296
]
],
"type": "ComplexItem",
"version": 1
}
],
"plannedHomePosition": [
47.76779208273835,
16.530520251864044,
178
],
"vehicleType": 2,
"version": 2
},
"rallyPoints": {
"points": [
],
"version": 2
},
"version": 1
}
{
"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.76779208273835,
16.53052025186404,
5
],
"type": "SimpleItem"
},
{
"DeltaAlpha": 3,
"DeltaR": 10,
"ReferencePointAlt": 0,
"ReferencePointLat": 47.77087170283815,
"ReferencePointLong": 16.53120355954269,
"TransectMinLength": 1,
"TransectStyleComplexItem": {
"CameraCalc": {
"AdjustedFootprintFrontal": 25,
"AdjustedFootprintSide": 25,
"CameraName": "Manual (no camera specs)",
"DistanceToSurface": 15,
"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.76787911538782,
16.530373143053875,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 3,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76787112287341,
16.530432237754336,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 4,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76785187605887,
16.530627484718586,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 5,
"frame": 3,
"params": [
0,
0,
0,
null,
47.767925215533104,
16.530875349994385,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 6,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76793716779096,
16.530684010368297,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 7,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76795974224912,
16.53045501678237,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 8,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76797500239839,
16.530342187419713,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 9,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76807772170158,
16.530260710744177,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 10,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76804836071953,
16.53047779455375,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 11,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76802647332397,
16.530699820729467,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 12,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768012516370526,
16.530923248770208,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 13,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76800652762542,
16.531147458440163,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 14,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76800655280982,
16.53115024528538,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 15,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76809756799416,
16.531107700703668,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 16,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76810225985858,
16.5309320464106,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 17,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76811577885341,
16.530715631144773,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 18,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768136979184064,
16.530500573736578,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 19,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76815245701991,
16.530386140459395,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 20,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76822214416695,
16.53055838419157,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 21,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76820508527868,
16.5307314416142,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 22,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76819200424394,
16.53094084541531,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 23,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768188800809625,
16.531060776248225,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 24,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76828003270505,
16.53101385296271,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 25,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76828174772784,
16.53094964311624,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 26,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76829404005899,
16.530752861881787,
15
],
"type": "SimpleItem"
}
],
"Refly90Degrees": false,
"TurnAroundDistance": 10,
"VisualTransectPoints": [
[
47.76787911538782,
16.530373143053875
],
[
47.76787112287341,
16.530432237754336
],
[
47.76785187605887,
16.530627484718586
],
[
47.767925215533104,
16.530875349994385
],
[
47.76793716779096,
16.530684010368297
],
[
47.76795974224912,
16.53045501678237
],
[
47.76797500239839,
16.530342187419713
],
[
47.76807772170158,
16.530260710744177
],
[
47.76804836071953,
16.53047779455375
],
[
47.76802647332397,
16.530699820729467
],
[
47.768012516370526,
16.530923248770208
],
[
47.76800652762542,
16.531147458440163
],
[
47.76800655280982,
16.53115024528538
],
[
47.76809756799416,
16.531107700703668
],
[
47.76810225985858,
16.5309320464106
],
[
47.76811577885341,
16.530715631144773
],
[
47.768136979184064,
16.530500573736578
],
[
47.76815245701991,
16.530386140459395
],
[
47.76822214416695,
16.53055838419157
],
[
47.76820508527868,
16.5307314416142
],
[
47.76819200424394,
16.53094084541531
],
[
47.768188800809625,
16.531060776248225
],
[
47.76828003270505,
16.53101385296271
],
[
47.76828174772784,
16.53094964311624
],
[
47.76829404005899,
16.530752861881787
]
],
"version": 1
},
"complexItemType": "CircularSurvey",
"polygon": [
[
47.76809580679245,
16.530246122817612
],
[
47.768239336013224,
16.53060087654427
],
[
47.7683711160486,
16.530967006195464
],
[
47.7680076482754,
16.531153949077463
],
[
47.7677855557718,
16.530403347547246
],
[
47.76797785674764,
16.530341265362296
]
],
"type": "ComplexItem",
"version": 1
}
],
"plannedHomePosition": [
47.76779208273835,
16.530520251864044,
178
],
"vehicleType": 2,
"version": 2
},
"rallyPoints": {
"points": [
],
"version": 2
},
"version": 1
}
{
"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.76779208273835,
16.53052025186404,
5
],
"type": "SimpleItem"
},
{
"DeltaAlpha": 3,
"DeltaR": 10,
"ReferencePointAlt": 0,
"ReferencePointLat": 47.77087170283815,
"ReferencePointLong": 16.53120355954269,
"TransectMinLength": 1,
"TransectStyleComplexItem": {
"CameraCalc": {
"AdjustedFootprintFrontal": 25,
"AdjustedFootprintSide": 25,
"CameraName": "Manual (no camera specs)",
"DistanceToSurface": 15,
"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.76787911538782,
16.530373143053875,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 3,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76787112287341,
16.530432237754336,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 4,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76785187605887,
16.530627484718586,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 5,
"frame": 3,
"params": [
0,
0,
0,
null,
47.767925215533104,
16.530875349994385,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 6,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76793716779096,
16.530684010368297,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 7,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76795974224912,
16.53045501678237,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 8,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76797500239839,
16.530342187419713,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 9,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76807772170158,
16.530260710744177,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 10,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76804836071953,
16.53047779455375,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 11,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76802647332397,
16.530699820729467,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 12,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768012516370526,
16.530923248770208,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 13,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76800652762542,
16.531147458440163,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 14,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76800655280982,
16.53115024528538,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 15,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76809756799416,
16.531107700703668,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 16,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76810225985858,
16.5309320464106,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 17,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76811577885341,
16.530715631144773,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 18,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768136979184064,
16.530500573736578,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 19,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76815245701991,
16.530386140459395,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 20,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76822214416695,
16.53055838419157,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 21,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76820508527868,
16.5307314416142,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 22,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76819200424394,
16.53094084541531,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 23,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768188800809625,
16.531060776248225,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 24,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76828003270505,
16.53101385296271,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 25,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76828174772784,
16.53094964311624,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 26,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76829404005899,
16.530752861881787,
15
],
"type": "SimpleItem"
}
],
"Refly90Degrees": false,
"TurnAroundDistance": 10,
"VisualTransectPoints": [
[
47.76787911538782,
16.530373143053875
],
[
47.76787112287341,
16.530432237754336
],
[
47.76785187605887,
16.530627484718586
],
[
47.767925215533104,
16.530875349994385
],
[
47.76793716779096,
16.530684010368297
],
[
47.76795974224912,
16.53045501678237
],
[
47.76797500239839,
16.530342187419713
],
[
47.76807772170158,
16.530260710744177
],
[
47.76804836071953,
16.53047779455375
],
[
47.76802647332397,
16.530699820729467
],
[
47.768012516370526,
16.530923248770208
],
[
47.76800652762542,
16.531147458440163
],
[
47.76800655280982,
16.53115024528538
],
[
47.76809756799416,
16.531107700703668
],
[
47.76810225985858,
16.5309320464106
],
[
47.76811577885341,
16.530715631144773
],
[
47.768136979184064,
16.530500573736578
],
[
47.76815245701991,
16.530386140459395
],
[
47.76822214416695,
16.53055838419157
],
[
47.76820508527868,
16.5307314416142
],
[
47.76819200424394,
16.53094084541531
],
[
47.768188800809625,
16.531060776248225
],
[
47.76828003270505,
16.53101385296271
],
[
47.76828174772784,
16.53094964311624
],
[
47.76829404005899,
16.530752861881787
]
],
"version": 1
},
"complexItemType": "CircularSurvey",
"polygon": [
[
47.76809580679245,
16.530246122817612
],
[
47.768239336013224,
16.53060087654427
],
[
47.7683711160486,
16.530967006195464
],
[
47.7680076482754,
16.531153949077463
],
[
47.7677855557718,
16.530403347547246
],
[
47.76797785674764,
16.530341265362296
]
],
"type": "ComplexItem",
"version": 1
}
],
"plannedHomePosition": [
47.76779208273835,
16.530520251864044,
178
],
"vehicleType": 2,
"version": 2
},
"rallyPoints": {
"points": [
],
"version": 2
},
"version": 1
}
......@@ -15,7 +15,8 @@ template <> ClipperLib::cInt get<1>(ClipperLib::IntPoint &p) { return p.Y; }
CSWorker::CSWorker(QObject *parent)
: QThread(parent), _deltaR(2 * bu::si::meter),
_deltaAlpha(3 * bu::degree::degree), _minLength(10 * bu::si::meter),
_calculating(false), _stop(false), _restart(false) {}
_useDepotSafeArea(false), _calculating(false), _stop(false),
_restart(false) {}
CSWorker::~CSWorker() {
this->_stop = true;
......@@ -34,11 +35,46 @@ void CSWorker::update(const QList<QGeoCoordinate> &polygon,
// Sample input.
Lock lk(this->_mutex);
this->_polygon = polygon;
for (auto &v : this->_polygon) {
v.setAltitude(0);
}
this->_origin = origin;
this->_origin.setAltitude(0);
this->_deltaR = deltaR;
this->_deltaAlpha = deltaAlpha;
this->_minLength = minLength;
lk.unlock();
this->_useDepotSafeArea = false;
if (!this->isRunning()) {
this->start();
} else {
Lock lk(this->_mutex);
this->_restart = true;
this->_cv.notify_one();
}
}
void CSWorker::update(const QGeoCoordinate &depot,
const QList<QGeoCoordinate> &safeArea,
const QList<QGeoCoordinate> &polygon,
const QGeoCoordinate &origin, snake::Length deltaR,
snake::Length minLength, snake::Angle deltaAlpha) {
// Sample input.
Lock lk(this->_mutex);
this->_depot = depot;
this->_safeArea = safeArea;
this->_polygon = polygon;
for (auto &v : this->_polygon) {
v.setAltitude(0);
}
this->_origin = origin;
this->_origin.setAltitude(0);
this->_deltaR = deltaR;
this->_deltaAlpha = deltaAlpha;
this->_minLength = minLength;
lk.unlock();
this->_useDepotSafeArea = true;
if (!this->isRunning()) {
this->start();
......@@ -53,7 +89,15 @@ void CSWorker::run() {
qWarning() << "CSWorker::run(): thread start.";
while (!this->_stop) {
// Copy input.
QGeoCoordinate depot;
QList<QGeoCoordinate> safeArea;
Lock lk(this->_mutex);
if (this->_useDepotSafeArea) {
depot = this->_depot;
safeArea = this->_safeArea;
} else {
safeArea = this->_polygon;
}
const auto polygon = this->_polygon;
const auto origin = this->_origin;
const auto deltaR = this->_deltaR;
......@@ -74,11 +118,16 @@ void CSWorker::run() {
emit calculatingChanged();
// Convert geo polygon to ENU polygon.
snake::BoostPolygon polygonENU;
snake::BoostPolygon safeAreaENU;
snake::BoostPoint originENU{0, 0};
snake::BoostPoint depotENU;
snake::areaToEnu(origin, polygon, polygonENU);
snake::areaToEnu(origin, safeArea, safeAreaENU);
snake::toENU(origin, depot, depotENU);
std::string error;
// Check validity.
if (!bg::is_valid(polygonENU, error)) {
if (!bg::is_valid(polygonENU, error) ||
!bg::is_valid(safeAreaENU, error)) {
#ifdef DEBUG_CIRCULAR_SURVEY
qWarning() << "CSWorker::run(): "
"invalid polygon.";
......@@ -159,7 +208,9 @@ void CSWorker::run() {
}
// Clip sectors to polygonENU.
ClipperLib::Path polygonClipper;
auto &outer = polygonENU.outer();
snake::BoostPolygon shrinked;
snake::offsetPolygon(polygonENU, shrinked, -0.1);
auto &outer = shrinked.outer();
polygonClipper.reserve(outer.size() - 1);
for (auto it = outer.begin(); it < outer.end() - 1; ++it) {
auto x = ClipperLib::cInt(std::round(it->get<0>() * CLIPPER_SCALE));
......@@ -176,6 +227,9 @@ void CSWorker::run() {
// Extract transects from PolyTree and convert them to
// BoostLineString
snake::Transects transectsENU;
if (this->_useDepotSafeArea) {
transectsENU.push_back(snake::BoostLineString{depotENU});
}
for (const auto &child : transectsClipper.Childs) {
snake::BoostLineString transect;
transect.reserve(child->Contour.size());
......@@ -233,44 +287,49 @@ void CSWorker::run() {
}
}
// Remove short transects
for (auto it = transectsENU.begin(); it < transectsENU.end();) {
auto begin = this->_useDepotSafeArea ? transectsENU.begin() + 1
: transectsENU.begin();
for (auto it = begin; it < transectsENU.end();) {
if (bg::length(*it) < minLength.value()) {
it = transectsENU.erase(it);
} else {
++it;
}
}
// Move transect with min. distance to the front.
auto minDist = std::numeric_limits<double>::max();
auto minIt = transectsENU.begin();
bool reverse = false;
for (auto it = transectsENU.begin(); it < transectsENU.end(); ++it) {
auto distFront = bg::distance(originENU, it->front());
auto distBack = bg::distance(originENU, it->back());
if (distFront < minDist) {
minDist = distFront;
minIt = it;
reverse = false;
}
if (distBack < minDist) {
minDist = distBack;
minIt = it;
reverse = true;
if (!this->_useDepotSafeArea) {
// Move transect with min. distance to the front.
auto minDist = std::numeric_limits<double>::max();
auto minIt = transectsENU.begin();
bool reverse = false;
for (auto it = transectsENU.begin(); it < transectsENU.end(); ++it) {
auto distFront = bg::distance(originENU, it->front());
auto distBack = bg::distance(originENU, it->back());
if (distFront < minDist) {
minDist = distFront;
minIt = it;
reverse = false;
}
if (distBack < minDist) {
minDist = distBack;
minIt = it;
reverse = true;
}
}
}
// Swap and reverse (if necessary).
if (minIt != transectsENU.begin()) {
auto minTransect = *minIt;
if (reverse) {
snake::BoostLineString rev;
for (auto it = minTransect.end() - 1; it >= minTransect.begin();
--it) {
rev.push_back(*it);
// Swap and reverse (if necessary).
if (minIt != transectsENU.begin()) {
auto minTransect = *minIt;
if (reverse) {
snake::BoostLineString rev;
for (auto it = minTransect.end() - 1; it >= minTransect.begin();
--it) {
rev.push_back(*it);
}
minTransect = rev;
}
minTransect = rev;
*minIt = *transectsENU.begin();
*transectsENU.begin() = minTransect;
}
*minIt = *transectsENU.begin();
*transectsENU.begin() = minTransect;
}
#ifdef SHOW_CIRCULAR_SURVEY_TIME
qWarning() << "CSWorker::run(): transect gen. time: "
......@@ -305,9 +364,9 @@ void CSWorker::run() {
};
std::string errorString;
// Route transects;
bool success = snake::route(polygonENU, transectsENU, transectsInfo,
bool success = snake::route(safeAreaENU, transectsENU, transectsInfo,
route, stopLambda, errorString);
if (!success && !this->_restart) {
if ((!success || route.size() < 3) && !this->_restart) {
#ifdef DEBUG_CIRCULAR_SURVEY
qWarning() << "CSWorker::run(): "
"routing failed.";
......@@ -318,19 +377,38 @@ void CSWorker::run() {
"restart requested.";
#endif
} else {
// Remove return path.
// Find index of first waypoint.
std::size_t idxFirst = 0;
const auto &info1 =
this->_useDepotSafeArea ? transectsInfo[1] : transectsInfo[0];
const auto &firstTransect = transectsENU[info1.index];
const auto &firstWaypoint =
info1.reversed ? firstTransect.back() : firstTransect.front();
double th = 0.001;
for (std::size_t i = 0; i < route.size(); ++i) {
auto dist = bg::distance(route[i], firstWaypoint);
if (dist < th) {
idxFirst = i;
break;
}
}
// Find index of last waypoint.
std::size_t idxLast = 0;
const auto &info = transectsInfo.back();
const auto &lastTransect = transectsENU[info.index];
const auto &lastWaypoint =
info.reversed ? lastTransect.front() : lastTransect.back();
auto &wp = route.back();
while (wp != lastWaypoint) {
route.pop_back();
wp = route.back();
for (long i = route.size() - 1; i >= 0; --i) {
auto dist = bg::distance(route[i], lastWaypoint);
if (dist < th) {
idxLast = i;
break;
}
}
// Convert to geo coordinates and notify main thread.
auto pRoute = PtrRoute(new Route());
for (const auto &vertex : route) {
for (std::size_t i = idxFirst; i <= idxLast; ++i) {
auto vertex = route[i];
QGeoCoordinate c;
snake::fromENU(origin, vertex, c);
pRoute->append(c);
......
......@@ -31,6 +31,11 @@ public slots:
void update(const QList<QGeoCoordinate> &polygon,
const QGeoCoordinate &origin, snake::Length deltaR,
snake::Length minLength, snake::Angle deltaAlpha);
void update(const QGeoCoordinate &depot,
const QList<QGeoCoordinate> &safeArea,
const QList<QGeoCoordinate> &polygon,
const QGeoCoordinate &origin, snake::Length deltaR,
snake::Length minLength, snake::Angle deltaAlpha);
signals:
void ready(PtrRoute pTransects);
......@@ -43,6 +48,8 @@ private:
mutable std::mutex _mutex;
mutable std::condition_variable _cv;
// Internal data
QGeoCoordinate _depot;
QList<QGeoCoordinate> _safeArea;
QList<QGeoCoordinate> _polygon;
QGeoCoordinate _origin;
snake::Length _deltaR;
......@@ -51,6 +58,7 @@ private:
std::size_t _maxWaypoints;
// State
std::atomic_bool _useDepotSafeArea;
std::atomic_bool _calculating;
std::atomic_bool _stop;
std::atomic_bool _restart;
......
......@@ -36,8 +36,8 @@ CircularSurvey::CircularSurvey(Vehicle *vehicle, bool flyView,
_deltaR(settingsGroup, _metaDataMap[deltaRName]),
_deltaAlpha(settingsGroup, _metaDataMap[deltaAlphaName]),
_minLength(settingsGroup, _metaDataMap[transectMinLengthName]),
_isInitialized(false), _pWorker(std::make_unique<CSWorker>()),
_needsStoring(false), _needsReversal(false) {
_pWorker(std::make_unique<CSWorker>()), _needsStoring(false),
_needsReversal(false) {
Q_UNUSED(kmlOrShpFile)
_editorQml = "qrc:/qml/CircularSurveyItemEditor.qml";
......@@ -50,6 +50,10 @@ CircularSurvey::CircularSurvey(Vehicle *vehicle, bool flyView,
&CircularSurvey::_rebuildTransects);
connect(this, &CircularSurvey::refPointChanged, this,
&CircularSurvey::_rebuildTransects);
connect(this, &CircularSurvey::depotChanged, this,
&CircularSurvey::_rebuildTransects);
connect(this, &CircularSurvey::safeAreaChanged, this,
&CircularSurvey::_rebuildTransects);
// Connect worker.
qRegisterMetaType<PtrRoute>("PtrRoute");
connect(this->_pWorker.get(), &CSWorker::ready, this,
......@@ -78,21 +82,40 @@ void CircularSurvey::setRefPoint(const QGeoCoordinate &refPt) {
}
}
void CircularSurvey::setIsInitialized(bool isInitialized) {
if (isInitialized != _isInitialized) {
_isInitialized = isInitialized;
emit isInitializedChanged();
}
}
QGeoCoordinate CircularSurvey::refPoint() const { return _referencePoint; }
Fact *CircularSurvey::deltaR() { return &_deltaR; }
Fact *CircularSurvey::deltaAlpha() { return &_deltaAlpha; }
bool CircularSurvey::isInitialized() { return _isInitialized; }
bool CircularSurvey::hidePolygon() const { return _hidePolygon; }
QGeoCoordinate CircularSurvey::depot() const { return this->_depot; }
QList<QGeoCoordinate> CircularSurvey::safeArea() const {
return this->_safeArea;
}
void CircularSurvey::setHidePolygon(bool hide) {
if (this->_hidePolygon != hide) {
this->_hidePolygon = hide;
emit hidePolygonChanged();
}
}
void CircularSurvey::setDepot(const QGeoCoordinate &depot) {
if (this->_depot != depot) {
this->_depot = depot;
emit depotChanged();
}
}
void CircularSurvey::setSafeArea(const QList<QGeoCoordinate> &safeArea) {
if (this->_safeArea != safeArea) {
this->_safeArea = safeArea;
emit safeAreaChanged();
}
}
bool CircularSurvey::load(const QJsonObject &complexObject, int sequenceNumber,
QString &errorString) {
......@@ -161,7 +184,6 @@ bool CircularSurvey::load(const QJsonObject &complexObject, int sequenceNumber,
_referencePoint.setLongitude(complexObject[refPointLongitudeName].toDouble());
_referencePoint.setLatitude(complexObject[refPointLatitudeName].toDouble());
_referencePoint.setAltitude(complexObject[refPointAltitudeName].toDouble());
setIsInitialized(true);
_ignoreRecalc = false;
......@@ -319,12 +341,21 @@ void CircularSurvey::_rebuildTransectsPhase1(void) {
} else {
this->_transects.clear();
auto polygon = this->_surveyAreaPolygon.coordinateList();
this->_pWorker->update(
polygon, this->_referencePoint,
this->_deltaR.rawValue().toDouble() * bu::si::meter,
this->_minLength.rawValue().toDouble() * bu::si::meter,
snake::Angle(this->_deltaAlpha.rawValue().toDouble() *
bu::degree::degree));
if (this->_depot.isValid() && this->_safeArea.size() >= 3) {
this->_pWorker->update(
this->_depot, this->_safeArea, polygon, this->_referencePoint,
this->_deltaR.rawValue().toDouble() * bu::si::meter,
this->_minLength.rawValue().toDouble() * bu::si::meter,
snake::Angle(this->_deltaAlpha.rawValue().toDouble() *
bu::degree::degree));
} else {
this->_pWorker->update(
polygon, this->_referencePoint,
this->_deltaR.rawValue().toDouble() * bu::si::meter,
this->_minLength.rawValue().toDouble() * bu::si::meter,
snake::Angle(this->_deltaAlpha.rawValue().toDouble() *
bu::degree::degree));
}
}
}
......@@ -351,7 +382,9 @@ void CircularSurvey::_setTransects(CircularSurvey::PtrRoute pRoute) {
Fact *CircularSurvey::transectMinLength() { return &_minLength; }
bool CircularSurvey::calculating() { return this->_pWorker->calculating(); }
bool CircularSurvey::calculating() const {
return this->_pWorker->calculating();
}
/*!
\class CircularSurveyComplexItem
......
......@@ -28,48 +28,43 @@ public:
Q_PROPERTY(Fact *deltaR READ deltaR CONSTANT)
Q_PROPERTY(Fact *deltaAlpha READ deltaAlpha CONSTANT)
Q_PROPERTY(Fact *transectMinLength READ transectMinLength CONSTANT)
Q_PROPERTY(bool isInitialized READ isInitialized WRITE setIsInitialized NOTIFY
isInitializedChanged)
Q_PROPERTY(bool calculating READ calculating NOTIFY calculatingChanged)
Q_PROPERTY(bool hidePolygon READ hidePolygon NOTIFY hidePolygon)
Q_INVOKABLE void resetReference(void);
Q_INVOKABLE void reverse(void);
// Property setters
void setRefPoint(const QGeoCoordinate &refPt);
// Set this to true if survey was automatically generated, prevents
// initialisation from gui.
void setIsInitialized(bool isInitialized);
void setHidePolygon(bool hide);
void setDepot(const QGeoCoordinate &depot);
void setSafeArea(const QList<QGeoCoordinate> &safeArea);
// Property getters
QGeoCoordinate refPoint() const;
Fact *deltaR();
Fact *deltaAlpha();
Fact *transectMinLength();
bool calculating();
// Is true if survey was automatically generated, prevents initialisation from
// gui.
bool isInitialized();
bool calculating() const;
bool hidePolygon() const;
QGeoCoordinate depot() const;
QList<QGeoCoordinate> safeArea() const;
// Overrides from ComplexMissionItem
// Overrides
bool load(const QJsonObject &complexObject, int sequenceNumber,
QString &errorString) final;
QString mapVisualQML(void) const final;
// Overrides from TransectStyleComplexItem
void save(QJsonArray &planItems) final;
bool specifiesCoordinate(void) const final;
QString &errorString) override final;
QString mapVisualQML(void) const override final;
void save(QJsonArray &planItems) override final;
bool specifiesCoordinate(void) const override final;
void appendMissionItems(QList<MissionItem *> &items,
QObject *missionItemParent) final;
void applyNewAltitude(double newAltitude) final;
double timeBetweenShots(void) final;
// Overrides from VisualMissionionItem
QString commandDescription(void) const final;
QString commandName(void) const final;
QString abbreviation(void) const final;
bool readyForSave(void) const final;
double additionalTimeDelay(void) const final;
QObject *missionItemParent) override final;
void applyNewAltitude(double newAltitude) override final;
double timeBetweenShots(void) override final;
QString commandDescription(void) const override final;
QString commandName(void) const override final;
QString abbreviation(void) const override final;
bool readyForSave(void) const override final;
double additionalTimeDelay(void) const override final;
static const char *settingsGroup;
static const char *deltaRName;
......@@ -82,8 +77,10 @@ public:
signals:
void refPointChanged();
void isInitializedChanged();
void calculatingChanged();
void hidePolygonChanged();
void depotChanged();
void safeAreaChanged();
private slots:
// Overrides from TransectStyleComplexItem
......@@ -109,14 +106,14 @@ private:
// minimal transect lenght, transects are rejected if they are shorter than
// this value
SettingsFact _minLength;
// indicates if the polygon and refpoint etc. are initialized, prevents
// reinitialisation from gui and execution of _rebuildTransectsPhase1 during
// init from gui
bool _isInitialized;
using PtrWorker = std::shared_ptr<CSWorker>;
PtrWorker _pWorker;
PtrRoute _pRoute;
bool _needsStoring;
bool _needsReversal;
bool _hidePolygon;
QGeoCoordinate _depot;
QList<QGeoCoordinate> _safeArea;
};
......@@ -135,14 +135,14 @@ bool WimaMeasurementArea::loadFromJson(const QJsonObject &json,
}
if (json.contains(tileWidthName) && json[tileWidthName].isDouble()) {
_tileHeight.setRawValue(json[tileWidthName].toDouble());
_tileWidth.setRawValue(json[tileWidthName].toDouble());
} else {
errorString.append(tr("Could not load tile width!\n"));
retVal = false;
}
if (json.contains(minTileAreaName) && json[minTileAreaName].isDouble()) {
_tileHeight.setRawValue(json[minTileAreaName].toDouble());
_minTileArea.setRawValue(json[minTileAreaName].toDouble());
} else {
errorString.append(tr("Could not load minimal tile area!\n"));
retVal = false;
......@@ -150,7 +150,7 @@ bool WimaMeasurementArea::loadFromJson(const QJsonObject &json,
if (json.contains(transectDistanceName) &&
json[transectDistanceName].isDouble()) {
_tileHeight.setRawValue(json[transectDistanceName].toDouble());
_transectDistance.setRawValue(json[transectDistanceName].toDouble());
} else {
errorString.append(tr("Could not load transect distance!\n"));
retVal = false;
......@@ -158,14 +158,14 @@ bool WimaMeasurementArea::loadFromJson(const QJsonObject &json,
if (json.contains(minTransectLengthName) &&
json[minTransectLengthName].isDouble()) {
_tileHeight.setRawValue(json[minTransectLengthName].toDouble());
_minTransectLength.setRawValue(json[minTransectLengthName].toDouble());
} else {
errorString.append(tr("Could not load minimal transect length!\n"));
retVal = false;
}
if (json.contains(showTilesName) && json[showTilesName].isBool()) {
_tileHeight.setRawValue(json[showTilesName].toDouble());
_showTiles.setRawValue(json[showTilesName].toBool());
} else {
errorString.append(tr("Could not load show tiles !\n"));
retVal = false;
......
#include "WimaServiceArea.h"
const char* WimaServiceArea::wimaServiceAreaName = "Service Area";
const char *WimaServiceArea::wimaServiceAreaName = "Service Area";
WimaServiceArea::WimaServiceArea(QObject *parent)
: WimaArea (parent)
{
init();
}
WimaServiceArea::WimaServiceArea(QObject *parent) : WimaArea(parent) { init(); }
WimaServiceArea::WimaServiceArea(const WimaServiceArea &other, QObject *parent)
: WimaArea (other, parent)
{
init();
: WimaArea(other, parent) {
init();
}
/*!
......@@ -21,63 +14,53 @@ WimaServiceArea::WimaServiceArea(const WimaServiceArea &other, QObject *parent)
*
* Calls the inherited operator WimaArea::operator=().
*/
WimaServiceArea &WimaServiceArea::operator=(const WimaServiceArea &other)
{
WimaArea::operator=(other);
return *this;
}
WimaServiceArea &WimaServiceArea::operator=(const WimaServiceArea &other) {
WimaArea::operator=(other);
void WimaServiceArea::setTakeOffPosition(const QGeoCoordinate &coordinate)
{
if(_takeOffPosition != coordinate){
_takeOffPosition = coordinate;
emit takeOffPositionChanged();
}
return *this;
}
void WimaServiceArea::setLandPosition(const QGeoCoordinate &coordinate)
{
if(_landPosition != coordinate){
_landPosition = coordinate;
emit landPositionChanged();
}
void WimaServiceArea::setDepot(const QGeoCoordinate &coordinate) {
if (_depot != coordinate) {
_depot = coordinate;
emit depotChanged();
}
}
void WimaServiceArea::saveToJson(QJsonObject &json)
{
this->WimaArea::saveToJson(json);
json[areaTypeName] = wimaServiceAreaName;
void WimaServiceArea::saveToJson(QJsonObject &json) {
this->WimaArea::saveToJson(json);
json[areaTypeName] = wimaServiceAreaName;
}
bool WimaServiceArea::loadFromJson(const QJsonObject &json, QString &errorString)
{
if ( this->WimaArea::loadFromJson(json, errorString)) {
bool retVal = true;
// code for loading here
return retVal;
} else {
qWarning() << errorString;
return false;
}
bool WimaServiceArea::loadFromJson(const QJsonObject &json,
QString &errorString) {
if (this->WimaArea::loadFromJson(json, errorString)) {
bool retVal = true;
// code for loading here
return retVal;
} else {
qWarning() << errorString;
return false;
}
}
void print(const WimaServiceArea &area)
{
QString message;
print(area, message);
qWarning() << message;
void print(const WimaServiceArea &area) {
QString message;
print(area, message);
qWarning() << message;
}
void print(const WimaServiceArea &area, QString &outputStr)
{
print(static_cast<const WimaArea&>(area), outputStr);
outputStr.append(QString("Takeoff Position: %s\n").arg(area._takeOffPosition.toString(QGeoCoordinate::Degrees)));
outputStr.append(QString("Land Position: %s\n").arg(area._landPosition.toString(QGeoCoordinate::Degrees)));
void print(const WimaServiceArea &area, QString &outputStr) {
print(static_cast<const WimaArea &>(area), outputStr);
outputStr.append(QString("Depot Position: %s\n")
.arg(area._depot.toString(QGeoCoordinate::Degrees)));
}
void WimaServiceArea::init()
{
this->setObjectName(wimaServiceAreaName);
void WimaServiceArea::init() {
this->setObjectName(wimaServiceAreaName);
connect(this, &WimaServiceArea::centerChanged, [this] {
if (!this->_depot.isValid()) {
this->setDepot(this->center());
}
});
}
#pragma once
#include <QObject>
#include "WimaArea.h"
#include "WimaTrackerPolyline.h"
#include <QObject>
class WimaServiceArea : public WimaArea
{
Q_OBJECT
class WimaServiceArea : public WimaArea {
Q_OBJECT
public:
WimaServiceArea(QObject* parent = nullptr);
WimaServiceArea(const WimaServiceArea& other, QObject* parent);
WimaServiceArea& operator=(const WimaServiceArea &other);
Q_PROPERTY(const QGeoCoordinate& takeOffPosition READ takeOffPosition WRITE setTakeOffPosition NOTIFY takeOffPositionChanged)
Q_PROPERTY(const QGeoCoordinate& landPosition READ landPosition WRITE setLandPosition NOTIFY landPositionChanged)
WimaServiceArea(QObject *parent = nullptr);
WimaServiceArea(const WimaServiceArea &other, QObject *parent);
WimaServiceArea &operator=(const WimaServiceArea &other);
// Overrides from WimaPolygon
QString mapVisualQML (void) const { return "WimaServiceAreaMapVisual.qml";}
QString editorQML (void) const { return "WimaServiceAreaEditor.qml";}
Q_PROPERTY(QGeoCoordinate depot READ depot WRITE setDepot NOTIFY depotChanged)
// Property acessors
const QGeoCoordinate& takeOffPosition (void) const { return _takeOffPosition;}
const QGeoCoordinate& landPosition (void) const { return _landPosition;}
// Overrides from WimaPolygon
QString mapVisualQML(void) const { return "WimaServiceAreaMapVisual.qml"; }
QString editorQML(void) const { return "WimaServiceAreaEditor.qml"; }
// Member Methodes
void saveToJson(QJsonObject& json);
bool loadFromJson(const QJsonObject& json, QString& errorString);
// Property acessors
const QGeoCoordinate &depot(void) const { return _depot; }
// Member Methodes
void saveToJson(QJsonObject &json);
bool loadFromJson(const QJsonObject &json, QString &errorString);
// Friends
friend void print(const WimaServiceArea &area, QString &outputStr);
friend void print(const WimaServiceArea &area);
// Friends
friend void print(const WimaServiceArea& area, QString& outputStr);
friend void print(const WimaServiceArea& area);
// static Members
static const char* wimaServiceAreaName;
// static Members
static const char *wimaServiceAreaName;
signals:
void takeOffPositionChanged (void);
void landPositionChanged (void);
void depotChanged(void);
public slots:
void setTakeOffPosition (const QGeoCoordinate& coordinate);
void setLandPosition (const QGeoCoordinate& coordinate);
void setDepot(const QGeoCoordinate &coordinate);
private:
// Member Methodes
void init();
// Member Methodes
void init();
// Members
QGeoCoordinate _takeOffPosition;
QGeoCoordinate _landPosition;
// Members
QGeoCoordinate _depot;
};
......@@ -100,7 +100,7 @@ void WimaServiceAreaData::assign(const WimaServiceArea &other)
{
WimaAreaData::assign(other);
setLandPosition(other.landPosition());
setTakeOffPosition(other.takeOffPosition());
setTakeOffPosition(other.depot());
}
......
......@@ -22,25 +22,25 @@ const char *WimaPlaner::missionItemsName = "MissionItems";
WimaPlaner::WimaPlaner(QObject *parent)
: QObject(parent), _masterController(nullptr), _missionController(nullptr),
_currentAreaIndex(-1), _wimaBridge(nullptr), _joinedArea(this),
_joinedAreaValid(false), _arrivalPathLength(0), _returnPathLength(0),
_TSComplexItem(nullptr), _surveyRefChanging(false),
_measurementAreaChanging(false), _corridorChanging(false),
_serviceAreaChanging(false), _syncronizedWithController(false),
_readyForSync(false) {
_lastMeasurementAreaPath = _measurementArea.path();
_lastServiceAreaPath = _serviceArea.path();
_lastCorridorPath = _corridor.path();
_currentAreaIndex(-1), _wimaBridge(nullptr), _mAreaChanged(true),
_sAreaChanged(true), _corridorChanged(true), _joinedArea(this),
_arrivalPathLength(0), _returnPathLength(0), _TSComplexItem(nullptr),
_surveyChanged(true), _synchronized(false) {
connect(this, &WimaPlaner::currentPolygonIndexChanged, this,
&WimaPlaner::recalcPolygonInteractivity);
connect(&_updateTimer, &QTimer::timeout, this, &WimaPlaner::updateTimerSlot);
connect(this, &WimaPlaner::joinedAreaValidChanged, this,
&WimaPlaner::updateMission);
_updateTimer.setInterval(300); // 300 ms means: max update time 2*300 ms
_updateTimer.start();
&WimaPlaner::updatePolygonInteractivity);
connect(&this->_measurementArea, &WimaArea::pathChanged, [this] {
this->_mAreaChanged = true;
this->setNeedsUpdate(true);
});
connect(&this->_serviceArea, &WimaArea::pathChanged, [this] {
this->_sAreaChanged = true;
this->setNeedsUpdate(true);
});
connect(&this->_corridor, &WimaArea::pathChanged, [this] {
this->_corridorChanged = true;
this->setNeedsUpdate(true);
});
#ifndef NDEBUG
// for debugging and testing purpose, remove if not needed anymore
connect(&_autoLoadTimer, &QTimer::timeout, this,
......@@ -48,15 +48,22 @@ WimaPlaner::WimaPlaner(QObject *parent)
_autoLoadTimer.setSingleShot(true);
_autoLoadTimer.start(300);
#endif
}
_calcArrivalAndReturnPathTimer.setInterval(100);
_calcArrivalAndReturnPathTimer.setSingleShot(true);
connect(&_calcArrivalAndReturnPathTimer, &QTimer::timeout, this,
&WimaPlaner::calcArrivalAndReturnPath);
PlanMasterController *WimaPlaner::masterController() {
return _masterController;
}
MissionController *WimaPlaner::missionController() {
return _missionController;
}
QmlObjectListModel *WimaPlaner::visualItems() { return &_visualItems; }
int WimaPlaner::currentPolygonIndex() const { return _currentAreaIndex; }
QString WimaPlaner::currentFile() const { return _currentFile; }
QStringList WimaPlaner::loadNameFilters() const {
QStringList filters;
......@@ -76,10 +83,14 @@ QStringList WimaPlaner::saveNameFilters() const {
return filters;
}
QString WimaPlaner::fileExtension() const { return wimaFileExtension; }
QGeoCoordinate WimaPlaner::joinedAreaCenter() const {
return _joinedArea.center();
}
WimaBridge *WimaPlaner::wimaBridge() { return _wimaBridge; }
void WimaPlaner::setMasterController(PlanMasterController *masterC) {
_masterController = masterC;
emit masterControllerChanged();
......@@ -106,11 +117,9 @@ void WimaPlaner::setWimaBridge(WimaBridge *bridge) {
}
}
bool WimaPlaner::syncronizedWithController() {
return _syncronizedWithController;
}
bool WimaPlaner::synchronized() { return _synchronized; }
bool WimaPlaner::readyForSync() { return _readyForSync; }
bool WimaPlaner::needsUpdate() { return _needsUpdate; }
WimaPlaner *WimaPlaner::thisPointer() { return this; }
......@@ -139,7 +148,7 @@ void WimaPlaner::removeArea(int index) {
if (_currentAreaIndex >= _visualItems.count()) {
setCurrentPolygonIndex(_visualItems.count() - 1);
} else {
recalcPolygonInteractivity(_currentAreaIndex);
updatePolygonInteractivity(_currentAreaIndex);
}
} else {
qWarning("Index out of bounds!");
......@@ -200,25 +209,75 @@ void WimaPlaner::removeAll() {
_currentFile = "";
_TSComplexItem = nullptr;
_surveyRefChanging = false;
emit currentFileChanged();
if (changesApplied)
emit visualItemsChanged();
}
bool WimaPlaner::updateMission() {
bool WimaPlaner::update() {
this->_synchronized = false;
emit synchronizedChanged();
// ====================== update joined area ======================
// check if at least service area and measurement area are available
if (_visualItems.indexOf(&_serviceArea) == -1 ||
_visualItems.indexOf(&_measurementArea) == -1)
return false;
// Check if polygons have at least three vertices
if (_serviceArea.count() < 3) {
qgcApp()->showMessage(tr("Service area has less than three vertices."));
return false;
}
if (_measurementArea.count() < 3) {
qgcApp()->showMessage(tr("Measurement area has less than three vertices."));
return false;
}
// Check for simple polygons
if (!_serviceArea.isSimplePolygon()) {
qgcApp()->showMessage(tr("Service area is not a simple polygon. "
"Only simple polygons allowed.\n"));
return false;
}
setReadyForSync(false);
if (!_corridor.isSimplePolygon() && _corridor.count() > 0) {
qgcApp()->showMessage(tr("Corridor is not a simple polygon. Only "
"simple polygons allowed.\n"));
return false;
}
if (!_joinedAreaValid)
if (!_measurementArea.isSimplePolygon()) {
qgcApp()->showMessage(tr("Measurement area is not a simple "
"polygon. Only simple polygons allowed.\n"));
return false;
}
// Join areas.
bool jAreaChanged =
this->_mAreaChanged || this->_sAreaChanged || this->_corridorChanged;
if (jAreaChanged) {
_joinedArea.setPath(_serviceArea.path());
if (_corridor.count() >= 3) {
_joinedArea.join(_corridor);
}
if (!_joinedArea.join(_measurementArea)) {
qgcApp()->showMessage(
tr("Not able to join areas. Service and measurement area"
" must be overlapping, or connected through a "
"corridor."));
return false;
}
}
// ===========================================================
// ====================== update survey ======================
bool updateSurveyArea = jAreaChanged;
// extract old survey data
QmlObjectListModel *missionItems = _missionController->visualItems();
int surveyIndex = missionItems->indexOf(_TSComplexItem);
// create survey item if not yet present
if (surveyIndex == -1) {
_missionController->insertComplexMissionItem(
......@@ -228,29 +287,150 @@ bool WimaPlaner::updateMission() {
missionItems->get(missionItems->count() - 1));
if (_TSComplexItem == nullptr) {
qWarning("WimaPlaner::updateMission(): survey == nullptr");
qWarning("WimaPlaner::update(): survey == nullptr");
return false;
}
// establish connections
_TSComplexItem->setRefPoint(_measurementArea.center());
_lastSurveyRefPoint = _measurementArea.center();
_surveyRefChanging = false;
_TSComplexItem->setIsInitialized(
true); // prevents reinitialisation from gui
connect(_TSComplexItem, &TransectStyleComplexItem::missionItemReady, this,
&WimaPlaner::calcArrivalAndReturnPath);
}
_TSComplexItem->setHidePolygon(true);
connect(_TSComplexItem, &CircularSurvey::missionItemReady, [this] {
this->_surveyChanged = true;
this->setNeedsUpdate(true);
});
updateSurveyArea = true;
}
if (updateSurveyArea) {
// update survey area
_TSComplexItem->surveyAreaPolygon()->clear();
_TSComplexItem->surveyAreaPolygon()->appendVertices(
_measurementArea.coordinateList());
_TSComplexItem->setDepot(this->_serviceArea.depot());
_TSComplexItem->setSafeArea(this->_joinedArea.coordinateList());
this->_mAreaChanged = false;
this->_sAreaChanged = false;
this->_corridorChanged = false;
} else if (this->_surveyChanged) {
// ==========================================================
// ====================== update paths ======================
surveyIndex = missionItems->indexOf(_TSComplexItem);
if (surveyIndex == -1) {
qWarning("WimaPlaner::update(): no survey item");
return false;
}
// update survey area
_TSComplexItem->surveyAreaPolygon()->clear();
_TSComplexItem->surveyAreaPolygon()->appendVertices(
_measurementArea.coordinateList());
// remove old arrival and return path
int size = missionItems->count();
for (int i = surveyIndex + 1; i < size; i++)
_missionController->removeMissionItem(surveyIndex + 1);
for (int i = surveyIndex - 1; i > 1; i--)
_missionController->removeMissionItem(i);
// set home position to serArea center
MissionSettingsItem *settingsItem =
qobject_cast<MissionSettingsItem *>(missionItems->get(0));
if (settingsItem == nullptr) {
qWarning("WimaPlaner::update(): settingsItem == nullptr");
return false;
}
// set altitudes
QGeoCoordinate point = _serviceArea.depot();
point.setAltitude(0);
_serviceArea.setDepot(point);
point = _measurementArea.center();
point.setAltitude(0);
_measurementArea.setCenter(point);
point = _corridor.center();
point.setAltitude(0);
_corridor.setCenter(point);
settingsItem->setCoordinate(_serviceArea.depot());
// set takeoff position
bool setCommandNeeded = false;
if (missionItems->count() < 3) {
setCommandNeeded = true;
_missionController->insertSimpleMissionItem(_serviceArea.depot(), 1);
}
SimpleMissionItem *takeOffItem =
qobject_cast<SimpleMissionItem *>(missionItems->get(1));
if (takeOffItem == nullptr) {
qWarning("WimaPlaner::update(): takeOffItem == nullptr");
return false;
}
if (setCommandNeeded)
_missionController->setTakeoffCommand(*takeOffItem);
takeOffItem->setCoordinate(_serviceArea.depot());
setReadyForSync(true);
if (_TSComplexItem->visualTransectPoints().size() == 0) {
qWarning("WimaPlaner::update(): survey no points.");
return false;
}
// calculate path from take off to survey
QGeoCoordinate start = _serviceArea.depot();
QGeoCoordinate end = _TSComplexItem->coordinate();
#ifdef QT_DEBUG
// if (!_visualItems.contains(&_joinedArea))
//_visualItems.append(&_joinedArea);
#endif
QVector<QGeoCoordinate> path;
if (!shortestPath(start, end, path)) {
qgcApp()->showMessage(QString(tr("Not able to calculate path from "
"takeoff position to measurement area."))
.toLocal8Bit()
.data());
return false;
}
_arrivalPathLength = path.size() - 1;
int sequenceNumber = 0;
for (int i = 1; i < path.count() - 1; i++) {
sequenceNumber = _missionController->insertSimpleMissionItem(
path[i], missionItems->count() - 1);
_missionController->setCurrentPlanViewIndex(sequenceNumber, true);
}
// calculate return path
start = _TSComplexItem->exitCoordinate();
end = _serviceArea.depot();
path.clear();
if (!shortestPath(start, end, path)) {
qgcApp()->showMessage(QString(tr("Not able to calculate the path from "
"measurement area to landing position."))
.toLocal8Bit()
.data());
return false;
}
_returnPathLength =
path.size() - 1; // -1: fist item is last measurement point
for (int i = 1; i < path.count() - 1; i++) {
sequenceNumber = _missionController->insertSimpleMissionItem(
path[i], missionItems->count());
_missionController->setCurrentPlanViewIndex(sequenceNumber, true);
}
// create land position item
sequenceNumber = _missionController->insertSimpleMissionItem(
_serviceArea.depot(), missionItems->count());
_missionController->setCurrentPlanViewIndex(sequenceNumber, true);
SimpleMissionItem *landItem = qobject_cast<SimpleMissionItem *>(
missionItems->get(missionItems->count() - 1));
if (landItem == nullptr) {
qWarning("WimaPlaner::calcArrivalAndReturnPath(): landItem == nullptr");
return false;
} else {
if (!_missionController->setLandCommand(*landItem))
return false;
}
this->_surveyChanged = false;
}
setNeedsUpdate(false);
return true;
}
void WimaPlaner::saveToCurrent() { saveToFile(_currentFile); }
void WimaPlaner::saveToFile(const QString &filename) {
......@@ -344,8 +524,6 @@ bool WimaPlaner::loadFromFile(const QString &filename) {
return false;
}
_lastMeasurementAreaPath =
_measurementArea.path(); // prevents error messages at this point
validAreaCounter++;
_visualItems.append(&_measurementArea);
emit visualItemsChanged();
......@@ -358,8 +536,6 @@ bool WimaPlaner::loadFromFile(const QString &filename) {
return false;
}
_lastServiceAreaPath =
_serviceArea.path(); // prevents error messages at this point
validAreaCounter++;
_visualItems.append(&_serviceArea);
emit visualItemsChanged();
......@@ -372,8 +548,6 @@ bool WimaPlaner::loadFromFile(const QString &filename) {
return false;
}
_lastCorridorPath =
_corridor.path(); // prevents error messages at this point
validAreaCounter++;
_visualItems.append(&_corridor);
emit visualItemsChanged();
......@@ -434,28 +608,21 @@ bool WimaPlaner::loadFromFile(const QString &filename) {
// load from temporary file
_masterController->loadFromFile(temporaryFileName);
QmlObjectListModel *missionItems = _missionController->visualItems();
_TSComplexItem = nullptr;
for (int i = 0; i < missionItems->count(); i++) {
_TSComplexItem = missionItems->value<CircularSurvey *>(i);
if (_TSComplexItem != nullptr) {
_lastSurveyRefPoint = _TSComplexItem->refPoint();
_surveyRefChanging = false;
_TSComplexItem->setIsInitialized(
true); // prevents reinitialisation from gui
connect(_TSComplexItem, &TransectStyleComplexItem::missionItemReady,
this, &WimaPlaner::calcArrivalAndReturnPath);
_TSComplexItem->setHidePolygon(true);
connect(_TSComplexItem, &CircularSurvey::missionItemReady, [this] {
this->_surveyChanged = true;
this->setNeedsUpdate(true);
});
break;
}
}
// if (_circularSurvey == nullptr)
if (!recalcJoinedArea())
return false;
if (!updateMission())
if (!update())
return false;
// remove temporary file
......@@ -464,13 +631,12 @@ bool WimaPlaner::loadFromFile(const QString &filename) {
"WimaPlaner::loadFromFile(): not able to remove temporary file.");
}
setSyncronizedWithController(false);
this->_synchronized = false;
emit synchronizedChanged();
return true;
} else if (fileInfo.suffix() == AppSettings::planFileExtension) {
_masterController->loadFromFile(filename);
return true; // might be wrong return value
} else {
errorString += QString(tr("File extension not supported.\n"));
......@@ -479,7 +645,7 @@ bool WimaPlaner::loadFromFile(const QString &filename) {
}
}
void WimaPlaner::recalcPolygonInteractivity(int index) {
void WimaPlaner::updatePolygonInteractivity(int index) {
if (index >= 0 && index < _visualItems.count()) {
resetAllInteractive();
WimaArea *interactivePoly =
......@@ -489,198 +655,22 @@ void WimaPlaner::recalcPolygonInteractivity(int index) {
}
}
bool WimaPlaner::calcArrivalAndReturnPath() {
setReadyForSync(false);
// extract old survey data
QmlObjectListModel *missionItems = _missionController->visualItems();
int surveyIndex = missionItems->indexOf(_TSComplexItem);
if (surveyIndex == -1) {
qWarning("WimaPlaner::calcArrivalAndReturnPath(): no survey item");
return false;
}
bool restorePlanViewIndex = false;
if (surveyIndex == _missionController->currentPlanViewIndex())
restorePlanViewIndex = true;
// remove old arrival and return path
int size = missionItems->count();
for (int i = surveyIndex + 1; i < size; i++)
_missionController->removeMissionItem(surveyIndex + 1);
for (int i = surveyIndex - 1; i > 1; i--)
_missionController->removeMissionItem(i);
// set home position to serArea center
MissionSettingsItem *settingsItem =
qobject_cast<MissionSettingsItem *>(missionItems->get(0));
if (settingsItem == nullptr) {
qWarning("WimaPlaner::calcArrivalAndReturnPath(): settingsItem == nullptr");
return false;
}
// set altitudes, temporary measure to solve bugs
QGeoCoordinate center = _serviceArea.center();
center.setAltitude(0);
_serviceArea.setCenter(center);
center = _measurementArea.center();
center.setAltitude(0);
_measurementArea.setCenter(center);
center = _corridor.center();
center.setAltitude(0);
_corridor.setCenter(center);
// set HomePos. to serArea center
settingsItem->setCoordinate(_serviceArea.center());
// set takeoff position
bool setCommandNeeded = false;
if (missionItems->count() < 3) {
setCommandNeeded = true;
_missionController->insertSimpleMissionItem(_serviceArea.center(), 1);
}
SimpleMissionItem *takeOffItem =
qobject_cast<SimpleMissionItem *>(missionItems->get(1));
if (takeOffItem == nullptr) {
qWarning("WimaPlaner::calcArrivalAndReturnPath(): takeOffItem == nullptr");
return false;
}
if (setCommandNeeded)
_missionController->setTakeoffCommand(*takeOffItem);
takeOffItem->setCoordinate(_serviceArea.center());
if (_TSComplexItem->visualTransectPoints().size() == 0) {
qWarning("WimaPlaner::calcArrivalAndReturnPath(): survey no points.");
return false;
}
// calculate path from take off to survey
QGeoCoordinate start = _serviceArea.center();
QGeoCoordinate end = _TSComplexItem->coordinate();
#ifdef QT_DEBUG
// if (!_visualItems.contains(&_joinedArea))
//_visualItems.append(&_joinedArea);
#endif
QVector<QGeoCoordinate> path;
if (!calcShortestPath(start, end, path)) {
qgcApp()->showMessage(QString(tr("Not able to calculate the path from "
"takeoff position to measurement area."))
.toLocal8Bit()
.data());
return false;
}
_arrivalPathLength = path.size() - 1;
int sequenceNumber = 0;
for (int i = 1; i < path.count() - 1; i++) {
sequenceNumber = _missionController->insertSimpleMissionItem(
path[i], missionItems->count() - 1);
_missionController->setCurrentPlanViewIndex(sequenceNumber, true);
}
// calculate return path
start = _TSComplexItem->exitCoordinate();
end = _serviceArea.center();
path.clear();
if (!calcShortestPath(start, end, path)) {
qgcApp()->showMessage(QString(tr("Not able to calculate the path from "
"measurement area to landing position."))
.toLocal8Bit()
.data());
return false;
}
_returnPathLength =
path.size() - 1; // -1: fist item is last measurement point
for (int i = 1; i < path.count() - 1; i++) {
sequenceNumber = _missionController->insertSimpleMissionItem(
path[i], missionItems->count());
_missionController->setCurrentPlanViewIndex(sequenceNumber, true);
}
// create land position item
sequenceNumber = _missionController->insertSimpleMissionItem(
_serviceArea.center(), missionItems->count());
_missionController->setCurrentPlanViewIndex(sequenceNumber, true);
SimpleMissionItem *landItem = qobject_cast<SimpleMissionItem *>(
missionItems->get(missionItems->count() - 1));
if (landItem == nullptr) {
qWarning("WimaPlaner::calcArrivalAndReturnPath(): landItem == nullptr");
return false;
} else {
if (!_missionController->setLandCommand(*landItem))
return false;
}
if (restorePlanViewIndex)
_missionController->setCurrentPlanViewIndex(
missionItems->indexOf(_TSComplexItem), false);
setSyncronizedWithControllerFalse();
setReadyForSync(true);
return true;
}
bool WimaPlaner::recalcJoinedArea() {
setJoinedAreaValid(false);
// check if at least service area and measurement area are available
if (_visualItems.indexOf(&_serviceArea) == -1 ||
_visualItems.indexOf(&_measurementArea) == -1)
return false;
// check if area paths form simple polygons
if (!_serviceArea.isSimplePolygon()) {
qgcApp()->showMessage(
tr("Service area is self intersecting and thus not a simple polygon. "
"Only simple polygons allowed.\n"));
return false;
}
if (!_corridor.isSimplePolygon() && _corridor.count() > 0) {
qgcApp()->showMessage(
tr("Corridor is self intersecting and thus not a simple polygon. Only "
"simple polygons allowed.\n"));
return false;
}
if (!_measurementArea.isSimplePolygon()) {
qgcApp()->showMessage(
tr("Measurement area is self intersecting and thus not a simple "
"polygon. Only simple polygons allowed.\n"));
return false;
}
_joinedArea.setPath(_serviceArea.path());
_joinedArea.join(_corridor);
if (!_joinedArea.join(_measurementArea)) {
/*qgcApp()->showMessage(tr("Not able to join areas. Service area and
measurement"
" must have a overlapping section, or be connected
through a corridor."));*/
return false; // this happens if all areas are pairwise disjoint
}
// join service area, op area and corridor
setJoinedAreaValid(true);
return true;
}
void WimaPlaner::pushToWimaController() {
if (_wimaBridge != nullptr) {
if (!_readyForSync)
if (!_needsUpdate)
return;
WimaPlanData planData = toPlanData();
(void)_wimaBridge->setWimaPlanData(planData);
setSyncronizedWithController(true);
this->_synchronized = true;
emit synchronizedChanged();
} else {
qWarning("WimaPlaner::uploadToContainer(): no container assigned.");
}
}
bool WimaPlaner::calcShortestPath(const QGeoCoordinate &start,
const QGeoCoordinate &destination,
QVector<QGeoCoordinate> &path) {
bool WimaPlaner::shortestPath(const QGeoCoordinate &start,
const QGeoCoordinate &destination,
QVector<QGeoCoordinate> &path) {
using namespace GeoUtilities;
using namespace PolygonCalculus;
QPolygonF polygon2D;
......@@ -696,6 +686,13 @@ bool WimaPlaner::calcShortestPath(const QGeoCoordinate &start,
return retVal;
}
void WimaPlaner::setNeedsUpdate(bool needsUpdate) {
if (this->_needsUpdate != needsUpdate) {
this->_needsUpdate = needsUpdate;
emit needsUpdateChanged();
}
}
void WimaPlaner::resetAllInteractive() {
// Marks all areas as inactive (area.interactive == false)
int itemCount = _visualItems.count();
......@@ -708,15 +705,15 @@ void WimaPlaner::resetAllInteractive() {
}
void WimaPlaner::setInteractive() {
recalcPolygonInteractivity(_currentAreaIndex);
updatePolygonInteractivity(_currentAreaIndex);
}
/*!
* \fn WimaPlanData WimaPlaner::toPlanData()
*
* Returns a \c WimaPlanData object containing information about the current
* mission. The \c WimaPlanData object holds only the data which is relevant for
* the \c WimaController class. Should only be called if updateMission() was
* mission. The \c WimaPlanData object holds only the data which is relevant
* for the \c WimaController class. Should only be called if update() was
* successful.
*
* \sa WimaController, WimaPlanData
......@@ -748,111 +745,6 @@ WimaPlanData WimaPlaner::toPlanData() {
return planData;
}
void WimaPlaner::setSyncronizedWithController(bool sync) {
if (_syncronizedWithController != sync) {
_syncronizedWithController = sync;
emit syncronizedWithControllerChanged();
}
}
void WimaPlaner::setReadyForSync(bool ready) {
if (_readyForSync != ready) {
_readyForSync = ready;
emit readyForSyncChanged();
}
}
void WimaPlaner::setJoinedAreaValid(bool valid) {
if (_joinedAreaValid != valid) {
_joinedAreaValid = valid;
emit joinedAreaValidChanged();
}
}
void WimaPlaner::updateTimerSlot() {
// General operation of this function:
// Check if parameter has changed, wait until it stops changing, update
// mission
// circular survey reference point
// if (_missionController != nullptr
// && _missionController->visualItems()->indexOf(_circularSurvey)
// != -1
// && _circularSurvey != nullptr)
// {
// if (_surveyRefChanging) {
// if (_circularSurvey->refPoint() == _lastSurveyRefPoint) { // is
// it still changing?
// calcArrivalAndReturnPath();
// _surveyRefChanging = false;
// }
// } else {
// if (_circularSurvey->refPoint() != _lastSurveyRefPoint) // does
// it started changing?
// _surveyRefChanging = true;
// }
// }
// measurementArea
if (_measurementAreaChanging) {
if (_measurementArea.path() ==
_lastMeasurementAreaPath) { // is it still changing?
setReadyForSync(false);
if (recalcJoinedArea() && calcArrivalAndReturnPath())
setReadyForSync(true);
_measurementAreaChanging = false;
}
} else {
if (_measurementArea.path() !=
_lastMeasurementAreaPath) // does it started changing?
_measurementAreaChanging = true;
}
// corridor
if (_corridorChanging) {
if (_corridor.path() == _lastCorridorPath) { // is it still changing?
setReadyForSync(false);
if (recalcJoinedArea() && calcArrivalAndReturnPath())
setReadyForSync(true);
_corridorChanging = false;
}
} else {
if (_corridor.path() != _lastCorridorPath) // does it started changing?
_corridorChanging = true;
}
// service area
if (_serviceAreaChanging) {
if (_serviceArea.path() == _lastServiceAreaPath) { // is it still changing?
setReadyForSync(false);
if (recalcJoinedArea() && calcArrivalAndReturnPath())
setReadyForSync(true);
_serviceAreaChanging = false;
}
} else {
if (_serviceArea.path() !=
_lastServiceAreaPath) // does it started changing?
_serviceAreaChanging = true;
}
// update old values
// if (_missionController != nullptr
// && _missionController->visualItems()->indexOf(_circularSurvey)
// != -1
// && _circularSurvey != nullptr)
// _lastSurveyRefPoint = _circularSurvey->refPoint();
_lastMeasurementAreaPath = _measurementArea.path();
_lastCorridorPath = _corridor.path();
_lastServiceAreaPath = _serviceArea.path();
}
void WimaPlaner::setSyncronizedWithControllerFalse() {
setSyncronizedWithController(false);
}
#ifndef NDEBUG
void WimaPlaner::autoLoadMission() {
loadFromFile("/home/valentin/Desktop/drones/qgroundcontrol/Paths/"
......@@ -861,10 +753,6 @@ void WimaPlaner::autoLoadMission() {
}
#endif
void WimaPlaner::startCalcArrivalAndReturnTimer() {
_calcArrivalAndReturnPathTimer.start();
}
QJsonDocument WimaPlaner::saveToJson(FileType fileType) {
/// This function save all areas (of WimaPlaner) and all mission items (of
/// MissionController) to a QJsonDocument
......
......@@ -44,9 +44,8 @@ public:
Q_PROPERTY(QGeoCoordinate joinedAreaCenter READ joinedAreaCenter CONSTANT)
Q_PROPERTY(WimaBridge *wimaBridge READ wimaBridge WRITE setWimaBridge NOTIFY
wimaBridgeChanged)
Q_PROPERTY(bool syncronized READ syncronizedWithController NOTIFY
syncronizedWithControllerChanged)
Q_PROPERTY(bool readyForSync READ readyForSync NOTIFY readyForSyncChanged)
Q_PROPERTY(bool synchronized READ synchronized NOTIFY synchronizedChanged)
Q_PROPERTY(bool needsUpdate READ needsUpdate NOTIFY needsUpdateChanged)
// Property accessors
PlanMasterController *masterController(void);
......@@ -59,6 +58,8 @@ public:
QString fileExtension(void) const;
QGeoCoordinate joinedAreaCenter(void) const;
WimaBridge *wimaBridge(void);
bool synchronized();
bool needsUpdate();
// Property setters
void setMasterController(PlanMasterController *masterController);
......@@ -68,11 +69,6 @@ public:
void setCurrentPolygonIndex(int index);
void setWimaBridge(WimaBridge *bridge);
// Property acessors
bool syncronizedWithController();
bool readyForSync();
// Member Methodes
Q_INVOKABLE WimaPlaner *thisPointer();
Q_INVOKABLE bool addMeasurementArea();
/// Removes an area from _visualItems
......@@ -84,24 +80,17 @@ public:
/// MissionController
Q_INVOKABLE void removeAll();
/// Recalculates vehicle corridor, flight path, etc.
Q_INVOKABLE bool updateMission();
Q_INVOKABLE bool update();
/// Pushes the generated mission data to the wimaController.
Q_INVOKABLE void pushToWimaController();
Q_INVOKABLE void saveToCurrent();
Q_INVOKABLE void saveToFile(const QString &filename);
Q_INVOKABLE bool loadFromCurrent();
Q_INVOKABLE bool loadFromFile(const QString &filename);
Q_INVOKABLE void resetAllInteractive(void);
Q_INVOKABLE void setInteractive(void);
QJsonDocument saveToJson(FileType fileType);
bool calcShortestPath(const QGeoCoordinate &start,
const QGeoCoordinate &destination,
QVector<QGeoCoordinate> &path);
// static Members
static const char *wimaFileExtension;
static const char *areaItemsName;
......@@ -114,21 +103,14 @@ signals:
void currentPolygonIndexChanged(int index);
void currentFileChanged();
void wimaBridgeChanged();
void syncronizedWithControllerChanged(void);
void readyForSyncChanged(void);
void synchronizedChanged(void);
void needsUpdateChanged(void);
private slots:
void recalcPolygonInteractivity(int index);
bool calcArrivalAndReturnPath(void);
bool recalcJoinedArea();
// called by _updateTimer::timeout signal, updates different mission parts, if
// parameters (e.g. survey or areas) have changed
void updateTimerSlot();
void setSyncronizedWithControllerFalse(void);
void updatePolygonInteractivity(int index);
#ifndef NDEBUG
void autoLoadMission(void);
#endif
void startCalcArrivalAndReturnTimer(void);
private:
signals:
......@@ -137,9 +119,10 @@ signals:
private:
// Member Functions
WimaPlanData toPlanData();
void setSyncronizedWithController(bool sync);
void setReadyForSync(bool ready);
void setJoinedAreaValid(bool valid);
bool shortestPath(const QGeoCoordinate &start,
const QGeoCoordinate &destination,
QVector<QGeoCoordinate> &path);
void setNeedsUpdate(bool needsUpdate);
// Member Variables
PlanMasterController *_masterController;
......@@ -151,8 +134,11 @@ private:
bool _joinedAreaValid;
WimaMeasurementArea _measurementArea;
bool _mAreaChanged;
WimaServiceArea _serviceArea;
bool _sAreaChanged;
WimaCorridor _corridor;
bool _corridorChanged;
// contains all visible areas
QmlObjectListModel _visualItems;
// joined area fromed by _measurementArea, _serviceArea, _corridor
......@@ -162,36 +148,15 @@ private:
// path from last measurement point to land
unsigned long _returnPathLength;
CircularSurvey *_TSComplexItem; // pointer to the CircularSurvey item in
// _missionController.visualItems()
// auto update
QTimer _updateTimer; // on this timers timeout different mission parts will be
// updated, if parameters (e.g. survey or areas) have
// changed
QGeoCoordinate _lastSurveyRefPoint; // stores the SurveyRefPoint of the
// previous timer call
bool _surveyRefChanging; // true if SurveyRefPoint is changing
QVariantList
_lastMeasurementAreaPath; // stores the path of _measurementArea, at the
// time instance of the previous timer call
bool _measurementAreaChanging; // true if the path of the _measurementArea is
// changing
QVariantList _lastCorridorPath; // stores the path of _corridor, at the time
// instance of the previous timer call
bool _corridorChanging; // true if the path of the _corridor is changing
QVariantList _lastServiceAreaPath; // stores the path of _serviceArea, at the
// time instance of the previous timer call
bool _serviceAreaChanging; // true if the path of the _serviceArea is changing
CircularSurvey *_TSComplexItem;
bool _surveyChanged;
// sync stuff
bool _syncronizedWithController; // true if planData is syncronized with
// wimaController
bool _readyForSync; // gets set by updateMission and calcArrivalAndReturnPath
bool _synchronized; // true if planData is synchronized with
// wimaController
bool _needsUpdate; // gets set by updateMission and calcArrivalAndReturnPath
#ifndef NDEBUG
QTimer _autoLoadTimer; // timer to auto load mission after some time, prevents
// seg. faults
#endif
QTimer _calcArrivalAndReturnPathTimer;
};
......@@ -88,13 +88,11 @@ Item {
}
Component.onCompleted: {
if ( !_missionItem.isInitialized ) {
if ( _missionItem.visualTransectPoints.length === 0 ) {
_addInitialPolygon()
_missionItem.isInitialized = true // set isInitialized to true, to trigger _rebuildTransectsPhase1 in the last line
_setRefPoint()
}
_addVisualElements()
}
Component.onDestruction: {
......@@ -111,6 +109,7 @@ Item {
borderColor: "black"
interiorColor: "green"
interiorOpacity: 0.5
visible: !_missionItem.hidePolygon
}
// Transect lines
......
......@@ -27,11 +27,9 @@ Item {
property var areaItem: object
property var _polygon: areaItem
//property var _polyline: areaItem.polyline
signal clicked(int sequenceNumber)
/// Add an initial 4 sided polygon if there is none
/// Add an initial 4 sided polygon if there is none
function _addInitialPolygon() {
......@@ -109,4 +107,30 @@ Item {
interiorOpacity: 1
}
// Depot Point.
Component {
id: depotPointComponent
DragCoordinate {
map: _root.map
qgcView: _root.qgcView
z: QGroundControl.zOrderMapItems
checked: areaItem.interactive
coordinate: areaItem.depot
property var point: areaItem.depot
onRefPointChanged: {
if (point !== coordinate) {
coordinate = point
}
}
onDragReleased: {
areaItem.depot = coordinate
}
}
}
}
......@@ -285,12 +285,15 @@ Rectangle {
anchors.rightMargin: _margins
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
text: qsTr("Sync WiMA")
text: wimaPlaner && wimaPlaner.needsUpdate ? qsTr("Update") : qsTr("Sync.")
enabled: true
visible: wimaPlaner ? wimaPlaner.readyForSync : false
onClicked: {
if (wimaPlaner && wimaPlaner.readyForSync) {
wimaPlaner.pushToWimaController()
if (wimaPlaner){
if (!wimaPlaner.needsUpdate) {
wimaPlaner.pushToWimaController()
} else {
wimaPlaner.update()
}
}
}
......@@ -299,7 +302,7 @@ Rectangle {
from: 0.5
to: 1
loops: Animation.Infinite
running: wimaPlaner ? !wimaPlaner.syncronized && wimaPlaner.readyForSync : false
running: wimaPlaner ? wimaPlaner.needsUpdate : false
alwaysRunToEnd: true
duration: 2000
}
......
......@@ -699,7 +699,7 @@ QGCView {
iconSource: "/res/street.png"
},
{
name: qsTr("Calculate"),
name: qsTr("Update"),
iconSource: "/res/calculator.png"
},
{
......@@ -729,7 +729,7 @@ QGCView {
wimaPlaner.addCorridor();
break
case 4:
wimaPlaner.updateMission();
wimaPlaner.update();
break
case 6:
editorMap.zoomLevel += 0.5
......
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