Commit 5e62e791 authored by Valentin Platzgummer's avatar Valentin Platzgummer

wima planer state machine added

parent dedb0c51
{
"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,
5
],
"type": "SimpleItem"
},
{
"Alpha": 23,
"MinLength": 5,
"NumRuns": 1,
"ReferencePointAlt": 0,
"ReferencePointLat": 47.76807182520187,
"ReferencePointLong": 16.530610531894183,
"Run": 1,
"TransectDistance": 2,
"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.76782117293054,
16.53045952207802,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 3,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76801762181985,
16.531145995440625,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 4,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76812651838593,
16.53090512987649,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 5,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768125250928335,
16.530839239105784,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 6,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768187963203616,
16.531058383792516,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 7,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768204997344334,
16.531049622605572,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 8,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76812144975848,
16.530757670470322,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 9,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76811764852164,
16.530676101820056,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 10,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768222031484335,
16.53104086139957,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 11,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768239065614615,
16.53103210018785,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 12,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768113847226864,
16.530594533208365,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 13,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76811004588309,
16.530512964621895,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 14,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76825609974418,
16.531023338983744,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 15,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76827313388202,
16.53101457776058,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 16,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76810624447235,
16.53043139603398,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 17,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76815568510607,
16.530399305509537,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 18,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76832423627323,
16.530988294070095,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 19,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76834127040819,
16.53097953282404,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 20,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76822245220941,
16.530564330637993,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 21,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76831125125834,
16.530806346203697,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 22,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768358304533436,
16.530970771572267,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 23,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768307202146545,
16.53099705529708,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 24,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76809864148597,
16.530268258893802,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 25,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768102443012644,
16.530349827431266,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 26,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76829016801015,
16.531005816531692,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 27,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768170929071175,
16.531067144987073,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 28,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76812500283788,
16.530906658047133,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 29,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76809124406109,
16.53085697602152,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 30,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76815389493801,
16.53107590617591,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 31,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768136860795146,
16.531084667345684,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 32,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76805748523563,
16.53080729404687,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 33,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76802372639744,
16.53075761214986,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 34,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76811982666054,
16.531093428523086,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 35,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76810279252523,
16.53110218969476,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 36,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76798996754654,
16.530707930317146,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 37,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76795620865596,
16.530658248522045,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 38,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768085758380195,
16.53111095084737,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 39,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76806872423443,
16.5311197120076,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 40,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76792244976166,
16.53060856681793,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 41,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76788869084566,
16.53055888517811,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 42,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768051690105956,
16.531128473148772,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 43,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76803465596775,
16.53113723429756,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 44,
"frame": 3,
"params": [
0,
0,
0,
null,
47.767854931889964,
16.530509203589244,
15
],
"type": "SimpleItem"
}
],
"Refly90Degrees": false,
"TurnAroundDistance": 10,
"VisualTransectPoints": [
[
47.76782117293054,
16.53045952207802
],
[
47.76801762181985,
16.531145995440625
],
[
47.76812651838593,
16.53090512987649
],
[
47.768125250928335,
16.530839239105784
],
[
47.768187963203616,
16.531058383792516
],
[
47.768204997344334,
16.531049622605572
],
[
47.76812144975848,
16.530757670470322
],
[
47.76811764852164,
16.530676101820056
],
[
47.768222031484335,
16.53104086139957
],
[
47.768239065614615,
16.53103210018785
],
[
47.768113847226864,
16.530594533208365
],
[
47.76811004588309,
16.530512964621895
],
[
47.76825609974418,
16.531023338983744
],
[
47.76827313388202,
16.53101457776058
],
[
47.76810624447235,
16.53043139603398
],
[
47.76815568510607,
16.530399305509537
],
[
47.76832423627323,
16.530988294070095
],
[
47.76834127040819,
16.53097953282404
],
[
47.76822245220941,
16.530564330637993
],
[
47.76831125125834,
16.530806346203697
],
[
47.768358304533436,
16.530970771572267
],
[
47.768307202146545,
16.53099705529708
],
[
47.76809864148597,
16.530268258893802
],
[
47.768102443012644,
16.530349827431266
],
[
47.76829016801015,
16.531005816531692
],
[
47.768170929071175,
16.531067144987073
],
[
47.76812500283788,
16.530906658047133
],
[
47.76809124406109,
16.53085697602152
],
[
47.76815389493801,
16.53107590617591
],
[
47.768136860795146,
16.531084667345684
],
[
47.76805748523563,
16.53080729404687
],
[
47.76802372639744,
16.53075761214986
],
[
47.76811982666054,
16.531093428523086
],
[
47.76810279252523,
16.53110218969476
],
[
47.76798996754654,
16.530707930317146
],
[
47.76795620865596,
16.530658248522045
],
[
47.768085758380195,
16.53111095084737
],
[
47.76806872423443,
16.5311197120076
],
[
47.76792244976166,
16.53060856681793
],
[
47.76788869084566,
16.53055888517811
],
[
47.768051690105956,
16.531128473148772
],
[
47.76803465596775,
16.53113723429756
],
[
47.767854931889964,
16.530509203589244
]
],
"version": 1
},
"Type": 1,
"Variant": 0,
"complexItemType": "CircularSurvey",
"polygon": [
[
47.76809580679245,
16.530246122817612
],
[
47.76823933601322,
16.53060087654427
],
[
47.7683711160486,
16.530967006195464
],
[
47.7680076482754,
16.531153949077463
],
[
47.7677855557718,
16.530403347547246
],
[
47.768126518382985,
16.5309051298743
]
],
"type": "ComplexItem",
"version": 1
},
{
"AMSLAltAboveTerrain": 0,
"Altitude": 0,
"AltitudeMode": 1,
"autoContinue": true,
"command": 21,
"doJumpId": 48,
"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
}
{
"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,
5
],
"type": "SimpleItem"
},
{
"Alpha": 23,
"MinLength": 5,
"NumRuns": 1,
"ReferencePointAlt": 0,
"ReferencePointLat": 47.76807182520187,
"ReferencePointLong": 16.530610531894183,
"Run": 1,
"TransectDistance": 2,
"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.76782117293054,
16.53045952207802,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 3,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76801762181985,
16.531145995440625,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 4,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76812651838593,
16.53090512987649,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 5,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768125250928335,
16.530839239105784,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 6,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768187963203616,
16.531058383792516,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 7,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768204997344334,
16.531049622605572,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 8,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76812144975848,
16.530757670470322,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 9,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76811764852164,
16.530676101820056,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 10,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768222031484335,
16.53104086139957,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 11,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768239065614615,
16.53103210018785,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 12,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768113847226864,
16.530594533208365,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 13,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76811004588309,
16.530512964621895,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 14,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76825609974418,
16.531023338983744,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 15,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76827313388202,
16.53101457776058,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 16,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76810624447235,
16.53043139603398,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 17,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76815568510607,
16.530399305509537,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 18,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76832423627323,
16.530988294070095,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 19,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76834127040819,
16.53097953282404,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 20,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76822245220941,
16.530564330637993,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 21,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76831125125834,
16.530806346203697,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 22,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768358304533436,
16.530970771572267,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 23,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768307202146545,
16.53099705529708,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 24,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76809864148597,
16.530268258893802,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 25,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768102443012644,
16.530349827431266,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 26,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76829016801015,
16.531005816531692,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 27,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768170929071175,
16.531067144987073,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 28,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76812500283788,
16.530906658047133,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 29,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76809124406109,
16.53085697602152,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 30,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76815389493801,
16.53107590617591,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 31,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768136860795146,
16.531084667345684,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 32,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76805748523563,
16.53080729404687,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 33,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76802372639744,
16.53075761214986,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 34,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76811982666054,
16.531093428523086,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 35,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76810279252523,
16.53110218969476,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 36,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76798996754654,
16.530707930317146,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 37,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76795620865596,
16.530658248522045,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 38,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768085758380195,
16.53111095084737,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 39,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76806872423443,
16.5311197120076,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 40,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76792244976166,
16.53060856681793,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 41,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76788869084566,
16.53055888517811,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 42,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768051690105956,
16.531128473148772,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 43,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76803465596775,
16.53113723429756,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 44,
"frame": 3,
"params": [
0,
0,
0,
null,
47.767854931889964,
16.530509203589244,
15
],
"type": "SimpleItem"
}
],
"Refly90Degrees": false,
"TurnAroundDistance": 10,
"VisualTransectPoints": [
[
47.76782117293054,
16.53045952207802
],
[
47.76801762181985,
16.531145995440625
],
[
47.76812651838593,
16.53090512987649
],
[
47.768125250928335,
16.530839239105784
],
[
47.768187963203616,
16.531058383792516
],
[
47.768204997344334,
16.531049622605572
],
[
47.76812144975848,
16.530757670470322
],
[
47.76811764852164,
16.530676101820056
],
[
47.768222031484335,
16.53104086139957
],
[
47.768239065614615,
16.53103210018785
],
[
47.768113847226864,
16.530594533208365
],
[
47.76811004588309,
16.530512964621895
],
[
47.76825609974418,
16.531023338983744
],
[
47.76827313388202,
16.53101457776058
],
[
47.76810624447235,
16.53043139603398
],
[
47.76815568510607,
16.530399305509537
],
[
47.76832423627323,
16.530988294070095
],
[
47.76834127040819,
16.53097953282404
],
[
47.76822245220941,
16.530564330637993
],
[
47.76831125125834,
16.530806346203697
],
[
47.768358304533436,
16.530970771572267
],
[
47.768307202146545,
16.53099705529708
],
[
47.76809864148597,
16.530268258893802
],
[
47.768102443012644,
16.530349827431266
],
[
47.76829016801015,
16.531005816531692
],
[
47.768170929071175,
16.531067144987073
],
[
47.76812500283788,
16.530906658047133
],
[
47.76809124406109,
16.53085697602152
],
[
47.76815389493801,
16.53107590617591
],
[
47.768136860795146,
16.531084667345684
],
[
47.76805748523563,
16.53080729404687
],
[
47.76802372639744,
16.53075761214986
],
[
47.76811982666054,
16.531093428523086
],
[
47.76810279252523,
16.53110218969476
],
[
47.76798996754654,
16.530707930317146
],
[
47.76795620865596,
16.530658248522045
],
[
47.768085758380195,
16.53111095084737
],
[
47.76806872423443,
16.5311197120076
],
[
47.76792244976166,
16.53060856681793
],
[
47.76788869084566,
16.53055888517811
],
[
47.768051690105956,
16.531128473148772
],
[
47.76803465596775,
16.53113723429756
],
[
47.767854931889964,
16.530509203589244
]
],
"version": 1
},
"Type": 1,
"Variant": 0,
"complexItemType": "CircularSurvey",
"polygon": [
[
47.76809580679245,
16.530246122817612
],
[
47.76823933601322,
16.53060087654427
],
[
47.7683711160486,
16.530967006195464
],
[
47.7680076482754,
16.531153949077463
],
[
47.7677855557718,
16.530403347547246
],
[
47.768126518382985,
16.5309051298743
]
],
"type": "ComplexItem",
"version": 1
},
{
"AMSLAltAboveTerrain": 0,
"Altitude": 0,
"AltitudeMode": 1,
"autoContinue": true,
"command": 21,
"doJumpId": 48,
"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
}
{
"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,
5
],
"type": "SimpleItem"
},
{
"Alpha": 23,
"MinLength": 5,
"NumRuns": 1,
"ReferencePointAlt": 0,
"ReferencePointLat": 47.76807182520187,
"ReferencePointLong": 16.530610531894183,
"Run": 1,
"TransectDistance": 2,
"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.76782117293054,
16.53045952207802,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 3,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76801762181985,
16.531145995440625,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 4,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76812651838593,
16.53090512987649,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 5,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768125250928335,
16.530839239105784,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 6,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768187963203616,
16.531058383792516,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 7,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768204997344334,
16.531049622605572,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 8,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76812144975848,
16.530757670470322,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 9,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76811764852164,
16.530676101820056,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 10,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768222031484335,
16.53104086139957,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 11,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768239065614615,
16.53103210018785,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 12,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768113847226864,
16.530594533208365,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 13,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76811004588309,
16.530512964621895,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 14,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76825609974418,
16.531023338983744,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 15,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76827313388202,
16.53101457776058,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 16,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76810624447235,
16.53043139603398,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 17,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76815568510607,
16.530399305509537,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 18,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76832423627323,
16.530988294070095,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 19,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76834127040819,
16.53097953282404,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 20,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76822245220941,
16.530564330637993,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 21,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76831125125834,
16.530806346203697,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 22,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768358304533436,
16.530970771572267,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 23,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768307202146545,
16.53099705529708,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 24,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76809864148597,
16.530268258893802,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 25,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768102443012644,
16.530349827431266,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 26,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76829016801015,
16.531005816531692,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 27,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768170929071175,
16.531067144987073,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 28,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76812500283788,
16.530906658047133,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 29,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76809124406109,
16.53085697602152,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 30,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76815389493801,
16.53107590617591,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 31,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768136860795146,
16.531084667345684,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 32,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76805748523563,
16.53080729404687,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 33,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76802372639744,
16.53075761214986,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 34,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76811982666054,
16.531093428523086,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 35,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76810279252523,
16.53110218969476,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 36,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76798996754654,
16.530707930317146,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 37,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76795620865596,
16.530658248522045,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 38,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768085758380195,
16.53111095084737,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 39,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76806872423443,
16.5311197120076,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 40,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76792244976166,
16.53060856681793,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 41,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76788869084566,
16.53055888517811,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 42,
"frame": 3,
"params": [
0,
0,
0,
null,
47.768051690105956,
16.531128473148772,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 43,
"frame": 3,
"params": [
0,
0,
0,
null,
47.76803465596775,
16.53113723429756,
15
],
"type": "SimpleItem"
},
{
"autoContinue": true,
"command": 16,
"doJumpId": 44,
"frame": 3,
"params": [
0,
0,
0,
null,
47.767854931889964,
16.530509203589244,
15
],
"type": "SimpleItem"
}
],
"Refly90Degrees": false,
"TurnAroundDistance": 10,
"VisualTransectPoints": [
[
47.76782117293054,
16.53045952207802
],
[
47.76801762181985,
16.531145995440625
],
[
47.76812651838593,
16.53090512987649
],
[
47.768125250928335,
16.530839239105784
],
[
47.768187963203616,
16.531058383792516
],
[
47.768204997344334,
16.531049622605572
],
[
47.76812144975848,
16.530757670470322
],
[
47.76811764852164,
16.530676101820056
],
[
47.768222031484335,
16.53104086139957
],
[
47.768239065614615,
16.53103210018785
],
[
47.768113847226864,
16.530594533208365
],
[
47.76811004588309,
16.530512964621895
],
[
47.76825609974418,
16.531023338983744
],
[
47.76827313388202,
16.53101457776058
],
[
47.76810624447235,
16.53043139603398
],
[
47.76815568510607,
16.530399305509537
],
[
47.76832423627323,
16.530988294070095
],
[
47.76834127040819,
16.53097953282404
],
[
47.76822245220941,
16.530564330637993
],
[
47.76831125125834,
16.530806346203697
],
[
47.768358304533436,
16.530970771572267
],
[
47.768307202146545,
16.53099705529708
],
[
47.76809864148597,
16.530268258893802
],
[
47.768102443012644,
16.530349827431266
],
[
47.76829016801015,
16.531005816531692
],
[
47.768170929071175,
16.531067144987073
],
[
47.76812500283788,
16.530906658047133
],
[
47.76809124406109,
16.53085697602152
],
[
47.76815389493801,
16.53107590617591
],
[
47.768136860795146,
16.531084667345684
],
[
47.76805748523563,
16.53080729404687
],
[
47.76802372639744,
16.53075761214986
],
[
47.76811982666054,
16.531093428523086
],
[
47.76810279252523,
16.53110218969476
],
[
47.76798996754654,
16.530707930317146
],
[
47.76795620865596,
16.530658248522045
],
[
47.768085758380195,
16.53111095084737
],
[
47.76806872423443,
16.5311197120076
],
[
47.76792244976166,
16.53060856681793
],
[
47.76788869084566,
16.53055888517811
],
[
47.768051690105956,
16.531128473148772
],
[
47.76803465596775,
16.53113723429756
],
[
47.767854931889964,
16.530509203589244
]
],
"version": 1
},
"Type": 1,
"Variant": 0,
"complexItemType": "CircularSurvey",
"polygon": [
[
47.76809580679245,
16.530246122817612
],
[
47.76823933601322,
16.53060087654427
],
[
47.7683711160486,
16.530967006195464
],
[
47.7680076482754,
16.531153949077463
],
[
47.7677855557718,
16.530403347547246
],
[
47.768126518382985,
16.5309051298743
]
],
"type": "ComplexItem",
"version": 1
},
{
"AMSLAltAboveTerrain": 0,
"Altitude": 0,
"AltitudeMode": 1,
"autoContinue": true,
"command": 21,
"doJumpId": 48,
"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
}
...@@ -454,6 +454,7 @@ HEADERS += \ ...@@ -454,6 +454,7 @@ HEADERS += \
src/Wima/Snake/SnakeTileLocal.h \ src/Wima/Snake/SnakeTileLocal.h \
src/Wima/Snake/SnakeTiles.h \ src/Wima/Snake/SnakeTiles.h \
src/Wima/Snake/SnakeTilesLocal.h \ src/Wima/Snake/SnakeTilesLocal.h \
src/Wima/StateMachine.h \
src/Wima/WaypointManager/AreaInterface.h \ src/Wima/WaypointManager/AreaInterface.h \
src/Wima/WaypointManager/DefaultManager.h \ src/Wima/WaypointManager/DefaultManager.h \
src/Wima/WaypointManager/GenericWaypointManager.h \ src/Wima/WaypointManager/GenericWaypointManager.h \
...@@ -515,6 +516,7 @@ SOURCES += \ ...@@ -515,6 +516,7 @@ SOURCES += \
src/Wima/Snake/NemoInterface.cpp \ src/Wima/Snake/NemoInterface.cpp \
src/Wima/Snake/QNemoProgress.cc \ src/Wima/Snake/QNemoProgress.cc \
src/Wima/Snake/SnakeTile.cpp \ src/Wima/Snake/SnakeTile.cpp \
src/Wima/StateMachine.cpp \
src/Wima/WaypointManager/AreaInterface.cpp \ src/Wima/WaypointManager/AreaInterface.cpp \
src/Wima/WaypointManager/DefaultManager.cpp \ src/Wima/WaypointManager/DefaultManager.cpp \
src/Wima/WaypointManager/GenericWaypointManager.cpp \ src/Wima/WaypointManager/GenericWaypointManager.cpp \
......
...@@ -3,19 +3,25 @@ ...@@ -3,19 +3,25 @@
// QGC // QGC
#include "JsonHelper.h" #include "JsonHelper.h"
#include "QGCApplication.h" #include "QGCApplication.h"
#include "QGCLoggingCategory.h"
// Wima // Wima
#include "snake.h" #include "snake.h"
#define CLIPPER_SCALE 1000000 #define CLIPPER_SCALE 1000000
#include "clipper/clipper.hpp" #include "clipper/clipper.hpp"
template <int k> ClipperLib::cInt get(ClipperLib::IntPoint &p);
template <> ClipperLib::cInt get<0>(ClipperLib::IntPoint &p) { return p.X; }
template <> ClipperLib::cInt get<1>(ClipperLib::IntPoint &p) { return p.Y; }
#include "Geometry/GenericCircle.h" #include "Geometry/GenericCircle.h"
#include "Snake/SnakeTile.h"
// boost // boost
#include <boost/units/io.hpp> #include <boost/units/io.hpp>
#include <boost/units/systems/si.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 { template <class Functor> class CommandRAII {
public: public:
CommandRAII(Functor f) : fun(f) {} CommandRAII(Functor f) : fun(f) {}
...@@ -30,15 +36,13 @@ constexpr typename std::underlying_type<T>::type integral(T value) { ...@@ -30,15 +36,13 @@ constexpr typename std::underlying_type<T>::type integral(T value) {
return static_cast<typename std::underlying_type<T>::type>(value); return static_cast<typename std::underlying_type<T>::type>(value);
} }
bool circularTransects(const QGeoCoordinate &ref, const QGeoCoordinate &depot, bool circularTransects(const snake::FPolygon &polygon, snake::Length deltaR,
bool useDepot, const QList<QGeoCoordinate> &polygon, snake::Angle deltaAlpha, snake::Length minLength,
snake::Length deltaR, snake::Angle deltaAlpha, snake::Transects &transects);
snake::Length minLength, snake::Transects &transects);
bool linearTransects(const QGeoCoordinate &origin, const QGeoCoordinate &depot, bool linearTransects(const snake::FPolygon &polygon, snake::Length distance,
bool useDepot, const QList<QGeoCoordinate> &polygon, snake::Angle angle, snake::Length minLength,
snake::Length distance, snake::Angle angle, snake::Transects &transects);
snake::Length minLength, snake::Transects &transects);
const char *CircularSurvey::settingsGroup = "CircularSurvey"; const char *CircularSurvey::settingsGroup = "CircularSurvey";
const char *CircularSurvey::transectDistanceName = "TransectDistance"; const char *CircularSurvey::transectDistanceName = "TransectDistance";
...@@ -80,10 +84,6 @@ CircularSurvey::CircularSurvey(Vehicle *vehicle, bool flyView, ...@@ -80,10 +84,6 @@ CircularSurvey::CircularSurvey(Vehicle *vehicle, bool flyView,
&CircularSurvey::_rebuildTransects); &CircularSurvey::_rebuildTransects);
connect(this, &CircularSurvey::refPointChanged, this, connect(this, &CircularSurvey::refPointChanged, this,
&CircularSurvey::_rebuildTransects); &CircularSurvey::_rebuildTransects);
connect(this, &CircularSurvey::depotChanged, this,
&CircularSurvey::_rebuildTransects);
connect(this, &CircularSurvey::safeAreaChanged, this,
&CircularSurvey::_rebuildTransects);
connect(&this->_type, &Fact::rawValueChanged, this, connect(&this->_type, &Fact::rawValueChanged, this,
&CircularSurvey::_rebuildTransects); &CircularSurvey::_rebuildTransects);
connect(&this->_variant, &Fact::rawValueChanged, this, connect(&this->_variant, &Fact::rawValueChanged, this,
...@@ -93,19 +93,23 @@ CircularSurvey::CircularSurvey(Vehicle *vehicle, bool flyView, ...@@ -93,19 +93,23 @@ CircularSurvey::CircularSurvey(Vehicle *vehicle, bool flyView,
connect(&this->_numRuns, &Fact::rawValueChanged, this, connect(&this->_numRuns, &Fact::rawValueChanged, this,
&CircularSurvey::_rebuildTransects); &CircularSurvey::_rebuildTransects);
// Areas.
connect(this, &CircularSurvey::measurementAreaChanged, this,
&CircularSurvey::_rebuildTransects);
connect(this, &CircularSurvey::joinedAreaChanged, this,
&CircularSurvey::_rebuildTransects);
// Connect worker. // Connect worker.
connect(this->_pWorker.get(), &RoutingThread::result, this, connect(this->_pWorker.get(), &RoutingThread::result, this,
&CircularSurvey::_setTransects); &CircularSurvey::_setTransects);
connect(this->_pWorker.get(), &RoutingThread::calculatingChanged, this, connect(this->_pWorker.get(), &RoutingThread::calculatingChanged, this,
&CircularSurvey::calculatingChanged); &CircularSurvey::calculatingChanged);
this->_transectsDirty = false; this->_transectsDirty = true;
} }
CircularSurvey::~CircularSurvey() {} CircularSurvey::~CircularSurvey() {}
void CircularSurvey::resetReference() { void CircularSurvey::resetReference() { setRefPoint(_mArea.center()); }
setRefPoint(_surveyAreaPolygon.center());
}
void CircularSurvey::reverse() { void CircularSurvey::reverse() {
this->_state = STATE::REVERSE; this->_state = STATE::REVERSE;
...@@ -133,12 +137,6 @@ QList<QString> CircularSurvey::variantNames() const { return _variantNames; } ...@@ -133,12 +137,6 @@ QList<QString> CircularSurvey::variantNames() const { return _variantNames; }
QList<QString> CircularSurvey::runNames() const { return _runNames; } QList<QString> CircularSurvey::runNames() const { return _runNames; }
QGeoCoordinate CircularSurvey::depot() const { return this->_depot; }
QList<QGeoCoordinate> CircularSurvey::safeArea() const {
return this->_safeArea;
}
const QList<QList<QGeoCoordinate>> &CircularSurvey::rawTransects() const { const QList<QList<QGeoCoordinate>> &CircularSurvey::rawTransects() const {
return this->_rawTransects; return this->_rawTransects;
} }
...@@ -150,18 +148,31 @@ void CircularSurvey::setHidePolygon(bool hide) { ...@@ -150,18 +148,31 @@ void CircularSurvey::setHidePolygon(bool hide) {
} }
} }
void CircularSurvey::setDepot(const QGeoCoordinate &depot) { void CircularSurvey::setMeasurementArea(const WimaMeasurementAreaData &mArea) {
if (this->_depot != depot) { if (this->_mArea != mArea) {
this->_depot = depot; this->_mArea = mArea;
this->_depot.setAltitude(0); emit measurementAreaChanged();
emit depotChanged(); }
}
void CircularSurvey::setJoinedArea(const WimaJoinedAreaData &jArea) {
if (this->_jArea != jArea) {
this->_jArea = jArea;
emit joinedAreaChanged();
} }
} }
void CircularSurvey::setSafeArea(const QList<QGeoCoordinate> &safeArea) { void CircularSurvey::setMeasurementArea(const WimaMeasurementArea &mArea) {
if (this->_safeArea != safeArea) { if (this->_mArea != mArea) {
this->_safeArea = safeArea; this->_mArea = mArea;
emit safeAreaChanged(); emit measurementAreaChanged();
}
}
void CircularSurvey::setJoinedArea(const WimaJoinedArea &jArea) {
if (this->_jArea != jArea) {
this->_jArea = jArea;
emit joinedAreaChanged();
} }
} }
...@@ -358,6 +369,8 @@ void CircularSurvey::_changeRun() { ...@@ -358,6 +369,8 @@ void CircularSurvey::_changeRun() {
} }
void CircularSurvey::_updateWorker() { void CircularSurvey::_updateWorker() {
// Mark transects as dirty.
this->_transectsDirty = true;
// Reset data. // Reset data.
this->_transects.clear(); this->_transects.clear();
this->_rawTransects.clear(); this->_rawTransects.clear();
...@@ -369,15 +382,51 @@ void CircularSurvey::_updateWorker() { ...@@ -369,15 +382,51 @@ void CircularSurvey::_updateWorker() {
// Prepare data. // Prepare data.
auto ref = this->_referencePoint; auto ref = this->_referencePoint;
auto polygon = this->_surveyAreaPolygon.coordinateList(); auto geoPolygon = this->_mArea.coordinateList();
for (auto &v : polygon) { for (auto &v : geoPolygon) {
v.setAltitude(0); v.setAltitude(0);
} }
auto safeArea = this->_safeArea; auto pPolygon = std::make_shared<snake::FPolygon>();
for (auto &v : safeArea) { snake::areaToEnu(ref, geoPolygon, *pPolygon);
// Progress and tiles.
const auto &progress = this->_mArea.progress();
const auto *tiles = this->_mArea.tiles();
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);
pPolygon->inners().push_back(std::move(tileENU.outer()));
} else {
qCWarning(CircularSurveyLog)
<< "CS::_updateWorker(): progress.size() != tiles->count().";
return;
}
}
}
} else {
qCWarning(CircularSurveyLog)
<< "CS::_updateWorker(): progress.size() != tiles->count().";
return;
}
bg::correct(*pPolygon);
// Convert safe area.
auto geoDepot = this->_jArea.center();
auto geoSafeArea = this->_jArea.coordinateList();
if (!geoDepot.isValid() || !(geoSafeArea.size() >= 3)) {
return;
}
for (auto &v : geoSafeArea) {
v.setAltitude(0); v.setAltitude(0);
} }
auto depot = this->_depot; snake::FPolygon safeArea;
snake::areaToEnu(ref, geoSafeArea, safeArea);
snake::FPoint depot;
snake::toENU(ref, geoDepot, depot);
// Routing par. // Routing par.
RoutingParameter par; RoutingParameter par;
...@@ -393,15 +442,8 @@ void CircularSurvey::_updateWorker() { ...@@ -393,15 +442,8 @@ void CircularSurvey::_updateWorker() {
} }
par.numRuns = this->_numRuns.rawValue().toUInt(); par.numRuns = this->_numRuns.rawValue().toUInt();
// Convert safe area.
auto &safeAreaENU = par.safeArea; auto &safeAreaENU = par.safeArea;
bool useDepot = false; snake::areaToEnu(ref, geoSafeArea, safeAreaENU);
if (this->_depot.isValid() && this->_safeArea.size() >= 3) {
useDepot = true;
snake::areaToEnu(ref, safeArea, safeAreaENU);
} else {
snake::areaToEnu(ref, polygon, safeAreaENU);
}
// Fetch transect parameter. // Fetch transect parameter.
auto distance = snake::Length(this->_transectDistance.rawValue().toDouble() * auto distance = snake::Length(this->_transectDistance.rawValue().toDouble() *
...@@ -416,10 +458,11 @@ void CircularSurvey::_updateWorker() { ...@@ -416,10 +458,11 @@ void CircularSurvey::_updateWorker() {
// Clip angle. // Clip angle.
if (alpha >= snake::Angle(0.3 * bu::degree::degree) && if (alpha >= snake::Angle(0.3 * bu::degree::degree) &&
alpha <= snake::Angle(45 * bu::degree::degree)) { alpha <= snake::Angle(45 * bu::degree::degree)) {
auto generator = [ref, depot, useDepot, polygon, distance, alpha, auto generator = [depot, pPolygon, distance, alpha,
minLength](snake::Transects &transects) -> bool { minLength](snake::Transects &transects) -> bool {
return circularTransects(ref, depot, useDepot, polygon, distance, alpha, transects.push_back(snake::FLineString{depot});
minLength, transects); return circularTransects(*pPolygon, distance, alpha, minLength,
transects);
}; };
// Start routing worker. // Start routing worker.
this->_pWorker->route(par, generator); this->_pWorker->route(par, generator);
...@@ -431,20 +474,18 @@ void CircularSurvey::_updateWorker() { ...@@ -431,20 +474,18 @@ void CircularSurvey::_updateWorker() {
} }
} }
} else if (this->_type.rawValue().toUInt() == integral(Type::Linear)) { } else if (this->_type.rawValue().toUInt() == integral(Type::Linear)) {
auto generator = [ref, depot, useDepot, polygon, distance, alpha, auto generator = [depot, pPolygon, distance, alpha,
minLength](snake::Transects &transects) -> bool { minLength](snake::Transects &transects) -> bool {
return linearTransects(ref, depot, useDepot, polygon, distance, alpha, transects.push_back(snake::FLineString{depot});
minLength, transects); return linearTransects(*pPolygon, distance, alpha, minLength, transects);
}; };
// Start routing worker. // Start routing worker.
this->_pWorker->route(par, generator); this->_pWorker->route(par, generator);
} else { } else {
qWarning() qCWarning(CircularSurveyLog)
<< "CircularSurvey::rebuildTransectsPhase1(): invalid survey type:" << "CircularSurvey::rebuildTransectsPhase1(): invalid survey type:"
<< this->_type.rawValue().toUInt(); << this->_type.rawValue().toUInt();
} }
// Mark transects as dirty.
this->_transectsDirty = true;
} }
void CircularSurvey::_changeVariantRunWorker() { void CircularSurvey::_changeVariantRunWorker() {
...@@ -494,9 +535,10 @@ void CircularSurvey::_changeVariantRunWorker() { ...@@ -494,9 +535,10 @@ void CircularSurvey::_changeVariantRunWorker() {
} }
} else { // error } else { // error
qWarning() << "Variant or run out of bounds (variant = " << variant qCWarning(CircularSurveyLog)
<< ", run = " << run << ")."; << "Variant or run out of bounds (variant = " << variant
qWarning() << "Resetting variant and run."; << ", run = " << run << ").";
qCWarning(CircularSurveyLog) << "Resetting variant and run.";
disconnect(&this->_variant, &Fact::rawValueChanged, this, disconnect(&this->_variant, &Fact::rawValueChanged, this,
&CircularSurvey::_changeVariant); &CircularSurvey::_changeVariant);
...@@ -552,14 +594,8 @@ void CircularSurvey::_storeWorker() { ...@@ -552,14 +594,8 @@ void CircularSurvey::_storeWorker() {
const auto &pRoutingData = this->_pRoutingData; const auto &pRoutingData = this->_pRoutingData;
const auto &ori = this->_referencePoint; const auto &ori = this->_referencePoint;
const auto &transectsENU = pRoutingData->transects; const auto &transectsENU = pRoutingData->transects;
std::size_t startIdx = 0;
bool depotValid = false;
if (transectsENU.size() > 0 && transectsENU.front().size() == 1) {
depotValid = true;
startIdx = 1;
}
QList<QList<QGeoCoordinate>> rawTransects; QList<QList<QGeoCoordinate>> rawTransects;
for (std::size_t i = startIdx; i < transectsENU.size(); ++i) { for (std::size_t i = 0; i < transectsENU.size(); ++i) {
const auto &t = transectsENU[i]; const auto &t = transectsENU[i];
rawTransects.append(QList<QGeoCoordinate>()); rawTransects.append(QList<QGeoCoordinate>());
auto trGeo = rawTransects.back(); auto trGeo = rawTransects.back();
...@@ -585,7 +621,7 @@ void CircularSurvey::_storeWorker() { ...@@ -585,7 +621,7 @@ void CircularSurvey::_storeWorker() {
if (info.size() > 1) { if (info.size() > 1) {
// Find index of first waypoint. // Find index of first waypoint.
std::size_t idxFirst = 0; std::size_t idxFirst = 0;
const auto &infoFirst = depotValid ? info.at(1) : info.at(0); const auto &infoFirst = info.at(1);
const auto &firstTransect = transectsENU[infoFirst.index]; const auto &firstTransect = transectsENU[infoFirst.index];
if (firstTransect.size() > 0) { if (firstTransect.size() > 0) {
const auto &firstWaypoint = const auto &firstWaypoint =
...@@ -623,13 +659,16 @@ void CircularSurvey::_storeWorker() { ...@@ -623,13 +659,16 @@ void CircularSurvey::_storeWorker() {
list.append(CoordInfo_t{c, CoordTypeInterior}); list.append(CoordInfo_t{c, CoordTypeInterior});
} }
} else { } else {
qWarning() << "CS::_storeWorker(): lastTransect.size() == 0"; qCWarning(CircularSurveyLog)
<< "CS::_storeWorker(): lastTransect.size() == 0";
} }
} else { } else {
qWarning() << "CS::_storeWorker(): firstTransect.size() == 0"; qCWarning(CircularSurveyLog)
<< "CS::_storeWorker(): firstTransect.size() == 0";
} }
} else { } else {
qWarning() << "CS::_storeWorker(): transectsInfo.size() <= 1"; qCWarning(CircularSurveyLog)
<< "CS::_storeWorker(): transectsInfo.size() <= 1";
} }
} }
// Remove empty runs. // Remove empty runs.
...@@ -713,52 +752,39 @@ bool CircularSurvey::readyForSave() const { ...@@ -713,52 +752,39 @@ bool CircularSurvey::readyForSave() const {
double CircularSurvey::additionalTimeDelay() const { return 0; } double CircularSurvey::additionalTimeDelay() const { return 0; }
void CircularSurvey::_rebuildTransectsPhase1(void) { void CircularSurvey::_rebuildTransectsPhase1(void) {
qWarning() << "_rebuildTransectsPhase1: TODO: remove depot valid stuff";
#ifdef SHOW_CIRCULAR_SURVEY_TIME
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
#endif
switch (this->_state) { switch (this->_state) {
case STATE::STORE: case STATE::STORE:
#ifdef SHOW_CIRCULAR_SURVEY_TIME qCWarning(CircularSurveyLog) << "CS::rebuildTransectsPhase1: store.";
qWarning() << "CS::rebuildTransectsPhase1: store.";
#endif
this->_storeWorker(); this->_storeWorker();
break; break;
case STATE::VARIANT_CHANGE: case STATE::VARIANT_CHANGE:
#ifdef SHOW_CIRCULAR_SURVEY_TIME qCWarning(CircularSurveyLog)
qWarning() << "CS::rebuildTransectsPhase1: variant change."; << "CS::rebuildTransectsPhase1: variant change.";
#endif
this->_changeVariantRunWorker(); this->_changeVariantRunWorker();
break; break;
case STATE::RUN_CHANGE: case STATE::RUN_CHANGE:
#ifdef SHOW_CIRCULAR_SURVEY_TIME qCWarning(CircularSurveyLog) << "CS::rebuildTransectsPhase1: run change.";
qWarning() << "CS::rebuildTransectsPhase1: run change.";
#endif
this->_changeVariantRunWorker(); this->_changeVariantRunWorker();
break; break;
case STATE::REVERSE: case STATE::REVERSE:
#ifdef SHOW_CIRCULAR_SURVEY_TIME qCWarning(CircularSurveyLog) << "CS::rebuildTransectsPhase1: reverse.";
qWarning() << "CS::rebuildTransectsPhase1: reverse.";
#endif
this->_reverseWorker(); this->_reverseWorker();
break; break;
case STATE::DEFAULT: case STATE::DEFAULT:
#ifdef SHOW_CIRCULAR_SURVEY_TIME qCWarning(CircularSurveyLog) << "CS::rebuildTransectsPhase1: update.";
qWarning() << "CS::rebuildTransectsPhase1: update.";
#endif
this->_updateWorker(); this->_updateWorker();
break; break;
} }
this->_state = STATE::DEFAULT; this->_state = STATE::DEFAULT;
#ifdef SHOW_CIRCULAR_SURVEY_TIME qCWarning(CircularSurveyLog)
qWarning() << "CS::rebuildTransectsPhase1(): " << "CS::rebuildTransectsPhase1(): "
<< std::chrono::duration_cast<std::chrono::milliseconds>( << std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start) std::chrono::high_resolution_clock::now() - start)
.count() .count()
<< " ms"; << " ms";
#endif
} }
void CircularSurvey::_recalcComplexDistance() { void CircularSurvey::_recalcComplexDistance() {
...@@ -798,54 +824,47 @@ bool CircularSurvey::calculating() const { ...@@ -798,54 +824,47 @@ bool CircularSurvey::calculating() const {
return this->_pWorker->calculating(); return this->_pWorker->calculating();
} }
bool circularTransects(const QGeoCoordinate &ref, const QGeoCoordinate &depot, bool circularTransects(const snake::FPolygon &polygon, snake::Length deltaR,
bool useDepot, const QList<QGeoCoordinate> &polygon, snake::Angle deltaAlpha, snake::Length minLength,
snake::Length deltaR, snake::Angle deltaAlpha, snake::Transects &transects) {
snake::Length minLength, snake::Transects &transects) {
#ifdef SHOW_CIRCULAR_SURVEY_TIME
auto s1 = std::chrono::high_resolution_clock::now(); auto s1 = std::chrono::high_resolution_clock::now();
#endif
// Check preconitions // Check preconitions
if (polygon.size() >= 3) { if (polygon.outer().size() >= 3) {
using namespace boost::units; using namespace boost::units;
// Convert geo polygon to ENU polygon. // Convert geo polygon to ENU polygon.
snake::FPolygon polygonENU; snake::FPoint origin{0, 0};
snake::FPoint originENU{0, 0};
snake::FPoint depotENU{0, 0};
snake::areaToEnu(ref, polygon, polygonENU);
snake::toENU(ref, ref, originENU);
snake::toENU(ref, depot, depotENU);
std::string error; std::string error;
// Check validity. // Check validity.
if (!bg::is_valid(polygonENU, error)) { if (!bg::is_valid(polygon, error)) {
#ifdef DEBUG_CIRCULAR_SURVEY qCWarning(CircularSurveyLog) << "CS::circularTransects(): "
qWarning() << "CS::circularTransects(): " "invalid polygon.";
"invalid polygon."; qCWarning(CircularSurveyLog) << error.c_str();
qWarning() << error.c_str();
std::stringstream ss; std::stringstream ss;
ss << bg::wkt(polygonENU); ss << bg::wkt(polygon);
qWarning() << ss.str().c_str(); qCWarning(CircularSurveyLog) << ss.str().c_str();
#endif
} else { } else {
// Calculate polygon distances and angles. // Calculate polygon distances and angles.
std::vector<snake::Length> distances; std::vector<snake::Length> distances;
distances.reserve(polygonENU.outer().size()); distances.reserve(polygon.outer().size());
std::vector<snake::Angle> angles; std::vector<snake::Angle> angles;
angles.reserve(polygonENU.outer().size()); angles.reserve(polygon.outer().size());
//#ifdef DEBUG_CIRCULAR_SURVEY //#ifdef DEBUG_CIRCULAR_SURVEY
// qWarning() << "CS::circularTransects():"; // qCWarning(CircularSurveyLog) << "CS::circularTransects():";
//#endif //#endif
for (const auto &p : polygonENU.outer()) { for (const auto &p : polygon.outer()) {
snake::Length distance = bg::distance(originENU, p) * si::meter; snake::Length distance = bg::distance(origin, p) * si::meter;
distances.push_back(distance); distances.push_back(distance);
snake::Angle alpha = (std::atan2(p.get<1>(), p.get<0>())) * si::radian; 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; alpha = alpha < 0 * si::radian ? alpha + 2 * M_PI * si::radian : alpha;
angles.push_back(alpha); angles.push_back(alpha);
//#ifdef DEBUG_CIRCULAR_SURVEY //#ifdef DEBUG_CIRCULAR_SURVEY
// qWarning() << "distances, angles, coordinates:"; // qCWarning(CircularSurveyLog) << "distances, angles,
// qWarning() << to_string(distance).c_str(); // coordinates:"; qCWarning(CircularSurveyLog) <<
// qWarning() << to_string(snake::Degree(alpha)).c_str(); // to_string(distance).c_str(); qCWarning(CircularSurveyLog) <<
// qWarning() << "x = " << p.get<0>() << "y = " << p.get<1>(); // to_string(snake::Degree(alpha)).c_str();
// qCWarning(CircularSurveyLog) << "x = " << p.get<0>() << "y = "
// << p.get<1>();
//#endif //#endif
} }
...@@ -853,8 +872,8 @@ bool circularTransects(const QGeoCoordinate &ref, const QGeoCoordinate &depot, ...@@ -853,8 +872,8 @@ bool circularTransects(const QGeoCoordinate &ref, const QGeoCoordinate &depot,
snake::Angle alpha1(0 * degree::degree); snake::Angle alpha1(0 * degree::degree);
snake::Angle alpha2(360 * degree::degree); snake::Angle alpha2(360 * degree::degree);
// Determine r_min by successive approximation // Determine r_min by successive approximation
if (!bg::within(originENU, polygonENU)) { if (!bg::within(origin, polygon.outer())) {
rMin = bg::distance(originENU, polygonENU) * si::meter; rMin = bg::distance(origin, polygon) * si::meter;
} }
auto rMax = (*std::max_element(distances.begin(), auto rMax = (*std::max_element(distances.begin(),
...@@ -865,9 +884,9 @@ bool circularTransects(const QGeoCoordinate &ref, const QGeoCoordinate &depot, ...@@ -865,9 +884,9 @@ bool circularTransects(const QGeoCoordinate &ref, const QGeoCoordinate &depot,
ClipperLib::cInt(std::round(rMin.value() * CLIPPER_SCALE)); ClipperLib::cInt(std::round(rMin.value() * CLIPPER_SCALE));
const auto deltaRScaled = const auto deltaRScaled =
ClipperLib::cInt(std::round(deltaR.value() * CLIPPER_SCALE)); ClipperLib::cInt(std::round(deltaR.value() * CLIPPER_SCALE));
auto originScaled = ClipperLib::IntPoint{ auto originScaled =
ClipperLib::cInt(std::round(originENU.get<0>())), ClipperLib::IntPoint{ClipperLib::cInt(std::round(origin.get<0>())),
ClipperLib::cInt(std::round(originENU.get<1>()))}; ClipperLib::cInt(std::round(origin.get<1>()))};
// Generate circle sectors. // Generate circle sectors.
auto rScaled = rMinScaled; auto rScaled = rMinScaled;
...@@ -876,15 +895,19 @@ bool circularTransects(const QGeoCoordinate &ref, const QGeoCoordinate &depot, ...@@ -876,15 +895,19 @@ bool circularTransects(const QGeoCoordinate &ref, const QGeoCoordinate &depot,
const auto nSectors = const auto nSectors =
long(std::round(((alpha2 - alpha1) / deltaAlpha).value())); long(std::round(((alpha2 - alpha1) / deltaAlpha).value()));
//#ifdef DEBUG_CIRCULAR_SURVEY //#ifdef DEBUG_CIRCULAR_SURVEY
// qWarning() << "CS::circularTransects(): sector parameres:"; // qCWarning(CircularSurveyLog) << "CS::circularTransects(): sector
// qWarning() << "alpha1: " << // parameres:"; qCWarning(CircularSurveyLog) << "alpha1: " <<
// to_string(snake::Degree(alpha1)).c_str(); qWarning() << "alpha2: // to_string(snake::Degree(alpha1)).c_str();
// qCWarning(CircularSurveyLog) << "alpha2:
// " // "
// << to_string(snake::Degree(alpha2)).c_str(); qWarning() << "n: " // << to_string(snake::Degree(alpha2)).c_str();
// << to_string((alpha2 - alpha1) / deltaAlpha).c_str(); qWarning() // qCWarning(CircularSurveyLog) << "n: "
// << "nSectors: " << nSectors; qWarning() << "rMin: " << // << to_string((alpha2 - alpha1) / deltaAlpha).c_str();
// to_string(rMin).c_str(); qWarning() << "rMax: " << // qCWarning(CircularSurveyLog)
// to_string(rMax).c_str(); qWarning() << "nTran: " << nTran; // << "nSectors: " << nSectors; qCWarning(CircularSurveyLog) <<
// "rMin: " << to_string(rMin).c_str(); qCWarning(CircularSurveyLog)
// << "rMax: " << to_string(rMax).c_str();
// qCWarning(CircularSurveyLog) << "nTran: " << nTran;
//#endif //#endif
using ClipperCircle = using ClipperCircle =
GenericCircle<ClipperLib::cInt, ClipperLib::IntPoint>; GenericCircle<ClipperLib::cInt, ClipperLib::IntPoint>;
...@@ -896,7 +919,7 @@ bool circularTransects(const QGeoCoordinate &ref, const QGeoCoordinate &depot, ...@@ -896,7 +919,7 @@ bool circularTransects(const QGeoCoordinate &ref, const QGeoCoordinate &depot,
// Clip sectors to polygonENU. // Clip sectors to polygonENU.
ClipperLib::Path polygonClipper; ClipperLib::Path polygonClipper;
snake::FPolygon shrinked; snake::FPolygon shrinked;
snake::offsetPolygon(polygonENU, shrinked, -0.3); snake::offsetPolygon(polygon, shrinked, -0.3);
auto &outer = shrinked.outer(); auto &outer = shrinked.outer();
polygonClipper.reserve(outer.size()); polygonClipper.reserve(outer.size());
for (auto it = outer.begin(); it < outer.end() - 1; ++it) { for (auto it = outer.begin(); it < outer.end() - 1; ++it) {
...@@ -911,11 +934,31 @@ bool circularTransects(const QGeoCoordinate &ref, const QGeoCoordinate &depot, ...@@ -911,11 +934,31 @@ bool circularTransects(const QGeoCoordinate &ref, const QGeoCoordinate &depot,
clipper.Execute(ClipperLib::ctIntersection, transectsClipper, clipper.Execute(ClipperLib::ctIntersection, transectsClipper,
ClipperLib::pftNonZero, ClipperLib::pftNonZero); ClipperLib::pftNonZero, ClipperLib::pftNonZero);
// Subtract holes.
if (polygon.inners().size() > 0) {
vector<ClipperLib::Path> processedTiles;
for (const auto &h : polygon.inners()) {
ClipperLib::Path path;
for (const auto &v : h) {
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(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 // Extract transects from PolyTree and convert them to
// BoostLineString // BoostLineString
if (useDepot) {
transects.push_back(snake::FLineString{depotENU});
}
for (const auto &child : transectsClipper.Childs) { for (const auto &child : transectsClipper.Childs) {
snake::FLineString transect; snake::FLineString transect;
transect.reserve(child->Contour.size()); transect.reserve(child->Contour.size());
...@@ -926,6 +969,7 @@ bool circularTransects(const QGeoCoordinate &ref, const QGeoCoordinate &depot, ...@@ -926,6 +969,7 @@ bool circularTransects(const QGeoCoordinate &ref, const QGeoCoordinate &depot,
} }
transects.push_back(transect); transects.push_back(transect);
} }
// Join sectors which where slit due to clipping. // Join sectors which where slit due to clipping.
const double th = 0.01; const double th = 0.01;
for (auto ito = transects.begin(); ito < transects.end(); ++ito) { for (auto ito = transects.begin(); ito < transects.end(); ++ito) {
...@@ -972,9 +1016,9 @@ bool circularTransects(const QGeoCoordinate &ref, const QGeoCoordinate &depot, ...@@ -972,9 +1016,9 @@ bool circularTransects(const QGeoCoordinate &ref, const QGeoCoordinate &depot,
} }
} }
} }
// Remove short transects // Remove short transects
auto begin = useDepot ? transects.begin() + 1 : transects.begin(); for (auto it = transects.begin(); it < transects.end();) {
for (auto it = begin; it < transects.end();) {
if (bg::length(*it) < minLength.value()) { if (bg::length(*it) < minLength.value()) {
it = transects.erase(it); it = transects.erase(it);
} else { } else {
...@@ -982,85 +1026,42 @@ bool circularTransects(const QGeoCoordinate &ref, const QGeoCoordinate &depot, ...@@ -982,85 +1026,42 @@ bool circularTransects(const QGeoCoordinate &ref, const QGeoCoordinate &depot,
} }
} }
if (!useDepot) { qCWarning(CircularSurveyLog)
// Move transect with min. distance to the front. << "CS::circularTransects(): transect gen. time: "
auto minDist = std::numeric_limits<double>::max(); << std::chrono::duration_cast<std::chrono::milliseconds>(
auto minIt = transects.begin(); std::chrono::high_resolution_clock::now() - s1)
bool reverse = false; .count()
for (auto it = transects.begin(); it < transects.end(); ++it) { << " ms";
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 != transects.begin()) {
auto minTransect = *minIt;
if (reverse) {
snake::FLineString rev;
for (auto it = minTransect.end() - 1; it >= minTransect.begin();
--it) {
rev.push_back(*it);
}
minTransect = rev;
}
*minIt = *transects.begin();
*transects.begin() = minTransect;
}
}
#ifdef SHOW_CIRCULAR_SURVEY_TIME
qWarning() << "CS::circularTransects(): transect gen. time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - s1)
.count()
<< " ms";
#endif
return true; return true;
} }
} }
return false; return false;
} }
bool linearTransects(const QGeoCoordinate &origin, const QGeoCoordinate &depot, bool linearTransects(const snake::FPolygon &polygon, snake::Length distance,
bool useDepot, const QList<QGeoCoordinate> &polygon, snake::Angle angle, snake::Length minLength,
snake::Length distance, snake::Angle angle, snake::Transects &transects) {
snake::Length minLength, snake::Transects &transects) {
namespace tr = bg::strategy::transform; namespace tr = bg::strategy::transform;
#ifdef SHOW_CIRCULAR_SURVEY_TIME
auto s1 = std::chrono::high_resolution_clock::now(); auto s1 = std::chrono::high_resolution_clock::now();
#endif
// Check preconitions // Check preconitions
if (polygon.size() >= 3) { if (polygon.outer().size() >= 3) {
// Convert to ENU system. // Convert to ENU system.
snake::FPolygon polygonENU;
snake::areaToEnu(origin, polygon, polygonENU);
std::string error; std::string error;
// Check validity. // Check validity.
if (!bg::is_valid(polygonENU, error)) { if (!bg::is_valid(polygon, error)) {
#ifdef DEBUG_CIRCULAR_SURVEY
qWarning() << "CS::circularTransects(): "
"invalid polygon.";
qWarning() << error.c_str();
std::stringstream ss; std::stringstream ss;
ss << bg::wkt(polygonENU); ss << bg::wkt(polygon);
qWarning() << ss.str().c_str();
#endif qCWarning(CircularSurveyLog) << "CS::circularTransects(): "
"invalid polygon. "
<< error.c_str() << ss.str().c_str();
} else { } else {
snake::FPoint depotENU;
snake::toENU(origin, depot, depotENU);
tr::rotate_transformer<bg::degree, double, 2, 2> rotate(angle.value() * tr::rotate_transformer<bg::degree, double, 2, 2> rotate(angle.value() *
180 / M_PI); 180 / M_PI);
// Rotate polygon by angle and calculate bounding box. // Rotate polygon by angle and calculate bounding box.
snake::FPolygon polygonENURotated; snake::FPolygon polygonENURotated;
bg::transform(polygonENU, polygonENURotated, rotate); bg::transform(polygon.outer(), polygonENURotated.outer(), rotate);
snake::FBox box; snake::FBox box;
boost::geometry::envelope(polygonENURotated, box); boost::geometry::envelope(polygonENURotated, box);
double x0 = box.min_corner().get<0>(); double x0 = box.min_corner().get<0>();
...@@ -1101,13 +1102,14 @@ bool linearTransects(const QGeoCoordinate &origin, const QGeoCoordinate &depot, ...@@ -1101,13 +1102,14 @@ bool linearTransects(const QGeoCoordinate &origin, const QGeoCoordinate &depot,
std::stringstream ss; std::stringstream ss;
ss << "Not able to generate transects. Parameter: distance = " ss << "Not able to generate transects. Parameter: distance = "
<< distance << std::endl; << distance << std::endl;
qWarning() << "CircularSurvey::linearTransects(): " << ss.str().c_str(); qCWarning(CircularSurveyLog)
<< "CircularSurvey::linearTransects(): " << ss.str().c_str();
return false; return false;
} }
// Convert measurement area to clipper path. // Convert measurement area to clipper path.
snake::FPolygon shrinked; snake::FPolygon shrinked;
snake::offsetPolygon(polygonENU, shrinked, -0.2); snake::offsetPolygon(polygon, shrinked, -0.2);
auto &outer = shrinked.outer(); auto &outer = shrinked.outer();
ClipperLib::Path polygonClipper; ClipperLib::Path polygonClipper;
for (auto vertex : outer) { for (auto vertex : outer) {
...@@ -1125,10 +1127,30 @@ bool linearTransects(const QGeoCoordinate &origin, const QGeoCoordinate &depot, ...@@ -1125,10 +1127,30 @@ bool linearTransects(const QGeoCoordinate &origin, const QGeoCoordinate &depot,
clipper.Execute(ClipperLib::ctIntersection, clippedTransecs, clipper.Execute(ClipperLib::ctIntersection, clippedTransecs,
ClipperLib::pftNonZero, ClipperLib::pftNonZero); ClipperLib::pftNonZero, ClipperLib::pftNonZero);
// Extract transects from PolyTree and convert them to BoostLineString // Subtract holes.
if (useDepot) { if (polygon.inners().size() > 0) {
transects.push_back(snake::FLineString{depotENU}); vector<ClipperLib::Path> processedTiles;
for (const auto &h : polygon.inners()) {
ClipperLib::Path path;
for (const auto &v : h) {
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(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) { for (const auto &child : clippedTransecs.Childs) {
const auto &clipperTransect = child->Contour; const auto &clipperTransect = child->Contour;
snake::FPoint v1{ snake::FPoint v1{
...@@ -1148,16 +1170,16 @@ bool linearTransects(const QGeoCoordinate &origin, const QGeoCoordinate &depot, ...@@ -1148,16 +1170,16 @@ bool linearTransects(const QGeoCoordinate &origin, const QGeoCoordinate &depot,
std::stringstream ss; std::stringstream ss;
ss << "Not able to generate transects. Parameter: minLength = " ss << "Not able to generate transects. Parameter: minLength = "
<< minLength << std::endl; << minLength << std::endl;
qWarning() << "CircularSurvey::linearTransects(): " << ss.str().c_str(); qCWarning(CircularSurveyLog)
<< "CircularSurvey::linearTransects(): " << ss.str().c_str();
return false; return false;
} }
#ifdef SHOW_CIRCULAR_SURVEY_TIME qCWarning(CircularSurveyLog)
qWarning() << "CS::circularTransects(): transect gen. time: " << "CS::circularTransects(): transect gen. time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>( << std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - s1) std::chrono::high_resolution_clock::now() - s1)
.count() .count()
<< " ms"; << " ms";
#endif
return true; return true;
} }
} }
......
...@@ -6,6 +6,9 @@ ...@@ -6,6 +6,9 @@
#include "SettingsFact.h" #include "SettingsFact.h"
#include "TransectStyleComplexItem.h" #include "TransectStyleComplexItem.h"
#include "Geometry/WimaJoinedAreaData.h"
#include "Geometry/WimaMeasurementAreaData.h"
class RoutingThread; class RoutingThread;
class RoutingData; class RoutingData;
...@@ -50,8 +53,10 @@ public: ...@@ -50,8 +53,10 @@ public:
// Property setters // Property setters
void setRefPoint(const QGeoCoordinate &refPt); void setRefPoint(const QGeoCoordinate &refPt);
void setHidePolygon(bool hide); void setHidePolygon(bool hide);
void setDepot(const QGeoCoordinate &depot); void setMeasurementArea(const WimaMeasurementAreaData &mArea);
void setSafeArea(const QList<QGeoCoordinate> &safeArea); void setJoinedArea(const WimaJoinedAreaData &jArea);
void setMeasurementArea(const WimaMeasurementArea &mArea);
void setJoinedArea(const WimaJoinedArea &jArea);
// Property getters // Property getters
QGeoCoordinate refPoint() const; QGeoCoordinate refPoint() const;
...@@ -68,7 +73,6 @@ public: ...@@ -68,7 +73,6 @@ public:
QList<QString> variantNames() const; QList<QString> variantNames() const;
QList<QString> runNames() const; QList<QString> runNames() const;
QGeoCoordinate depot() const; QGeoCoordinate depot() const;
QList<QGeoCoordinate> safeArea() const;
const QList<QList<QGeoCoordinate>> &rawTransects() const; const QList<QList<QGeoCoordinate>> &rawTransects() const;
// Overrides // Overrides
...@@ -105,9 +109,10 @@ signals: ...@@ -105,9 +109,10 @@ signals:
void calculatingChanged(); void calculatingChanged();
void hidePolygonChanged(); void hidePolygonChanged();
void depotChanged(); void depotChanged();
void safeAreaChanged();
void variantNamesChanged(); void variantNamesChanged();
void runNamesChanged(); void runNamesChanged();
void measurementAreaChanged();
void joinedAreaChanged();
private slots: private slots:
// Overrides from TransectStyleComplexItem // Overrides from TransectStyleComplexItem
...@@ -147,14 +152,16 @@ private: ...@@ -147,14 +152,16 @@ private:
SettingsFact _run; SettingsFact _run;
QList<QString> _runNames; QList<QString> _runNames;
// Area data
WimaMeasurementAreaData _mArea;
WimaJoinedAreaData _jArea;
// Worker // Worker
using PtrWorker = std::shared_ptr<RoutingThread>; using PtrWorker = std::shared_ptr<RoutingThread>;
PtrWorker _pWorker; PtrWorker _pWorker;
PtrRoutingData _pRoutingData; PtrRoutingData _pRoutingData;
// Routing data. // Routing data.
QGeoCoordinate _depot;
QList<QGeoCoordinate> _safeArea;
QList<QList<QGeoCoordinate>> _rawTransects; QList<QList<QGeoCoordinate>> _rawTransects;
using Runs = QVector<Transects>; using Runs = QVector<Transects>;
QVector<Runs> _variantVector; QVector<Runs> _variantVector;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include "boost/units/systems/angle/degrees.hpp" #include "boost/units/systems/angle/degrees.hpp"
#include "boost/units/systems/si.hpp" #include "boost/units/systems/si.hpp"
template <class Point, int k> auto get(Point &p); template <int k, class Point> auto get(const Point &p);
namespace bu = boost::units; namespace bu = boost::units;
...@@ -112,11 +112,11 @@ void approximate(Circle &circ, long n, qty::Angle alpha1, qty::Angle alpha2, ...@@ -112,11 +112,11 @@ void approximate(Circle &circ, long n, qty::Angle alpha1, qty::Angle alpha2,
} }
double a = a1; double a = a1;
using Point =
std::remove_cv_t<std::remove_reference_t<decltype(circ.origin())>>;
auto x0 = get<0>(circ.origin()); auto x0 = get<0>(circ.origin());
auto y0 = get<1>(circ.origin()); auto y0 = get<1>(circ.origin());
auto r = circ.radius(); auto r = circ.radius();
using Point =
std::remove_cv_t<std::remove_reference_t<decltype(circ.origin())>>;
using NumberType = std::remove_cv_t<std::remove_reference_t<decltype(x0)>>; using NumberType = std::remove_cv_t<std::remove_reference_t<decltype(x0)>>;
while (n--) { while (n--) {
auto x = NumberType(x0 + r * std::cos(a)); auto x = NumberType(x0 + r * std::cos(a));
...@@ -139,11 +139,11 @@ void approximate(Circle &circ, long n, Container &c) { ...@@ -139,11 +139,11 @@ void approximate(Circle &circ, long n, Container &c) {
} }
double a = 0; double a = 0;
using Point =
std::remove_cv_t<std::remove_reference_t<decltype(circ.origin())>>;
auto x0 = get<0>(circ.origin()); auto x0 = get<0>(circ.origin());
auto y0 = get<1>(circ.origin()); auto y0 = get<1>(circ.origin());
auto r = circ.radius(); auto r = circ.radius();
using Point =
std::remove_cv_t<std::remove_reference_t<decltype(circ.origin())>>;
using NumberType = std::remove_cv_t<std::remove_reference_t<decltype(x0)>>; using NumberType = std::remove_cv_t<std::remove_reference_t<decltype(x0)>>;
while (n--) { while (n--) {
auto x = NumberType(x0 + r * std::cos(a)); auto x = NumberType(x0 + r * std::cos(a));
......
#include "WimaAreaData.h" #include "WimaAreaData.h"
WimaAreaData::WimaAreaData(QObject *parent) : QObject(parent) { WimaAreaData::WimaAreaData(QObject *parent) : QObject(parent) {}
_maxAltitude = 0;
}
WimaAreaData::~WimaAreaData() {} WimaAreaData::~WimaAreaData() {}
/*! bool WimaAreaData::operator==(const WimaAreaData &data) const {
* \fn double WimaAreaData::maxAltitude() return this->_path == data._path && this->_center == data._center;
* }
* Returns the maximum altitude at which vehicles are allowed to fly.
*/ bool WimaAreaData::operator!=(const WimaAreaData &data) const {
double WimaAreaData::maxAltitude() const { return _maxAltitude; } return !this->operator==(data);
}
/*!
* \fn double WimaAreaData::maxAltitude()
*
* Returns the path (vertex list defining the \l {Simple Polygon}).
*/
QVariantList WimaAreaData::path() const { return _path; } QVariantList WimaAreaData::path() const { return _path; }
QGeoCoordinate WimaAreaData::center() const { return _center; } QGeoCoordinate WimaAreaData::center() const { return _center; }
...@@ -51,20 +45,6 @@ void WimaAreaData::clear() { ...@@ -51,20 +45,6 @@ void WimaAreaData::clear() {
_path.clear(); _path.clear();
} }
/*!
* \fn void WimaAreaData::setMaxAltitude(double maxAltitude)
*
* Sets the maximum altitude member to \a maxAltitude and emits the \c
* maxAltitudeChanged() signal if \a maxAltitude differs from the members value.
*/
void WimaAreaData::setMaxAltitude(double maxAltitude) {
if (!qFuzzyCompare(_maxAltitude, maxAltitude)) {
_maxAltitude = maxAltitude;
emit maxAltitudeChanged(_maxAltitude);
}
}
void WimaAreaData::setPath(const QVariantList &coordinateList) { void WimaAreaData::setPath(const QVariantList &coordinateList) {
_path = coordinateList; _path = coordinateList;
_list.clear(); _list.clear();
...@@ -87,13 +67,11 @@ void WimaAreaData::setCenter(const QGeoCoordinate &center) { ...@@ -87,13 +67,11 @@ void WimaAreaData::setCenter(const QGeoCoordinate &center) {
* Assigns \a other to the invoking object * Assigns \a other to the invoking object
*/ */
void WimaAreaData::assign(const WimaAreaData &other) { void WimaAreaData::assign(const WimaAreaData &other) {
setMaxAltitude(other.maxAltitude());
setPath(other.path()); setPath(other.path());
setCenter(other.center()); setCenter(other.center());
} }
void WimaAreaData::assign(const WimaArea &other) { void WimaAreaData::assign(const WimaArea &other) {
setMaxAltitude(other.maxAltitude());
setPath(other.path()); setPath(other.path());
setCenter(other.center()); setCenter(other.center());
} }
...@@ -116,6 +94,13 @@ void WimaAreaData::setPath(const QList<QGeoCoordinate> &coordinateList) { ...@@ -116,6 +94,13 @@ void WimaAreaData::setPath(const QList<QGeoCoordinate> &coordinateList) {
emit pathChanged(_path); 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);
}
/*! /*!
* \class WimaArea::WimaAreaData * \class WimaArea::WimaAreaData
* \brief Class to store and exchange data of a \c WimaArea Object. * \brief Class to store and exchange data of a \c WimaArea Object.
......
...@@ -20,7 +20,9 @@ public: ...@@ -20,7 +20,9 @@ public:
WimaAreaData & WimaAreaData &
operator=(const WimaAreaData &otherData) = delete; // avoid slicing operator=(const WimaAreaData &otherData) = delete; // avoid slicing
double maxAltitude() const; bool operator==(const WimaAreaData &data) const;
bool operator!=(const WimaAreaData &data) const;
QVariantList path() const; QVariantList path() const;
QGeoCoordinate center() const; QGeoCoordinate center() const;
const QList<QGeoCoordinate> &coordinateList() const; const QList<QGeoCoordinate> &coordinateList() const;
...@@ -32,12 +34,10 @@ public: ...@@ -32,12 +34,10 @@ public:
void clear(); void clear();
signals: signals:
void maxAltitudeChanged(double maxAltitude);
void pathChanged(const QVariantList &coordinateList); void pathChanged(const QVariantList &coordinateList);
void centerChanged(void); void centerChanged(void);
public slots: public slots:
void setMaxAltitude(double maxAltitude);
void setPath(const QList<QGeoCoordinate> &coordinateList); void setPath(const QList<QGeoCoordinate> &coordinateList);
void setPath(const QVariantList &coordinateList); void setPath(const QVariantList &coordinateList);
void setCenter(const QGeoCoordinate &center); void setCenter(const QGeoCoordinate &center);
...@@ -51,8 +51,10 @@ private: ...@@ -51,8 +51,10 @@ private:
// Member Variables // Member Variables
// see WimaArea.h for explanation // see WimaArea.h for explanation
double _maxAltitude;
QVariantList _path; QVariantList _path;
QList<QGeoCoordinate> _list; mutable QList<QGeoCoordinate> _list;
QGeoCoordinate _center; QGeoCoordinate _center;
}; };
bool operator==(const WimaAreaData &m1, const WimaArea &m2);
bool operator!=(const WimaAreaData &m1, const WimaArea &m2);
...@@ -5,10 +5,14 @@ ...@@ -5,10 +5,14 @@
#include <boost/units/systems/si.hpp> #include <boost/units/systems/si.hpp>
#include "QGCLoggingCategory.h"
#ifndef SNAKE_MAX_TILES #ifndef SNAKE_MAX_TILES
#define SNAKE_MAX_TILES 1000 #define SNAKE_MAX_TILES 1000
#endif #endif
QGC_LOGGING_CATEGORY(WimaMeasurementAreaLog, "WimaMeasurementAreaLog")
TileData::TileData() : tiles(this) {} TileData::TileData() : tiles(this) {}
TileData::~TileData() { tiles.clearAndDeleteContents(); } TileData::~TileData() { tiles.clearAndDeleteContents(); }
...@@ -21,7 +25,7 @@ TileData &TileData::operator=(const TileData &other) { ...@@ -21,7 +25,7 @@ TileData &TileData::operator=(const TileData &other) {
if (tile != nullptr) { if (tile != nullptr) {
this->tiles.append(new SnakeTile(*tile, this)); this->tiles.append(new SnakeTile(*tile, this));
} else { } else {
qWarning("TileData::operator=: nullptr"); qCWarning(WimaMeasurementAreaLog) << "TileData::operator=: nullptr";
} }
} }
this->tileCenterPoints = other.tileCenterPoints; this->tileCenterPoints = other.tileCenterPoints;
...@@ -80,7 +84,7 @@ WimaMeasurementArea::WimaMeasurementArea(QObject *parent) ...@@ -80,7 +84,7 @@ WimaMeasurementArea::WimaMeasurementArea(QObject *parent)
this /* QObject parent */)), this /* QObject parent */)),
_showTiles(SettingsFact(settingsGroup, _metaDataMap[showTilesName], _showTiles(SettingsFact(settingsGroup, _metaDataMap[showTilesName],
this /* QObject parent */)), this /* QObject parent */)),
_calculating(false) { _state(STATE::IDLE) {
init(); init();
} }
...@@ -104,7 +108,7 @@ WimaMeasurementArea::WimaMeasurementArea(const WimaMeasurementArea &other, ...@@ -104,7 +108,7 @@ WimaMeasurementArea::WimaMeasurementArea(const WimaMeasurementArea &other,
this /* QObject parent */)), this /* QObject parent */)),
_showTiles(SettingsFact(settingsGroup, _metaDataMap[showTilesName], _showTiles(SettingsFact(settingsGroup, _metaDataMap[showTilesName],
this /* QObject parent */)), this /* QObject parent */)),
_calculating(false) { _state(STATE::IDLE) {
init(); init();
} }
...@@ -123,11 +127,11 @@ operator=(const WimaMeasurementArea &other) { ...@@ -123,11 +127,11 @@ operator=(const WimaMeasurementArea &other) {
WimaMeasurementArea::~WimaMeasurementArea() {} WimaMeasurementArea::~WimaMeasurementArea() {}
QString WimaMeasurementArea::mapVisualQML() const { QString WimaMeasurementArea::mapVisualQML() const {
return "WimaMeasurementAreaMapVisual.qml"; return QStringLiteral("WimaMeasurementAreaMapVisual.qml");
} }
QString WimaMeasurementArea::editorQML() const { QString WimaMeasurementArea::editorQML() const {
return "WimaMeasurementAreaEditor.qml"; return QStringLiteral("WimaMeasurementAreaEditor.qml");
} }
Fact *WimaMeasurementArea::tileHeight() { return &_tileHeight; } Fact *WimaMeasurementArea::tileHeight() { return &_tileHeight; }
...@@ -146,7 +150,13 @@ QmlObjectListModel *WimaMeasurementArea::tiles() { ...@@ -146,7 +150,13 @@ QmlObjectListModel *WimaMeasurementArea::tiles() {
return &this->_tileData.tiles; return &this->_tileData.tiles;
} }
QVector<int> WimaMeasurementArea::progress() { return this->_progress; } const QVector<int> &WimaMeasurementArea::progress() const {
return this->_progress;
}
QVector<int> WimaMeasurementArea::progressQml() const {
return this->_progress;
}
const QmlObjectListModel *WimaMeasurementArea::tiles() const { const QmlObjectListModel *WimaMeasurementArea::tiles() const {
return &this->_tileData.tiles; return &this->_tileData.tiles;
...@@ -162,7 +172,7 @@ const TileData &WimaMeasurementArea::tileData() const { ...@@ -162,7 +172,7 @@ const TileData &WimaMeasurementArea::tileData() const {
int WimaMeasurementArea::maxTiles() const { return SNAKE_MAX_TILES; } int WimaMeasurementArea::maxTiles() const { return SNAKE_MAX_TILES; }
bool WimaMeasurementArea::ready() const { return !_calculating; } bool WimaMeasurementArea::ready() const { return this->_state == STATE::IDLE; }
void WimaMeasurementArea::saveToJson(QJsonObject &json) { void WimaMeasurementArea::saveToJson(QJsonObject &json) {
this->WimaArea::saveToJson(json); this->WimaArea::saveToJson(json);
...@@ -230,7 +240,7 @@ bool WimaMeasurementArea::loadFromJson(const QJsonObject &json, ...@@ -230,7 +240,7 @@ bool WimaMeasurementArea::loadFromJson(const QJsonObject &json,
} }
bool WimaMeasurementArea::setProgress(const QVector<int> &p) { bool WimaMeasurementArea::setProgress(const QVector<int> &p) {
if (!_calculating) { if (!ready()) {
if (p.size() == this->tiles()->count() && this->_progress != p) { if (p.size() == this->tiles()->count() && this->_progress != p) {
this->_progress = p; this->_progress = p;
emit progressChanged(); emit progressChanged();
...@@ -246,18 +256,18 @@ bool WimaMeasurementArea::setProgress(const QVector<int> &p) { ...@@ -246,18 +256,18 @@ bool WimaMeasurementArea::setProgress(const QVector<int> &p) {
void WimaMeasurementArea::doUpdate() { void WimaMeasurementArea::doUpdate() {
using namespace snake; using namespace snake;
using namespace boost::units; using namespace boost::units;
#ifdef SNAKE_SHOW_TIME
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
#endif
const auto height = this->_tileHeight.rawValue().toDouble() * si::meter; const auto height = this->_tileHeight.rawValue().toDouble() * si::meter;
const auto width = this->_tileWidth.rawValue().toDouble() * si::meter; const auto width = this->_tileWidth.rawValue().toDouble() * si::meter;
const auto tileArea = width * height; const auto tileArea = width * height;
const auto totalArea = this->area() * si::meter * si::meter; const auto totalArea = this->area() * si::meter * si::meter;
const auto estNumTiles = totalArea / tileArea; const auto estNumTiles = totalArea / tileArea;
if (!this->_calculating && if (this->_state != STATE::UPDATE &&
long(std::ceil(estNumTiles.value())) <= SNAKE_MAX_TILES && long(std::ceil(estNumTiles.value())) <= SNAKE_MAX_TILES &&
this->count() >= 3 && this->isSimplePolygon()) { this->count() >= 3 && this->isSimplePolygon()) {
this->_calculating = true; setState(STATE::UPDATE);
auto polygon = this->coordinateList(); auto polygon = this->coordinateList();
for (auto &v : polygon) { for (auto &v : polygon) {
v.setAltitude(0); v.setAltitude(0);
...@@ -266,9 +276,8 @@ void WimaMeasurementArea::doUpdate() { ...@@ -266,9 +276,8 @@ void WimaMeasurementArea::doUpdate() {
this->_minTileArea.rawValue().toDouble() * si::meter * si::meter; this->_minTileArea.rawValue().toDouble() * si::meter * si::meter;
auto *th = this->thread(); auto *th = this->thread();
auto future = QtConcurrent::run([polygon, th, height, width, minArea] { auto future = QtConcurrent::run([polygon, th, height, width, minArea] {
#ifdef SNAKE_SHOW_TIME
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
#endif
DataPtr pData(new TileData()); DataPtr pData(new TileData());
// Convert to ENU system. // Convert to ENU system.
QGeoCoordinate origin = polygon.first(); QGeoCoordinate origin = polygon.first();
...@@ -298,56 +307,67 @@ void WimaMeasurementArea::doUpdate() { ...@@ -298,56 +307,67 @@ void WimaMeasurementArea::doUpdate() {
} }
} }
pData->moveToThread(th); pData->moveToThread(th);
#ifdef SNAKE_SHOW_TIME
qDebug() << "WimaMeasurementArea::doUpdate concurrent update execution " qCDebug(WimaMeasurementAreaLog)
"time: " << "doUpdate(): update time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>( << std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start) std::chrono::high_resolution_clock::now() - start)
.count() .count()
<< " ms"; << " ms";
#endif
return pData; return pData;
}); // QtConcurrent::run() }); // QtConcurrent::run()
this->_watcher.setFuture(future); this->_watcher.setFuture(future);
} }
#ifdef SNAKE_SHOW_TIME
qDebug() << "WimaMeasurementArea::doUpdate execution time: " qCDebug(WimaMeasurementAreaLog)
<< std::chrono::duration_cast<std::chrono::milliseconds>( << "doUpdate(): execution time: "
std::chrono::high_resolution_clock::now() - start) << std::chrono::duration_cast<std::chrono::milliseconds>(
.count() std::chrono::high_resolution_clock::now() - start)
<< " ms"; .count()
#endif << " ms";
} }
void WimaMeasurementArea::deferUpdate() { void WimaMeasurementArea::deferUpdate() {
if (this->_timer.isActive()) { if (this->_state == STATE::IDLE || this->_state == STATE::DEFERED) {
this->_timer.stop(); if (this->_state == STATE::IDLE) {
} this->_progress.clear();
if (this->_tileData.size() > 0) { this->_tileData.clear();
this->_progress.clear(); emit this->progressChanged();
emit this->progressChanged(); emit this->tilesChanged();
this->_tileData.clear(); }
emit this->tilesChanged(); this->setState(STATE::DEFERED);
this->_timer.start(100);
} else if (this->_state == STATE::UPDATE) {
setState(STATE::RESTART);
} }
this->_timer.start(100);
} }
void WimaMeasurementArea::storeTiles() { void WimaMeasurementArea::storeTiles() {
#ifdef SNAKE_SHOW_TIME
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
#endif
this->_tileData = *this->_watcher.result(); if (this->_state == STATE::UPDATE) {
this->_calculating = false;
// This is expensive. Drawing tiles is expensive too. qCDebug(WimaMeasurementAreaLog) << "storeTiles(): update.";
emit this->tilesChanged();
#ifdef SNAKE_SHOW_TIME this->_tileData = *this->_watcher.result();
qDebug() << "WimaMeasurementArea::storeTiles() execution time: " // This is expensive. Drawing tiles is expensive too.
<< std::chrono::duration_cast<std::chrono::milliseconds>( this->_progress = QVector<int>(this->_tileData.tiles.count(), 0);
std::chrono::high_resolution_clock::now() - start) this->progressChanged();
.count() emit this->tilesChanged();
<< " ms"; setState(STATE::IDLE);
#endif } else if (this->_state == STATE::RESTART) {
qCDebug(WimaMeasurementAreaLog) << "storeTiles(): restart.";
doUpdate();
}
qCDebug(WimaMeasurementAreaLog)
<< "storeTiles() execution time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start)
.count()
<< " ms";
} }
void WimaMeasurementArea::init() { void WimaMeasurementArea::init() {
...@@ -368,6 +388,16 @@ void WimaMeasurementArea::init() { ...@@ -368,6 +388,16 @@ void WimaMeasurementArea::init() {
&WimaMeasurementArea::storeTiles); &WimaMeasurementArea::storeTiles);
} }
void WimaMeasurementArea::setState(WimaMeasurementArea::STATE s) {
if (this->_state != s) {
auto oldState = this->_state;
this->_state = s;
if (s == STATE::IDLE || oldState == STATE::IDLE) {
emit readyChanged();
}
}
}
/*! /*!
* \class WimaMeasurementArea * \class WimaMeasurementArea
* \brief Class defining the area inside which the actual drone measurements * \brief Class defining the area inside which the actual drone measurements
......
...@@ -26,6 +26,14 @@ public: ...@@ -26,6 +26,14 @@ public:
class WimaMeasurementArea : public WimaArea { class WimaMeasurementArea : public WimaArea {
Q_OBJECT Q_OBJECT
enum class STATE {
IDLE,
DEFERED,
UPDATE,
RESTART,
};
public: public:
WimaMeasurementArea(QObject *parent = nullptr); WimaMeasurementArea(QObject *parent = nullptr);
WimaMeasurementArea(const WimaMeasurementArea &other, WimaMeasurementArea(const WimaMeasurementArea &other,
...@@ -41,7 +49,7 @@ public: ...@@ -41,7 +49,7 @@ public:
Q_PROPERTY(Fact *showTiles READ showTiles CONSTANT) Q_PROPERTY(Fact *showTiles READ showTiles CONSTANT)
Q_PROPERTY(QmlObjectListModel *tiles READ tiles NOTIFY tilesChanged) Q_PROPERTY(QmlObjectListModel *tiles READ tiles NOTIFY tilesChanged)
Q_PROPERTY(int maxTiles READ maxTiles NOTIFY maxTilesChanged) Q_PROPERTY(int maxTiles READ maxTiles NOTIFY maxTilesChanged)
Q_PROPERTY(QVector<int> progress READ progress NOTIFY progressChanged) Q_PROPERTY(QVector<int> progress READ progressQml NOTIFY progressChanged)
// Overrides from WimaPolygon // Overrides from WimaPolygon
QString mapVisualQML(void) const; QString mapVisualQML(void) const;
...@@ -54,7 +62,8 @@ public: ...@@ -54,7 +62,8 @@ public:
Fact *minTransectLength(); Fact *minTransectLength();
Fact *showTiles(); Fact *showTiles();
QmlObjectListModel *tiles(); QmlObjectListModel *tiles();
QVector<int> progress(); const QVector<int> &progress() const;
QVector<int> progressQml() const;
const QmlObjectListModel *tiles() const; const QmlObjectListModel *tiles() const;
const QVariantList &tileCenterPoints() const; // List of QGeoCoordinate const QVariantList &tileCenterPoints() const; // List of QGeoCoordinate
const TileData &tileData() const; const TileData &tileData() const;
...@@ -83,6 +92,7 @@ signals: ...@@ -83,6 +92,7 @@ signals:
void tilesChanged(); void tilesChanged();
void maxTilesChanged(); void maxTilesChanged();
void progressChanged(); void progressChanged();
void readyChanged();
public slots: public slots:
bool setProgress(const QVector<int> &p); bool setProgress(const QVector<int> &p);
...@@ -95,6 +105,7 @@ private slots: ...@@ -95,6 +105,7 @@ private slots:
private: private:
// Member Methodes // Member Methodes
void init(); void init();
void setState(STATE s);
// Members // Members
QMap<QString, FactMetaData *> _metaDataMap; QMap<QString, FactMetaData *> _metaDataMap;
...@@ -111,7 +122,8 @@ private: ...@@ -111,7 +122,8 @@ private:
using DataPtr = std::shared_ptr<TileData>; using DataPtr = std::shared_ptr<TileData>;
TileData _tileData; TileData _tileData;
QFutureWatcher<DataPtr> _watcher; QFutureWatcher<DataPtr> _watcher;
bool _calculating;
STATE _state;
QVector<int> _progress; QVector<int> _progress;
}; };
...@@ -18,6 +18,18 @@ WimaMeasurementAreaData::WimaMeasurementAreaData( ...@@ -18,6 +18,18 @@ WimaMeasurementAreaData::WimaMeasurementAreaData(
*this = other; *this = other;
} }
bool WimaMeasurementAreaData::
operator==(const WimaMeasurementAreaData &other) const {
return this->WimaAreaData::operator==(other) &&
this->_tileData == other.tileData() &&
this->center() == other.center();
}
bool WimaMeasurementAreaData::
operator!=(const WimaMeasurementAreaData &other) const {
return !(*this == other);
}
/*! /*!
* \overload operator=(); * \overload operator=();
* *
...@@ -82,9 +94,31 @@ void WimaMeasurementAreaData::assign(const WimaMeasurementArea &other) { ...@@ -82,9 +94,31 @@ void WimaMeasurementAreaData::assign(const WimaMeasurementArea &other) {
WimaAreaData::assign(other); WimaAreaData::assign(other);
if (other.ready()) { if (other.ready()) {
this->_tileData = other.tileData(); this->_tileData = other.tileData();
qWarning() << "WimaMeasurementAreaData: add progress copy here."; this->_progress = other.progress();
} else { } else {
qWarning() qWarning()
<< "WimaMeasurementAreaData::assign(): WimaMeasurementArea not ready."; << "WimaMeasurementAreaData::assign(): WimaMeasurementArea not ready.";
} }
} }
bool operator==(const WimaMeasurementAreaData &m1,
const WimaMeasurementArea &m2) {
return operator==(*static_cast<const WimaAreaData *>(&m1),
*static_cast<const WimaArea *>(&m2)) &&
m1.tileData() == m2.tileData() && m1.progress() == m2.progress();
}
bool operator!=(const WimaMeasurementAreaData &m1,
const WimaMeasurementArea &m2) {
return !(m1 == m2);
}
bool operator==(const WimaMeasurementArea &m1,
const WimaMeasurementAreaData &m2) {
return m2 == m1;
}
bool operator!=(const WimaMeasurementArea &m1,
const WimaMeasurementAreaData &m2) {
return m2 != m1;
}
...@@ -18,6 +18,9 @@ public: ...@@ -18,6 +18,9 @@ public:
WimaMeasurementAreaData &operator=(const WimaMeasurementAreaData &other); WimaMeasurementAreaData &operator=(const WimaMeasurementAreaData &other);
WimaMeasurementAreaData &operator=(const WimaMeasurementArea &other); WimaMeasurementAreaData &operator=(const WimaMeasurementArea &other);
bool operator==(const WimaMeasurementAreaData &other) const;
bool operator!=(const WimaMeasurementAreaData &other) const;
QString type() const; QString type() const;
WimaMeasurementAreaData *Clone() const { WimaMeasurementAreaData *Clone() const {
return new WimaMeasurementAreaData(*this); return new WimaMeasurementAreaData(*this);
...@@ -42,3 +45,12 @@ private: ...@@ -42,3 +45,12 @@ private:
TileData _tileData; TileData _tileData;
QVector<int> _progress; QVector<int> _progress;
}; };
bool operator==(const WimaMeasurementAreaData &m1,
const WimaMeasurementArea &m2);
bool operator!=(const WimaMeasurementAreaData &m1,
const WimaMeasurementArea &m2);
bool operator==(const WimaMeasurementArea &m1,
const WimaMeasurementAreaData &m2);
bool operator!=(const WimaMeasurementArea &m1,
const WimaMeasurementAreaData &m2);
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
// Qt // Qt
#include <QDebug> #include <QDebug>
#include "QGCLoggingCategory.h"
QGC_LOGGING_CATEGORY(RoutingWorkerLog, "RoutingWorkerLog")
RoutingThread::RoutingThread(QObject *parent) RoutingThread::RoutingThread(QObject *parent)
: QThread(parent), _calculating(false), _stop(false), _restart(false) { : QThread(parent), _calculating(false), _stop(false), _restart(false) {
...@@ -41,16 +44,13 @@ void RoutingThread::route(const RoutingParameter &par, ...@@ -41,16 +44,13 @@ void RoutingThread::route(const RoutingParameter &par,
} }
void RoutingThread::run() { void RoutingThread::run() {
qWarning() << "RoutingWorker::run(): thread start."; qCWarning(RoutingWorkerLog) << "run(): thread start.";
while (!this->_stop) { while (!this->_stop) {
#ifdef DEBUG_CIRCULAR_SURVEY qCWarning(RoutingWorkerLog) << "run(): calculation "
qWarning() << "RoutingWorker::run(): calculation " "started.";
"started.";
#endif
// Copy input. // Copy input.
#ifdef SHOW_CIRCULAR_SURVEY_TIME
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
#endif
this->_calculating = true; this->_calculating = true;
emit calculatingChanged(); emit calculatingChanged();
Lock lk(this->_mutex); Lock lk(this->_mutex);
...@@ -67,10 +67,8 @@ void RoutingThread::run() { ...@@ -67,10 +67,8 @@ void RoutingThread::run() {
if (generator(transectsENU)) { if (generator(transectsENU)) {
// Check if generation was successful. // Check if generation was successful.
if (transectsENU.size() == 0) { if (transectsENU.size() == 0) {
#ifdef DEBUG_CIRCULAR_SURVEY qCWarning(RoutingWorkerLog) << "run(): "
qWarning() << "RoutingWorker::run(): " "not able to generate transects.";
"not able to generate transects.";
#endif
} else { } else {
// Prepare data for routing. // Prepare data for routing.
auto &solutionVector = pRouteData->solutionVector; auto &solutionVector = pRouteData->solutionVector;
...@@ -95,38 +93,29 @@ void RoutingThread::run() { ...@@ -95,38 +93,29 @@ void RoutingThread::run() {
// Check if routing was successful. // Check if routing was successful.
if ((!success || solutionVector.size() < 1) && !this->_restart) { if ((!success || solutionVector.size() < 1) && !this->_restart) {
#ifdef DEBUG_CIRCULAR_SURVEY qCWarning(RoutingWorkerLog) << "run(): "
qWarning() << "RoutingWorker::run(): " "routing failed. "
"routing failed."; << snakePar.errorString.c_str();
qWarning() << snakePar.errorString.c_str();
#endif
} else if (this->_restart) { } else if (this->_restart) {
#ifdef DEBUG_CIRCULAR_SURVEY qCWarning(RoutingWorkerLog) << "run(): "
qWarning() << "RoutingWorker::run(): " "restart requested.";
"restart requested.";
#endif
} else { } else {
// Notify main thread. // Notify main thread.
emit result(pRouteData); emit result(pRouteData);
#ifdef DEBUG_CIRCULAR_SURVEY qCWarning(RoutingWorkerLog) << "run(): "
qWarning() << "RoutingWorker::run(): " "concurrent update success.";
"concurrent update success.";
#endif
} }
} }
} // end calculation } // end calculation
#ifdef DEBUG_CIRCULAR_SURVEY
else { else {
qWarning() << "RoutingWorker::run(): generator() failed."; qCWarning(RoutingWorkerLog) << "run(): generator() failed.";
} }
#endif qCWarning(RoutingWorkerLog)
#ifdef SHOW_CIRCULAR_SURVEY_TIME << "run(): execution time: "
qWarning() << "RoutingWorker::run(): execution time: " << std::chrono::duration_cast<std::chrono::milliseconds>(
<< std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::high_resolution_clock::now() - start)
std::chrono::high_resolution_clock::now() - start) .count()
.count() << " ms";
<< " ms";
#endif
// Signal calulation end and set thread to sleep. // Signal calulation end and set thread to sleep.
this->_calculating = false; this->_calculating = false;
emit calculatingChanged(); emit calculatingChanged();
...@@ -136,5 +125,5 @@ void RoutingThread::run() { ...@@ -136,5 +125,5 @@ void RoutingThread::run() {
} }
this->_restart = false; this->_restart = false;
} // main loop } // main loop
qWarning() << "RoutingWorker::run(): thread end."; qCWarning(RoutingWorkerLog) << "run(): thread end.";
} }
...@@ -48,7 +48,7 @@ public: ...@@ -48,7 +48,7 @@ public:
void setAutoPublish(bool ap); void setAutoPublish(bool ap);
void setHoldProgress(bool hp); void setHoldProgress(bool hp);
bool holdProgress(); bool lockProgress();
void publishTileData(); void publishTileData();
NemoInterface::STATUS status(); NemoInterface::STATUS status();
...@@ -88,7 +88,7 @@ private: ...@@ -88,7 +88,7 @@ private:
// Internals // Internals
std::atomic_bool running_; std::atomic_bool running_;
std::atomic_bool holdProgress_; std::atomic_bool lockProgress_;
std::atomic_bool topicServiceSetupDone; std::atomic_bool topicServiceSetupDone;
ROSBridgePtr pRosBridge; ROSBridgePtr pRosBridge;
QTimer loopTimer; QTimer loopTimer;
...@@ -110,7 +110,7 @@ StatusMap statusMap{ ...@@ -110,7 +110,7 @@ StatusMap statusMap{
NemoInterface::Impl::Impl(NemoInterface *p) NemoInterface::Impl::Impl(NemoInterface *p)
: status_(STATUS::NOT_CONNECTED), nextTimeout(TimePoint::max()), : status_(STATUS::NOT_CONNECTED), nextTimeout(TimePoint::max()),
running_(false), holdProgress_(false), topicServiceSetupDone(false), running_(false), lockProgress_(false), topicServiceSetupDone(false),
parent(p) { parent(p) {
// ROS Bridge. // ROS Bridge.
...@@ -189,11 +189,11 @@ bool NemoInterface::Impl::hasTileData(const TileData &tileData) const { ...@@ -189,11 +189,11 @@ bool NemoInterface::Impl::hasTileData(const TileData &tileData) const {
} }
void NemoInterface::Impl::setHoldProgress(bool hp) { void NemoInterface::Impl::setHoldProgress(bool hp) {
if (this->holdProgress_ != hp) { if (this->lockProgress_ != hp) {
this->holdProgress_ = hp; this->lockProgress_ = hp;
emit this->parent->holdProgressChanged(); emit this->parent->lockProgressChanged();
if (!this->holdProgress_) { if (!this->lockProgress_) {
UniqueLock lk(this->progressMutex); UniqueLock lk(this->progressMutex);
if (this->qProgress != this->qProgressHolded) { if (this->qProgress != this->qProgressHolded) {
this->qProgressHolded = this->qProgress; this->qProgressHolded = this->qProgress;
...@@ -204,7 +204,7 @@ void NemoInterface::Impl::setHoldProgress(bool hp) { ...@@ -204,7 +204,7 @@ void NemoInterface::Impl::setHoldProgress(bool hp) {
} }
} }
bool NemoInterface::Impl::holdProgress() { return this->holdProgress_.load(); } bool NemoInterface::Impl::lockProgress() { return this->lockProgress_.load(); }
void NemoInterface::Impl::publishTileData() { void NemoInterface::Impl::publishTileData() {
std::lock(this->ENUOriginMutex, this->tilesENUMutex); std::lock(this->ENUOriginMutex, this->tilesENUMutex);
...@@ -263,7 +263,7 @@ bool NemoInterface::Impl::doTopicServiceSetup() { ...@@ -263,7 +263,7 @@ bool NemoInterface::Impl::doTopicServiceSetup() {
UniqueLock lk3(this->ENUOriginMutex, std::adopt_lock); UniqueLock lk3(this->ENUOriginMutex, std::adopt_lock);
int requiredSize = this->tilesENU.polygons().size(); int requiredSize = this->tilesENU.polygons().size();
auto hold = this->holdProgress_.load(); auto hold = this->lockProgress_.load();
auto &progressMsg = this->qProgress; auto &progressMsg = this->qProgress;
if (!nemo_msgs::progress::fromJson(*pDoc, progressMsg) || if (!nemo_msgs::progress::fromJson(*pDoc, progressMsg) ||
progressMsg.progress().size() != progressMsg.progress().size() !=
...@@ -474,4 +474,4 @@ QString NemoInterface::editorQml() { ...@@ -474,4 +474,4 @@ QString NemoInterface::editorQml() {
bool NemoInterface::running() { return this->pImpl->running(); } bool NemoInterface::running() { return this->pImpl->running(); }
bool NemoInterface::holdProgress() { return this->pImpl->holdProgress(); } bool NemoInterface::lockProgress() { return this->pImpl->lockProgress(); }
...@@ -29,8 +29,8 @@ public: ...@@ -29,8 +29,8 @@ public:
Q_PROPERTY(QVector<int> progress READ progress NOTIFY progressChanged) Q_PROPERTY(QVector<int> progress READ progress NOTIFY progressChanged)
Q_PROPERTY(QString editorQml READ editorQml CONSTANT) Q_PROPERTY(QString editorQml READ editorQml CONSTANT)
Q_PROPERTY(bool running READ running NOTIFY runningChanged) Q_PROPERTY(bool running READ running NOTIFY runningChanged)
Q_PROPERTY(bool holdProgress READ holdProgress WRITE setHoldProgress NOTIFY Q_PROPERTY(bool lockProgress READ lockProgress WRITE setHoldProgress NOTIFY
holdProgressChanged) lockProgressChanged)
Q_INVOKABLE void start(); Q_INVOKABLE void start();
Q_INVOKABLE void stop(); Q_INVOKABLE void stop();
...@@ -48,13 +48,13 @@ public: ...@@ -48,13 +48,13 @@ public:
QVector<int> progress() const; QVector<int> progress() const;
QString editorQml(); QString editorQml();
bool running(); bool running();
bool holdProgress(); bool lockProgress();
signals: signals:
void statusChanged(); void statusChanged();
void progressChanged(); void progressChanged();
void runningChanged(); void runningChanged();
void holdProgressChanged(); void lockProgressChanged();
private: private:
PImpl pImpl; PImpl pImpl;
......
#include "StateMachine.h"
#include "QGCLoggingCategory.h"
#include <QDebug>
const QLoggingCategory &WimaPlanerLog();
namespace wima_planer_detail {
template <typename T>
constexpr typename std::underlying_type<T>::type integral(T value) {
return static_cast<typename std::underlying_type<T>::type>(value);
}
StateMachine::StateMachine(QObject *parent)
: QObject(parent), _state(STATE::NEEDS_INIT) {}
STATE StateMachine::state() { return this->_state; }
void StateMachine::updateState(EVENT e) {
qCDebug(WimaPlanerLog) << "StateMachine::updateState(): event:" << e;
switch (this->_state) {
case STATE::NEEDS_INIT:
switch (e) {
case EVENT::INIT_DONE:
setState(STATE::NEEDS_J_AREA_UPDATE);
break;
case EVENT::M_AREA_PATH_CHANGED:
case EVENT::S_AREA_PATH_CHANGED:
case EVENT::CORRIDOR_PATH_CHANGED:
case EVENT::M_AREA_TILES_CHANGED:
case EVENT::M_AREA_PROGRESS_CHANGED:
case EVENT::J_AREA_UPDATED:
case EVENT::DEPOT_CHANGED:
case EVENT::SURVEY_DESTROYED:
case EVENT::SURVEY_UPDATE_TRIGGERED:
case EVENT::SURVEY_UPDATED:
case EVENT::PATH_UPDATED:
break;
default:
qCCritical(WimaPlanerLog)
<< "StateMachine::updateState: Unknown event: " << e;
Q_ASSERT(false);
break;
}
break; // STATE::NEEDS_INIT
case STATE::NEEDS_J_AREA_UPDATE:
switch (e) {
case EVENT::INIT_DONE:
case EVENT::M_AREA_PATH_CHANGED:
case EVENT::S_AREA_PATH_CHANGED:
case EVENT::CORRIDOR_PATH_CHANGED:
case EVENT::M_AREA_TILES_CHANGED:
case EVENT::M_AREA_PROGRESS_CHANGED:
break;
case EVENT::J_AREA_UPDATED:
setState(STATE::NEEDS_SURVEY_UPDATE);
case EVENT::DEPOT_CHANGED:
case EVENT::SURVEY_DESTROYED:
case EVENT::SURVEY_UPDATE_TRIGGERED:
case EVENT::SURVEY_UPDATED:
case EVENT::PATH_UPDATED:
break;
default:
qCCritical(WimaPlanerLog)
<< "StateMachine::updateState: Unknown event: " << e;
Q_ASSERT(false);
break;
}
break; // STATE::NEEDS_J_AREA_UPDATE
case STATE::NEEDS_SURVEY_UPDATE:
switch (e) {
case EVENT::INIT_DONE:
case EVENT::M_AREA_PATH_CHANGED:
case EVENT::S_AREA_PATH_CHANGED:
case EVENT::CORRIDOR_PATH_CHANGED:
setState(STATE::NEEDS_J_AREA_UPDATE);
break;
case EVENT::M_AREA_TILES_CHANGED:
case EVENT::M_AREA_PROGRESS_CHANGED:
case EVENT::J_AREA_UPDATED:
case EVENT::DEPOT_CHANGED:
case EVENT::SURVEY_DESTROYED:
break;
case EVENT::SURVEY_UPDATE_TRIGGERED:
setState(STATE::WAITING_FOR_SURVEY_UPDATE);
break;
case EVENT::SURVEY_UPDATED:
case EVENT::PATH_UPDATED:
break;
default:
qCCritical(WimaPlanerLog)
<< "StateMachine::updateState: Unknown event: " << e;
Q_ASSERT(false);
break;
}
break; // STATE::NEEDS_SURVEY_UPDATE
case STATE::WAITING_FOR_SURVEY_UPDATE:
switch (e) {
case EVENT::INIT_DONE:
case EVENT::M_AREA_PATH_CHANGED:
case EVENT::S_AREA_PATH_CHANGED:
case EVENT::CORRIDOR_PATH_CHANGED:
setState(STATE::NEEDS_J_AREA_UPDATE);
break;
case EVENT::M_AREA_TILES_CHANGED:
case EVENT::M_AREA_PROGRESS_CHANGED:
case EVENT::J_AREA_UPDATED:
case EVENT::DEPOT_CHANGED:
case EVENT::SURVEY_DESTROYED:
setState(STATE::NEEDS_SURVEY_UPDATE);
break;
case EVENT::SURVEY_UPDATE_TRIGGERED:
break;
case EVENT::SURVEY_UPDATED:
setState(STATE::NEEDS_PATH_UPDATE);
case EVENT::PATH_UPDATED:
break;
default:
qCCritical(WimaPlanerLog)
<< "StateMachine::updateState: Unknown event: " << e;
Q_ASSERT(false);
break;
}
break; // STATE::WAYTING_FOR_SURVEY_UPDATE
case STATE::NEEDS_PATH_UPDATE:
switch (e) {
case EVENT::INIT_DONE:
case EVENT::M_AREA_PATH_CHANGED:
case EVENT::S_AREA_PATH_CHANGED:
case EVENT::CORRIDOR_PATH_CHANGED:
setState(STATE::NEEDS_J_AREA_UPDATE);
break;
case EVENT::M_AREA_TILES_CHANGED:
case EVENT::M_AREA_PROGRESS_CHANGED:
case EVENT::J_AREA_UPDATED:
case EVENT::DEPOT_CHANGED:
case EVENT::SURVEY_DESTROYED:
setState(STATE::NEEDS_SURVEY_UPDATE);
break;
case EVENT::SURVEY_UPDATE_TRIGGERED:
setState(STATE::WAITING_FOR_SURVEY_UPDATE);
break;
case EVENT::SURVEY_UPDATED:
break;
case EVENT::PATH_UPDATED:
setState(STATE::UP_TO_DATE);
break;
default:
qCCritical(WimaPlanerLog)
<< "StateMachine::updateState: Unknown event: " << e;
Q_ASSERT(false);
break;
}
break; // STATE::NEEDS_PATH_UPDATE
case STATE::UP_TO_DATE:
switch (e) {
case EVENT::INIT_DONE:
case EVENT::M_AREA_PATH_CHANGED:
case EVENT::S_AREA_PATH_CHANGED:
case EVENT::CORRIDOR_PATH_CHANGED:
setState(STATE::NEEDS_J_AREA_UPDATE);
break;
case EVENT::M_AREA_TILES_CHANGED:
case EVENT::M_AREA_PROGRESS_CHANGED:
case EVENT::J_AREA_UPDATED:
case EVENT::DEPOT_CHANGED:
case EVENT::SURVEY_DESTROYED:
setState(STATE::NEEDS_SURVEY_UPDATE);
break;
case EVENT::SURVEY_UPDATE_TRIGGERED:
setState(STATE::WAITING_FOR_SURVEY_UPDATE);
break;
case EVENT::SURVEY_UPDATED:
setState(STATE::NEEDS_PATH_UPDATE);
break;
case EVENT::PATH_UPDATED:
break;
default:
qCCritical(WimaPlanerLog)
<< "StateMachine::updateState: Unknown event: " << e;
Q_ASSERT(false);
break;
}
break; // STATE::UP_TO_DATE
default:
qCCritical(WimaPlanerLog)
<< "StateMachine::updateState: Unknown state: " << this->_state;
Q_ASSERT(false);
break;
}
}
bool StateMachine::upToDate() { return this->_state == STATE::UP_TO_DATE; }
void StateMachine::setState(STATE s) {
if (this->_state != s) {
auto oldState = this->_state;
this->_state = s;
emit stateChanged();
if (oldState == STATE::UP_TO_DATE || s == STATE::UP_TO_DATE) {
emit upToDateChanged();
}
qCDebug(WimaPlanerLog) << "StateMachine::setState():" << oldState << "->"
<< s;
}
}
QDebug &operator<<(QDebug &ds, STATE s) {
switch (s) {
case STATE::NEEDS_INIT:
ds << "NEEDS_INIT";
break;
case STATE::NEEDS_J_AREA_UPDATE:
ds << "NEEDS_J_AREA_UPDATE";
break;
case STATE::NEEDS_SURVEY_UPDATE:
ds << "NEEDS_SURVEY_UPDATE";
break;
case STATE::WAITING_FOR_SURVEY_UPDATE:
ds << "WAITING_FOR_SURVEY_UPDATE";
break;
case STATE::NEEDS_PATH_UPDATE:
ds << "NEEDS_PATH_UPDATE";
break;
case STATE::UP_TO_DATE:
ds << "UP_TO_DATE";
break;
}
return ds;
}
QDebug &operator<<(QDebug &ds, EVENT s) {
switch (s) {
case EVENT::INIT_DONE:
ds << "INIT_DONE";
break;
case EVENT::M_AREA_PATH_CHANGED:
ds << "M_AREA_PATH_CHANGED";
break;
case EVENT::S_AREA_PATH_CHANGED:
ds << "S_AREA_PATH_CHANGED";
break;
case EVENT::CORRIDOR_PATH_CHANGED:
ds << "CORRIDOR_PATH_CHANGED";
break;
case EVENT::M_AREA_TILES_CHANGED:
ds << "M_AREA_TILES_CHANGED";
break;
case EVENT::M_AREA_PROGRESS_CHANGED:
ds << "M_AREA_PROGRESS_CHANGED";
break;
case EVENT::J_AREA_UPDATED:
ds << "J_AREA_UPDATED";
break;
case EVENT::DEPOT_CHANGED:
ds << "DEPOT_CHANGED";
break;
case EVENT::SURVEY_DESTROYED:
ds << "SURVEY_DESTROYED";
break;
case EVENT::SURVEY_UPDATE_TRIGGERED:
ds << "SURVEY_UPDATE_TRIGGERED";
break;
case EVENT::SURVEY_UPDATED:
ds << "SURVEY_UPDATED";
break;
case EVENT::PATH_UPDATED:
ds << "PATH_UPDATED";
break;
}
return ds;
}
} // namespace wima_planer_detail
#pragma once
#include <QDataStream>
#include <QObject>
namespace wima_planer_detail {
enum class STATE {
NEEDS_INIT,
NEEDS_J_AREA_UPDATE,
NEEDS_SURVEY_UPDATE,
WAITING_FOR_SURVEY_UPDATE,
NEEDS_PATH_UPDATE,
UP_TO_DATE
};
QDebug &operator<<(QDebug &ds, STATE s);
enum class EVENT {
INIT_DONE,
M_AREA_PATH_CHANGED,
S_AREA_PATH_CHANGED,
CORRIDOR_PATH_CHANGED,
M_AREA_TILES_CHANGED,
M_AREA_PROGRESS_CHANGED,
J_AREA_UPDATED,
DEPOT_CHANGED,
SURVEY_DESTROYED,
SURVEY_UPDATE_TRIGGERED,
SURVEY_UPDATED,
PATH_UPDATED,
};
QDebug &operator<<(QDebug &ds, EVENT s);
class StateMachine : public QObject {
Q_OBJECT
public:
explicit StateMachine(QObject *parent = nullptr);
STATE state();
void updateState(EVENT e);
bool upToDate();
signals:
void stateChanged();
void upToDateChanged();
private:
void setState(STATE s);
STATE _state;
};
} // namespace wima_planer_detail
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "MissionSettingsItem.h" #include "MissionSettingsItem.h"
#include "PlanMasterController.h" #include "PlanMasterController.h"
#include "QGCApplication.h" #include "QGCApplication.h"
#include "QGCLoggingCategory.h"
#include "QGCMapPolygon.h" #include "QGCMapPolygon.h"
#include "SimpleMissionItem.h" #include "SimpleMissionItem.h"
...@@ -16,40 +17,39 @@ ...@@ -16,40 +17,39 @@
#include "Geometry/WimaAreaData.h" #include "Geometry/WimaAreaData.h"
#include "WimaBridge.h" #include "WimaBridge.h"
#include "StateMachine.h"
using namespace wima_planer_detail;
#include <functional>
QGC_LOGGING_CATEGORY(WimaPlanerLog, "WimaPlanerLog")
class CommandRAII {
std::function<void(void)> f;
public:
CommandRAII(const std::function<void(void)> &fun) : f(fun) {}
~CommandRAII() { f(); }
};
const char *WimaPlaner::wimaFileExtension = "wima"; const char *WimaPlaner::wimaFileExtension = "wima";
const char *WimaPlaner::areaItemsName = "AreaItems"; const char *WimaPlaner::areaItemsName = "AreaItems";
const char *WimaPlaner::missionItemsName = "MissionItems"; const char *WimaPlaner::missionItemsName = "MissionItems";
WimaPlaner::WimaPlaner(QObject *parent) WimaPlaner::WimaPlaner(QObject *parent)
: QObject(parent), _masterController(nullptr), _missionController(nullptr), : QObject(parent), _masterController(nullptr), _missionController(nullptr),
_currentAreaIndex(-1), _wimaBridge(nullptr), _mAreaChanged(true), _currentAreaIndex(-1), _wimaBridge(nullptr), _copyMAreaToSurvey(true),
_sAreaChanged(true), _corridorChanged(true), _joinedArea(this), _copySAreaToSurvey(true), _corridorChanged(true), _joinedArea(this),
_arrivalPathLength(0), _returnPathLength(0), _TSComplexItem(nullptr), _arrivalPathLength(0), _returnPathLength(0), _survey(nullptr),
_surveyChanged(true), _synchronized(false), _needsUpdate(true), _surveyChanged(true), _synchronized(false), _nemoInterface(this),
_nemoInterface(this) { _stateMachine(new StateMachine) {
connect(this, &WimaPlaner::currentPolygonIndexChanged, this, connect(this, &WimaPlaner::currentPolygonIndexChanged, this,
&WimaPlaner::updatePolygonInteractivity); &WimaPlaner::updatePolygonInteractivity);
connect(&this->_measurementArea, &WimaArea::pathChanged, [this] {
this->_mAreaChanged = true;
this->setNeedsUpdate(true);
});
connect(&this->_measurementArea, &WimaMeasurementArea::tilesChanged, [this] {
this->_nemoInterface.setTileData(this->_measurementArea.tileData());
});
connect(&this->_serviceArea, &WimaArea::pathChanged, [this] {
this->_sAreaChanged = true;
this->setNeedsUpdate(true);
});
connect(&this->_serviceArea, &WimaServiceArea::depotChanged, [this] { // Enable monitoring (state update)
this->_sAreaChanged = true; enableMonitoring();
this->setNeedsUpdate(true);
});
connect(&this->_corridor, &WimaArea::pathChanged, [this] {
this->_corridorChanged = true;
this->setNeedsUpdate(true);
});
#ifndef NDEBUG #ifndef NDEBUG
// for debugging and testing purpose, remove if not needed anymore // for debugging and testing purpose, remove if not needed anymore
connect(&_autoLoadTimer, &QTimer::timeout, this, connect(&_autoLoadTimer, &QTimer::timeout, this,
...@@ -62,8 +62,14 @@ WimaPlaner::WimaPlaner(QObject *parent) ...@@ -62,8 +62,14 @@ WimaPlaner::WimaPlaner(QObject *parent)
connect(&this->_nemoInterface, &NemoInterface::progressChanged, [this] { connect(&this->_nemoInterface, &NemoInterface::progressChanged, [this] {
this->_measurementArea.setProgress(this->_nemoInterface.progress()); this->_measurementArea.setProgress(this->_nemoInterface.progress());
}); });
// StateMachine
connect(this->_stateMachine.get(), &StateMachine::upToDateChanged, this,
&WimaPlaner::needsUpdateChanged);
} }
WimaPlaner::~WimaPlaner() {}
PlanMasterController *WimaPlaner::masterController() { PlanMasterController *WimaPlaner::masterController() {
return _masterController; return _masterController;
} }
...@@ -135,7 +141,7 @@ void WimaPlaner::setWimaBridge(WimaBridge *bridge) { ...@@ -135,7 +141,7 @@ void WimaPlaner::setWimaBridge(WimaBridge *bridge) {
bool WimaPlaner::synchronized() { return _synchronized; } bool WimaPlaner::synchronized() { return _synchronized; }
bool WimaPlaner::needsUpdate() { return _needsUpdate; } bool WimaPlaner::needsUpdate() { return !this->_stateMachine->upToDate(); }
WimaPlaner *WimaPlaner::thisPointer() { return this; } WimaPlaner *WimaPlaner::thisPointer() { return this; }
...@@ -144,7 +150,8 @@ void WimaPlaner::removeArea(int index) { ...@@ -144,7 +150,8 @@ void WimaPlaner::removeArea(int index) {
WimaArea *area = qobject_cast<WimaArea *>(_visualItems.removeAt(index)); WimaArea *area = qobject_cast<WimaArea *>(_visualItems.removeAt(index));
if (area == nullptr) { if (area == nullptr) {
qWarning("WimaPlaner::removeArea(): nullptr catched, internal error."); qCWarning(WimaPlanerLog)
<< "removeArea(): nullptr catched, internal error.";
return; return;
} }
area->clear(); area->clear();
...@@ -167,7 +174,7 @@ void WimaPlaner::removeArea(int index) { ...@@ -167,7 +174,7 @@ void WimaPlaner::removeArea(int index) {
updatePolygonInteractivity(_currentAreaIndex); updatePolygonInteractivity(_currentAreaIndex);
} }
} else { } else {
qWarning("Index out of bounds!"); qCWarning(WimaPlanerLog) << "removeArea(): Index out of bounds!";
} }
} }
...@@ -224,62 +231,67 @@ void WimaPlaner::removeAll() { ...@@ -224,62 +231,67 @@ void WimaPlaner::removeAll() {
_currentFile = ""; _currentFile = "";
_TSComplexItem = nullptr; _survey = nullptr;
emit currentFileChanged(); emit currentFileChanged();
if (changesApplied) if (changesApplied)
emit visualItemsChanged(); emit visualItemsChanged();
} }
bool WimaPlaner::update() { void WimaPlaner::update() { this->_update(); }
this->_synchronized = false;
emit synchronizedChanged();
// ====================== update joined area ====================== void WimaPlaner::_update() {
// check if at least service area and measurement area are available setSynchronized(false);
if (_visualItems.indexOf(&_serviceArea) == -1 ||
_visualItems.indexOf(&_measurementArea) == -1)
return false;
// Check if polygons have at least three vertices switch (this->_stateMachine->state()) {
if (_serviceArea.count() < 3) { case STATE::NEEDS_INIT: {
qgcApp()->showMessage(tr("Service area has less than three vertices.")); this->_stateMachine->updateState(EVENT::INIT_DONE);
return false; this->_update();
} } break;
if (_measurementArea.count() < 3) { case STATE::NEEDS_J_AREA_UPDATE: {
qgcApp()->showMessage(tr("Measurement area has less than three vertices.")); // check if at least service area and measurement area are available
return false; if (_visualItems.indexOf(&_serviceArea) == -1 ||
} _visualItems.indexOf(&_measurementArea) == -1)
return;
// Check for simple polygons // Check if polygons have at least three vertices
if (!_serviceArea.isSimplePolygon()) { if (_serviceArea.count() < 3) {
qgcApp()->showMessage(tr("Service area is not a simple polygon. " qgcApp()->showMessage(tr("Service area has less than three vertices."));
"Only simple polygons allowed.\n")); return;
return false; }
}
if (!_corridor.isSimplePolygon() && _corridor.count() > 0) { if (_measurementArea.count() < 3) {
qgcApp()->showMessage(tr("Corridor is not a simple polygon. Only " qgcApp()->showMessage(
"simple polygons allowed.\n")); tr("Measurement area has less than three vertices."));
return false; return;
} }
if (!_measurementArea.isSimplePolygon()) { // Check for simple polygons
qgcApp()->showMessage(tr("Measurement area is not a simple " if (!_serviceArea.isSimplePolygon()) {
"polygon. Only simple polygons allowed.\n")); qgcApp()->showMessage(tr("Service area is not a simple polygon. "
return false; "Only simple polygons allowed.\n"));
} return;
}
if (!_serviceArea.containsCoordinate(_serviceArea.depot())) { if (!_corridor.isSimplePolygon() && _corridor.count() > 0) {
qgcApp()->showMessage(tr("Depot not inside service area.")); qgcApp()->showMessage(tr("Corridor is not a simple polygon. Only "
return false; "simple polygons allowed.\n"));
} return;
}
if (!_measurementArea.isSimplePolygon()) {
qgcApp()->showMessage(tr("Measurement area is not a simple "
"polygon. Only simple polygons allowed.\n"));
return;
}
if (!_serviceArea.containsCoordinate(_serviceArea.depot())) {
qgcApp()->showMessage(tr("Depot not inside service area."));
return;
}
// Join areas. // Join areas.
bool jAreaChanged =
this->_mAreaChanged || this->_sAreaChanged || this->_corridorChanged;
if (jAreaChanged) {
_joinedArea.setPath(_serviceArea.path()); _joinedArea.setPath(_serviceArea.path());
if (_corridor.count() >= 3) { if (_corridor.count() >= 3) {
_joinedArea.join(_corridor); _joinedArea.join(_corridor);
...@@ -289,169 +301,208 @@ bool WimaPlaner::update() { ...@@ -289,169 +301,208 @@ bool WimaPlaner::update() {
tr("Not able to join areas. Service and measurement area" tr("Not able to join areas. Service and measurement area"
" must be overlapping, or connected through a " " must be overlapping, or connected through a "
"corridor.")); "corridor."));
return false; return;
} }
} this->_stateMachine->updateState(EVENT::J_AREA_UPDATED);
this->_update();
} break; // STATE::NEEDS_J_AREA_UPDATE
// =========================================================== case STATE::NEEDS_SURVEY_UPDATE: {
// ====================== update survey ====================== // Need to insert Survey?
bool updateSurveyArea = jAreaChanged; QmlObjectListModel *missionItems = _missionController->visualItems();
// extract old survey data int surveyIndex = missionItems->indexOf(_survey);
QmlObjectListModel *missionItems = _missionController->visualItems(); // Create survey item if not yet present.
int surveyIndex = missionItems->indexOf(_TSComplexItem); if (surveyIndex < 0) {
// create survey item if not yet present _missionController->insertComplexMissionItem(
if (surveyIndex == -1) { _missionController->circularSurveyComplexItemName(),
_missionController->insertComplexMissionItem( _measurementArea.center(), missionItems->count());
_missionController->circularSurveyComplexItemName(), _survey = qobject_cast<CircularSurvey *>(
_measurementArea.center(), missionItems->count()); missionItems->get(missionItems->count() - 1));
_TSComplexItem = qobject_cast<CircularSurvey *>(
missionItems->get(missionItems->count() - 1)); if (_survey == nullptr) {
qCWarning(WimaPlanerLog) << "_survey == nullptr";
if (_TSComplexItem == nullptr) { return;
qWarning("WimaPlaner::update(): survey == nullptr"); }
return false;
}
// establish connections // establish connections
_TSComplexItem->setRefPoint(_measurementArea.center()); _survey->setRefPoint(_measurementArea.center());
_TSComplexItem->setHidePolygon(true); _survey->setHidePolygon(true);
connect(_TSComplexItem, &CircularSurvey::missionItemReady, [this] { connect(_survey, &CircularSurvey::calculatingChanged, this,
this->_surveyChanged = true; &WimaPlaner::CSCalculatingChangedHandler);
this->setNeedsUpdate(true); connect(_survey, &CircularSurvey::missionItemReady, this,
}); &WimaPlaner::CSMissionItemReadyHandler);
updateSurveyArea = true; connect(_survey, &CircularSurvey::destroyed, this,
} &WimaPlaner::CSDestroyedHandler);
}
if (updateSurveyArea) {
// update survey area // update survey area
_TSComplexItem->surveyAreaPolygon()->clear(); disconnect(_survey, &CircularSurvey::calculatingChanged, this,
_TSComplexItem->surveyAreaPolygon()->appendVertices( &WimaPlaner::CSCalculatingChangedHandler);
_measurementArea.coordinateList()); _survey->setMeasurementArea(this->_measurementArea);
_TSComplexItem->setDepot(this->_serviceArea.depot()); _survey->setJoinedArea(this->_joinedArea);
_TSComplexItem->setSafeArea(this->_joinedArea.coordinateList()); connect(_survey, &CircularSurvey::calculatingChanged, this,
this->_mAreaChanged = false; &WimaPlaner::CSCalculatingChangedHandler);
this->_sAreaChanged = false;
this->_corridorChanged = false; // Folloing statement just for completeness.
} else if (this->_surveyChanged) { this->_stateMachine->updateState(EVENT::SURVEY_UPDATE_TRIGGERED);
} break; // STATE::NEEDS_SURVEY_UPDATE
// ==========================================================
// ====================== update paths ====================== case STATE::WAITING_FOR_SURVEY_UPDATE: {
} break;
surveyIndex = missionItems->indexOf(_TSComplexItem);
case STATE::NEEDS_PATH_UPDATE: {
if (surveyIndex == -1) { // Check if survey is present.
qWarning("WimaPlaner::update(): no survey item"); QmlObjectListModel *missionItems = _missionController->visualItems();
return false; int surveyIndex = missionItems->indexOf(_survey);
} if (surveyIndex < 0) {
this->_stateMachine->updateState(EVENT::SURVEY_DESTROYED);
this->_update();
} else {
// remove old arrival and return path // Remove old arrival and return path.
int size = missionItems->count(); int size = missionItems->count();
for (int i = surveyIndex + 1; i < size; i++) for (int i = surveyIndex + 1; i < size; i++)
_missionController->removeMissionItem(surveyIndex + 1); _missionController->removeMissionItem(surveyIndex + 1);
for (int i = surveyIndex - 1; i > 1; i--) for (int i = surveyIndex - 1; i > 1; i--)
_missionController->removeMissionItem(i); _missionController->removeMissionItem(i);
// set home position to serArea center // set home position to serArea center
MissionSettingsItem *settingsItem = MissionSettingsItem *settingsItem =
qobject_cast<MissionSettingsItem *>(missionItems->get(0)); qobject_cast<MissionSettingsItem *>(missionItems->get(0));
if (settingsItem == nullptr) { if (settingsItem == nullptr) {
qWarning("WimaPlaner::update(): settingsItem == nullptr"); qCWarning(WimaPlanerLog) << "update(): settingsItem == nullptr";
return false; return;
} }
// 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());
if (_TSComplexItem->visualTransectPoints().size() == 0) { // set altitudes
qWarning("WimaPlaner::update(): survey no points."); auto depot = _serviceArea.depot();
return false; depot.setAltitude(0);
} settingsItem->setCoordinate(depot);
// calculate path from take off to survey // set takeoff position
QGeoCoordinate start = _serviceArea.depot(); bool setCommandNeeded = false;
QGeoCoordinate end = _TSComplexItem->coordinate(); if (missionItems->count() < 3) {
#ifdef QT_DEBUG setCommandNeeded = true;
// if (!_visualItems.contains(&_joinedArea)) _missionController->insertSimpleMissionItem(depot, 1);
//_visualItems.append(&_joinedArea); }
#endif SimpleMissionItem *takeOffItem =
QVector<QGeoCoordinate> path; qobject_cast<SimpleMissionItem *>(missionItems->get(1));
if (!shortestPath(start, end, path)) { if (takeOffItem == nullptr) {
qgcApp()->showMessage(QString(tr("Not able to calculate path from " qCWarning(WimaPlanerLog) << "update(): takeOffItem == nullptr";
"takeoff position to measurement area.")) return;
.toLocal8Bit() }
.data()); if (setCommandNeeded)
return false; _missionController->setTakeoffCommand(*takeOffItem);
} takeOffItem->setCoordinate(depot);
_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 if (_survey->visualTransectPoints().size() == 0) {
start = _TSComplexItem->exitCoordinate(); qCWarning(WimaPlanerLog) << "update(): survey no points";
end = _serviceArea.depot(); return;
path.clear(); }
if (!shortestPath(start, end, path)) {
qgcApp()->showMessage(QString(tr("Not able to calculate the path from " // calculate path from take off to survey
"measurement area to landing position.")) QGeoCoordinate start = depot;
.toLocal8Bit() QGeoCoordinate end = _survey->coordinate();
.data()); QVector<QGeoCoordinate> path;
return false; if (!shortestPath(start, end, path)) {
} qgcApp()->showMessage(
_returnPathLength = QString(tr("Not able to calculate path from "
path.size() - 1; // -1: fist item is last measurement point "takeoff position to measurement area."))
for (int i = 1; i < path.count() - 1; i++) { .toLocal8Bit()
.data());
return;
}
_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 = _survey->exitCoordinate();
end = 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;
}
_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( sequenceNumber = _missionController->insertSimpleMissionItem(
path[i], missionItems->count()); depot, missionItems->count());
_missionController->setCurrentPlanViewIndex(sequenceNumber, true); _missionController->setCurrentPlanViewIndex(sequenceNumber, true);
} SimpleMissionItem *landItem = qobject_cast<SimpleMissionItem *>(
missionItems->get(missionItems->count() - 1));
// create land position item if (landItem == nullptr) {
sequenceNumber = _missionController->insertSimpleMissionItem( qCWarning(WimaPlanerLog) << "update(): landItem == nullptr";
_serviceArea.depot(), missionItems->count()); return;
_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)) if (!_missionController->setLandCommand(*landItem))
return false; return;
this->_stateMachine->updateState(EVENT::PATH_UPDATED);
} }
this->_surveyChanged = false; } break; // STATE::NEEDS_PATH_UPDATE
setNeedsUpdate(false);
case STATE::UP_TO_DATE: {
} break; // STATE::UP_TO_DATE
} // switch
}
void WimaPlaner::CSDestroyedHandler() {
this->_stateMachine->updateState(EVENT::SURVEY_DESTROYED);
}
void WimaPlaner::CSMissionItemReadyHandler() {
this->_stateMachine->updateState(EVENT::SURVEY_UPDATED);
this->_update();
}
void WimaPlaner::CSCalculatingChangedHandler() {
if (this->_survey->calculating()) {
this->_stateMachine->updateState(EVENT::SURVEY_UPDATE_TRIGGERED);
} }
}
void WimaPlaner::mAreaPathChangedHandler() {
this->_stateMachine->updateState(EVENT::M_AREA_PATH_CHANGED);
}
void WimaPlaner::mAreaTilesChangedHandler() {
this->_nemoInterface.setTileData(this->_measurementArea.tileData());
this->_stateMachine->updateState(EVENT::M_AREA_TILES_CHANGED);
}
void WimaPlaner::mAreaProgressChangedHandler() {
this->_stateMachine->updateState(EVENT::M_AREA_PROGRESS_CHANGED);
}
void WimaPlaner::sAreaPathChangedHandler() {
this->_stateMachine->updateState(EVENT::S_AREA_PATH_CHANGED);
}
void WimaPlaner::corridorPathChangedHandler() {
this->_stateMachine->updateState(EVENT::CORRIDOR_PATH_CHANGED);
}
return true; void WimaPlaner::depotChangedHandler() {
this->_stateMachine->updateState(EVENT::DEPOT_CHANGED);
} }
void WimaPlaner::saveToCurrent() { saveToFile(_currentFile); } void WimaPlaner::saveToCurrent() { saveToFile(_currentFile); }
void WimaPlaner::saveToFile(const QString &filename) { void WimaPlaner::saveToFile(const QString &filename) {
...@@ -498,7 +549,22 @@ void WimaPlaner::saveToFile(const QString &filename) { ...@@ -498,7 +549,22 @@ void WimaPlaner::saveToFile(const QString &filename) {
bool WimaPlaner::loadFromCurrent() { return loadFromFile(_currentFile); } bool WimaPlaner::loadFromCurrent() { return loadFromFile(_currentFile); }
bool WimaPlaner::loadFromFile(const QString &filename) { bool WimaPlaner::loadFromFile(const QString &filename) {
#define debug 0 // Remove obsolete connections.
disableMonitoring();
CommandRAII onExit([this] { this->enableMonitoring(); });
// disconnect old survey
if (_survey != nullptr) {
disconnect(_survey, &CircularSurvey::calculatingChanged, this,
&WimaPlaner::CSCalculatingChangedHandler);
disconnect(_survey, &CircularSurvey::missionItemReady, this,
&WimaPlaner::CSMissionItemReadyHandler);
disconnect(_survey, &CircularSurvey::destroyed, this,
&WimaPlaner::CSDestroyedHandler);
}
setSynchronized(false);
// Precondition.
QString errorString; QString errorString;
QString errorMessage = QString errorMessage =
tr("Error loading Plan file (%1). %2").arg(filename).arg("%1"); tr("Error loading Plan file (%1). %2").arg(filename).arg("%1");
...@@ -593,21 +659,15 @@ bool WimaPlaner::loadFromFile(const QString &filename) { ...@@ -593,21 +659,15 @@ bool WimaPlaner::loadFromFile(const QString &filename) {
QJsonObject missionObject = json[missionItemsName].toObject(); QJsonObject missionObject = json[missionItemsName].toObject();
// qWarning() << json[missionItemsName].type();
QJsonDocument missionJsonDoc = QJsonDocument(missionObject); QJsonDocument missionJsonDoc = QJsonDocument(missionObject);
// create temporary file with missionItems // create temporary file with missionItems
QFile temporaryFile; QFile temporaryFile;
QString cropedFileName = filename.section("/", 0, -2); QString cropedFileName = filename.section("/", 0, -2);
#if debug
qWarning() << cropedFileName;
#endif
QString temporaryFileName; QString temporaryFileName;
for (int i = 0;; i++) { for (int i = 0;; i++) {
temporaryFileName = temporaryFileName =
cropedFileName + cropedFileName +
QString("/temp%1.%2").arg(i).arg(AppSettings::planFileExtension); QString("/temp%1.%2").arg(i).arg(AppSettings::planFileExtension);
// qWarning() << temporaryFileName;
if (!QFile::exists(temporaryFileName)) { if (!QFile::exists(temporaryFileName)) {
temporaryFile.setFileName(temporaryFileName); temporaryFile.setFileName(temporaryFileName);
...@@ -617,48 +677,40 @@ bool WimaPlaner::loadFromFile(const QString &filename) { ...@@ -617,48 +677,40 @@ bool WimaPlaner::loadFromFile(const QString &filename) {
} }
if (i > 1000) { if (i > 1000) {
qWarning( qCWarning(WimaPlanerLog)
"WimaPlaner::loadFromFile(): not able to create temporary file."); << "loadFromFile(): not able to create temporary file.";
return false; return false;
} }
} }
// qWarning() << missionJsonDoc.toVariant().toString();
temporaryFile.write(missionJsonDoc.toJson()); temporaryFile.write(missionJsonDoc.toJson());
temporaryFile.close(); temporaryFile.close();
// load from temporary file // load from temporary file
_masterController->loadFromFile(temporaryFileName); _masterController->loadFromFile(temporaryFileName);
QmlObjectListModel *missionItems = _missionController->visualItems(); QmlObjectListModel *missionItems = _missionController->visualItems();
_TSComplexItem = nullptr; _survey = nullptr;
for (int i = 0; i < missionItems->count(); i++) { for (int i = 0; i < missionItems->count(); i++) {
_TSComplexItem = missionItems->value<CircularSurvey *>(i); _survey = missionItems->value<CircularSurvey *>(i);
if (_TSComplexItem != nullptr) { if (_survey != nullptr) {
_TSComplexItem->setHidePolygon(true); _survey->setHidePolygon(true);
connect(_TSComplexItem, &CircularSurvey::missionItemReady, [this] { connect(_survey, &CircularSurvey::calculatingChanged, this,
this->_surveyChanged = true; &WimaPlaner::CSCalculatingChangedHandler);
this->setNeedsUpdate(true); connect(_survey, &CircularSurvey::missionItemReady, this,
}); &WimaPlaner::CSMissionItemReadyHandler);
connect(_survey, &CircularSurvey::destroyed, this,
&WimaPlaner::CSDestroyedHandler);
break; break;
} }
} }
if (!update())
return false;
// remove temporary file // remove temporary file
if (!temporaryFile.remove()) { if (!temporaryFile.remove()) {
qWarning( qCWarning(WimaPlanerLog)
"WimaPlaner::loadFromFile(): not able to remove temporary file."); << "WimaPlaner::loadFromFile(): not able to remove "
"temporary file.";
} }
this->_synchronized = false;
emit synchronizedChanged();
return true; return true;
} else if (fileInfo.suffix() == AppSettings::planFileExtension) {
_masterController->loadFromFile(filename);
return true; // might be wrong return value
} else { } else {
errorString += QString(tr("File extension not supported.\n")); errorString += QString(tr("File extension not supported.\n"));
qgcApp()->showMessage(errorMessage.arg(errorString)); qgcApp()->showMessage(errorMessage.arg(errorString));
...@@ -678,25 +730,20 @@ void WimaPlaner::updatePolygonInteractivity(int index) { ...@@ -678,25 +730,20 @@ void WimaPlaner::updatePolygonInteractivity(int index) {
void WimaPlaner::synchronize() { void WimaPlaner::synchronize() {
if (_wimaBridge != nullptr) { if (_wimaBridge != nullptr) {
if (readyForSynchronization()) { if (!needsUpdate()) {
auto planData = toPlanData(); auto planData = toPlanData();
if (planData) { if (planData) {
(void)_wimaBridge->setWimaPlanData(planData); (void)_wimaBridge->setWimaPlanData(planData);
this->_synchronized = true; setSynchronized(true);
emit synchronizedChanged();
} else { } else {
qWarning("WimaPlaner::uploadToContainer(): error creating plan data."); qCWarning(WimaPlanerLog) << "error creating plan data.";
} }
} }
} else { } else {
qWarning("WimaPlaner::uploadToContainer(): no container assigned."); qCWarning(WimaPlanerLog) << "no container assigned.";
} }
} }
bool WimaPlaner::readyForSynchronization() {
return !_needsUpdate && _measurementArea.ready();
}
bool WimaPlaner::shortestPath(const QGeoCoordinate &start, bool WimaPlaner::shortestPath(const QGeoCoordinate &start,
const QGeoCoordinate &destination, const QGeoCoordinate &destination,
QVector<QGeoCoordinate> &path) { QVector<QGeoCoordinate> &path) {
...@@ -715,13 +762,43 @@ bool WimaPlaner::shortestPath(const QGeoCoordinate &start, ...@@ -715,13 +762,43 @@ bool WimaPlaner::shortestPath(const QGeoCoordinate &start,
return retVal; return retVal;
} }
void WimaPlaner::setNeedsUpdate(bool needsUpdate) { void WimaPlaner::setSynchronized(bool s) {
if (this->_needsUpdate != needsUpdate) { if (this->_synchronized != s) {
this->_needsUpdate = needsUpdate; this->_synchronized = s;
emit needsUpdateChanged(); emit this->synchronizedChanged();
} }
} }
void WimaPlaner::enableMonitoring() {
connect(&this->_measurementArea, &WimaArea::pathChanged, this,
&WimaPlaner::mAreaPathChangedHandler);
connect(&this->_measurementArea, &WimaMeasurementArea::tilesChanged, this,
&WimaPlaner::mAreaTilesChangedHandler);
connect(&this->_measurementArea, &WimaMeasurementArea::progressChanged, this,
&WimaPlaner::mAreaProgressChangedHandler);
connect(&this->_serviceArea, &WimaArea::pathChanged, this,
&WimaPlaner::sAreaPathChangedHandler);
connect(&this->_serviceArea, &WimaServiceArea::depotChanged, this,
&WimaPlaner::depotChangedHandler);
connect(&this->_corridor, &WimaArea::pathChanged, this,
&WimaPlaner::corridorPathChangedHandler);
}
void WimaPlaner::disableMonitoring() {
disconnect(&this->_measurementArea, &WimaArea::pathChanged, this,
&WimaPlaner::mAreaPathChangedHandler);
disconnect(&this->_measurementArea, &WimaMeasurementArea::tilesChanged, this,
&WimaPlaner::mAreaTilesChangedHandler);
disconnect(&this->_measurementArea, &WimaMeasurementArea::progressChanged,
this, &WimaPlaner::mAreaProgressChangedHandler);
disconnect(&this->_serviceArea, &WimaArea::pathChanged, this,
&WimaPlaner::sAreaPathChangedHandler);
disconnect(&this->_serviceArea, &WimaServiceArea::depotChanged, this,
&WimaPlaner::depotChangedHandler);
disconnect(&this->_corridor, &WimaArea::pathChanged, this,
&WimaPlaner::corridorPathChangedHandler);
}
void WimaPlaner::resetAllInteractive() { void WimaPlaner::resetAllInteractive() {
// Marks all areas as inactive (area.interactive == false) // Marks all areas as inactive (area.interactive == false)
int itemCount = _visualItems.count(); int itemCount = _visualItems.count();
...@@ -758,13 +835,12 @@ QSharedPointer<WimaPlanData> WimaPlaner::toPlanData() { ...@@ -758,13 +835,12 @@ QSharedPointer<WimaPlanData> WimaPlaner::toPlanData() {
// convert mission items to mavlink commands // convert mission items to mavlink commands
if (_missionController && _missionController->visualItems()) { if (_missionController && _missionController->visualItems()) {
int surveyIndex = int surveyIndex = _missionController->visualItems()->indexOf(_survey);
_missionController->visualItems()->indexOf(_TSComplexItem);
if (surveyIndex > 0) { if (surveyIndex > 0) {
QList<MissionItem *> missionItems; QList<MissionItem *> missionItems;
_TSComplexItem->appendMissionItems(missionItems, nullptr); _survey->appendMissionItems(missionItems, nullptr);
planData->append(missionItems); planData->append(missionItems);
planData->setTransects(this->_TSComplexItem->rawTransects()); planData->setTransects(this->_survey->rawTransects());
return planData; return planData;
} }
} }
...@@ -795,7 +871,7 @@ QJsonDocument WimaPlaner::saveToJson(FileType fileType) { ...@@ -795,7 +871,7 @@ QJsonDocument WimaPlaner::saveToJson(FileType fileType) {
WimaArea *area = qobject_cast<WimaArea *>(_visualItems.get(i)); WimaArea *area = qobject_cast<WimaArea *>(_visualItems.get(i));
if (area == nullptr) { if (area == nullptr) {
qWarning("WimaPlaner::saveToJson(): Internal error, area == nullptr!"); qCWarning(WimaPlanerLog) << "saveing, area == nullptr!";
return QJsonDocument(); return QJsonDocument();
} }
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include "QmlObjectListModel.h" #include "QmlObjectListModel.h"
#include <QObject> #include <QObject>
#include <QScopedPointer>
#include <QSharedPointer> #include <QSharedPointer>
#include "Geometry/WimaCorridor.h" #include "Geometry/WimaCorridor.h"
...@@ -22,6 +23,10 @@ class MissionController; ...@@ -22,6 +23,10 @@ class MissionController;
class PlanMasterController; class PlanMasterController;
class WimaBridge; class WimaBridge;
namespace wima_planer_detail {
class StateMachine;
}
class WimaPlaner : public QObject { class WimaPlaner : public QObject {
Q_OBJECT Q_OBJECT
...@@ -29,6 +34,7 @@ class WimaPlaner : public QObject { ...@@ -29,6 +34,7 @@ class WimaPlaner : public QObject {
public: public:
WimaPlaner(QObject *parent = nullptr); WimaPlaner(QObject *parent = nullptr);
~WimaPlaner();
template <class T> WimaPlaner(T t, QObject *parent = nullptr) = delete; template <class T> WimaPlaner(T t, QObject *parent = nullptr) = delete;
template <class T> WimaPlaner(T t) = delete; template <class T> WimaPlaner(T t) = delete;
...@@ -85,10 +91,9 @@ public: ...@@ -85,10 +91,9 @@ public:
/// MissionController /// MissionController
Q_INVOKABLE void removeAll(); Q_INVOKABLE void removeAll();
/// Recalculates vehicle corridor, flight path, etc. /// Recalculates vehicle corridor, flight path, etc.
Q_INVOKABLE bool update(); Q_INVOKABLE void update();
/// Pushes the generated mission data to the wimaController. /// Pushes the generated mission data to the wimaController.
Q_INVOKABLE void synchronize(); Q_INVOKABLE void synchronize();
Q_INVOKABLE bool readyForSynchronization();
Q_INVOKABLE void saveToCurrent(); Q_INVOKABLE void saveToCurrent();
Q_INVOKABLE void saveToFile(const QString &filename); Q_INVOKABLE void saveToFile(const QString &filename);
Q_INVOKABLE bool loadFromCurrent(); Q_INVOKABLE bool loadFromCurrent();
...@@ -114,6 +119,17 @@ signals: ...@@ -114,6 +119,17 @@ signals:
private slots: private slots:
void updatePolygonInteractivity(int index); void updatePolygonInteractivity(int index);
void _update();
void CSDestroyedHandler();
void CSMissionItemReadyHandler();
void CSCalculatingChangedHandler();
void mAreaPathChangedHandler();
void mAreaTilesChangedHandler();
void mAreaProgressChangedHandler();
void sAreaPathChangedHandler();
void corridorPathChangedHandler();
void depotChangedHandler();
#ifndef NDEBUG #ifndef NDEBUG
void autoLoadMission(void); void autoLoadMission(void);
#endif #endif
...@@ -121,6 +137,7 @@ private slots: ...@@ -121,6 +137,7 @@ private slots:
private: private:
signals: signals:
void joinedAreaValidChanged(); void joinedAreaValidChanged();
void stateChanged();
private: private:
// Member Functions // Member Functions
...@@ -128,7 +145,9 @@ private: ...@@ -128,7 +145,9 @@ private:
bool shortestPath(const QGeoCoordinate &start, bool shortestPath(const QGeoCoordinate &start,
const QGeoCoordinate &destination, const QGeoCoordinate &destination,
QVector<QGeoCoordinate> &path); QVector<QGeoCoordinate> &path);
void setNeedsUpdate(bool needsUpdate); void setSynchronized(bool s);
void enableMonitoring();
void disableMonitoring();
// Member Variables // Member Variables
PlanMasterController *_masterController; PlanMasterController *_masterController;
...@@ -140,9 +159,9 @@ private: ...@@ -140,9 +159,9 @@ private:
bool _joinedAreaValid; bool _joinedAreaValid;
WimaMeasurementArea _measurementArea; WimaMeasurementArea _measurementArea;
bool _mAreaChanged; bool _copyMAreaToSurvey;
WimaServiceArea _serviceArea; WimaServiceArea _serviceArea;
bool _sAreaChanged; bool _copySAreaToSurvey;
WimaCorridor _corridor; WimaCorridor _corridor;
bool _corridorChanged; bool _corridorChanged;
// contains all visible areas // contains all visible areas
...@@ -154,12 +173,11 @@ private: ...@@ -154,12 +173,11 @@ private:
// path from last measurement point to land // path from last measurement point to land
unsigned long _returnPathLength; unsigned long _returnPathLength;
CircularSurvey *_TSComplexItem; CircularSurvey *_survey;
bool _surveyChanged; bool _surveyChanged;
// sync stuff // sync stuff
bool _synchronized; // true if planData is synchronized with bool _synchronized; // true if planData is synchronized with
// wimaController // wimaController
bool _needsUpdate; // gets set by updateMission and calcArrivalAndReturnPath
#ifndef NDEBUG #ifndef NDEBUG
QTimer _autoLoadTimer; // timer to auto load mission after some time, prevents QTimer _autoLoadTimer; // timer to auto load mission after some time, prevents
...@@ -167,4 +185,7 @@ private: ...@@ -167,4 +185,7 @@ private:
#endif #endif
NemoInterface _nemoInterface; NemoInterface _nemoInterface;
// State
QScopedPointer<wima_planer_detail::StateMachine> _stateMachine;
}; };
...@@ -65,6 +65,7 @@ Item { ...@@ -65,6 +65,7 @@ Item {
function _destroyEntryCoordinate(){ function _destroyEntryCoordinate(){
if (_entryCoordinate){ if (_entryCoordinate){
map.removeMapItem(_entryCoordinate)
_entryCoordinate.destroy() _entryCoordinate.destroy()
_entryCoordinate = undefined _entryCoordinate = undefined
} }
...@@ -72,6 +73,7 @@ Item { ...@@ -72,6 +73,7 @@ Item {
function _destroyExitCoordinate(){ function _destroyExitCoordinate(){
if (_exitCoordinate){ if (_exitCoordinate){
map.removeMapItem(_exitCoordinate)
_exitCoordinate.destroy() _exitCoordinate.destroy()
_exitCoordinate = undefined _exitCoordinate = undefined
} }
...@@ -79,6 +81,7 @@ Item { ...@@ -79,6 +81,7 @@ Item {
function _destroyRefPoint(){ function _destroyRefPoint(){
if (_refPoint){ if (_refPoint){
map.removeMapItem(_refPoint)
_refPoint.destroy() _refPoint.destroy()
_refPoint = undefined _refPoint = undefined
} }
...@@ -86,6 +89,7 @@ Item { ...@@ -86,6 +89,7 @@ Item {
function _destroyTransectsComponent(){ function _destroyTransectsComponent(){
if (_transectsComponent){ if (_transectsComponent){
map.removeMapItem(_transectsComponent)
_transectsComponent.destroy() _transectsComponent.destroy()
_transectsComponent = undefined _transectsComponent = undefined
} }
......
...@@ -110,51 +110,64 @@ Item { ...@@ -110,51 +110,64 @@ Item {
// Add Snake tiles to the map // Add Snake tiles to the map
Component { Component {
id: tileComponent id: tileComponent
MapPolygon{
path: [] Item{
opacity: 0.6 id: root
z: 2
property MapPolygon polygon
MapPolygon{
id:mapPolygon
path: []
}
Component.onCompleted: {
polygon = mapPolygon
map.addMapItem(mapPolygon)
}
Component.onDestruction: {
map.removeMapItem(mapPolygon)
}
} }
} }
function getColor(progress) {
if (progress < 25)
return "transparent"
if (progress < 50)
return "orange"
if (progress < 75)
return "yellow"
if (progress < 100)
return "greenyellow"
return "limegreen"
}
Repeater { Repeater {
id: progressRepeater id: progressRepeater
property bool enable: areaItem.showTiles.value property bool enable: areaItem.showTiles.value
model: enable ? areaItem.tiles : 0 model: enable ? areaItem.tiles : []
function getColor(i) {
var progress = areaItem.progress[i]
if (progress < 25)
return "transparent"
if (progress < 50)
return "orange"
if (progress < 75)
return "yellow"
if (progress < 100)
return "greenyellow"
return "limegreen"
}
Item{ Item{
property var _tileComponent property var _tileComponent
property int _progress: _root.areaItem.progress.length
function addVisuals() { Component.onCompleted: {
_tileComponent = tileComponent.createObject(map) _tileComponent = tileComponent.createObject(map)
map.addMapItem(_tileComponent)
_tileComponent.path = object.path
_tileComponent.color = progressRepeater.getColor(index)
}
function removeVisuals() { _tileComponent.polygon.path =
_tileComponent.destroy() Qt.binding(function(){return object.path})
_tileComponent.polygon.opacity = 0.6
_tileComponent.polygon.border.color = "black"
_tileComponent.polygon.border.width = 1
_tileComponent.polygon.color =
Qt.binding(function(){return getColor(_progress)})
} }
Component.onCompleted: {
addVisuals()
}
Component.onDestruction: { Component.onDestruction: {
removeVisuals() _tileComponent.destroy()
} }
} }
} }
} }
...@@ -252,7 +252,7 @@ Rectangle { ...@@ -252,7 +252,7 @@ Rectangle {
rowSpacing: _rowSpacing rowSpacing: _rowSpacing
columnSpacing: _labelToValueSpacing columnSpacing: _labelToValueSpacing
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
// visible: _batteryInfoAvailable visible: _batteryInfoAvailable
QGCLabel { QGCLabel {
text: qsTr("Battery") text: qsTr("Battery")
......
...@@ -966,6 +966,12 @@ QGCView { ...@@ -966,6 +966,12 @@ QGCView {
checked: true checked: true
visible: QGroundControl.corePlugin.options.enablePlanViewSelector visible: QGroundControl.corePlugin.options.enablePlanViewSelector
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
onCheckedChanged:{
if (!checked){
wimaPlaner.update()
}
}
} }
QGCRadioButton { QGCRadioButton {
id: planElementMission id: planElementMission
......
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