8import QGroundControl.Controls
9import QGroundControl.FlightMap
11/// QGCMapPolyline map visuals
15 property var mapControl ///< Map control to place item in
16 property var mapPolyline ///< QGCMapPolyline object
17 property bool interactive: mapPolyline.interactive
18 property int lineWidth: 3
19 property color lineColor: "#be781c"
21 property var _dragHandlesComponent
22 property var _splitHandlesComponent
23 property string _instructionText: _corridorToolsText
24 property real _zorderDragHandle: QGroundControl.zOrderMapItems + 3 // Highest to prevent splitting when items overlap
25 property real _zorderSplitHandle: QGroundControl.zOrderMapItems + 2
26 property var _savedVertices: [ ]
28 readonly property string _corridorToolsText: qsTr("Polyline Tools")
29 readonly property string _traceText: qsTr("Click in the map to add vertices. Click 'Done Tracing' when finished.")
31 function _addCommonVisuals() {
32 if (_objMgrCommonVisuals.empty) {
33 _objMgrCommonVisuals.createObject(polylineComponent, mapControl, true)
37 function _addInteractiveVisuals() {
38 if (_objMgrInteractiveVisuals.empty) {
39 _objMgrInteractiveVisuals.createObjects([ dragHandlesComponent, splitHandlesComponent, toolbarComponent ], mapControl)
43 /// Calculate the default/initial polyline
44 function _defaultPolylineVertices() {
45 var x = mapControl.centerViewport.x + (mapControl.centerViewport.width / 2)
46 var yInset = mapControl.centerViewport.height / 4
47 var topPointCoord = mapControl.toCoordinate(Qt.point(x, mapControl.centerViewport.y + yInset), false /* clipToViewPort */)
48 var bottomPointCoord = mapControl.toCoordinate(Qt.point(x, mapControl.centerViewport.y + mapControl.centerViewport.height - yInset), false /* clipToViewPort */)
49 return [ topPointCoord, bottomPointCoord ]
52 /// Reset polyline back to initial default
53 function _resetPolyline() {
54 mapPolyline.beginReset()
56 var initialVertices = _defaultPolylineVertices()
57 mapPolyline.appendVertex(initialVertices[0])
58 mapPolyline.appendVertex(initialVertices[1])
59 mapPolyline.endReset()
62 function _saveCurrentVertices() {
64 for (var i=0; i<mapPolyline.count; i++) {
65 _savedVertices.push(mapPolyline.vertexCoordinate(i))
69 function _restorePreviousVertices() {
70 mapPolyline.beginReset()
72 for (var i=0; i<_savedVertices.length; i++) {
73 mapPolyline.appendVertex(_savedVertices[i])
75 mapPolyline.endReset()
78 onInteractiveChanged: {
80 _addInteractiveVisuals()
82 _objMgrInteractiveVisuals.destroyObjects()
88 function onTraceModeChanged(traceMode) {
90 _instructionText = _traceText
91 _objMgrTraceVisuals.createObject(traceMouseAreaComponent, mapControl, false)
93 _instructionText = _corridorToolsText
94 _objMgrTraceVisuals.destroyObjects()
99 Component.onCompleted: {
102 _addInteractiveVisuals()
105 Component.onDestruction: mapPolyline.traceMode = false
107 QGCDynamicObjectManager { id: _objMgrCommonVisuals }
108 QGCDynamicObjectManager { id: _objMgrInteractiveVisuals }
109 QGCDynamicObjectManager { id: _objMgrTraceVisuals }
111 QGCPalette { id: qgcPal }
114 id: kmlOrSHPLoadDialog
115 title: qsTr("Select Polyline File")
117 onAcceptedForLoad: (file) => {
118 mapPolyline.loadKMLOrSHPFile(file)
119 mapFitFunctions.fitMapViewportToMissionItems()
126 property int _removeVertexIndex
128 function popUpWithIndex(curIndex) {
129 _removeVertexIndex = curIndex
130 removeVertexItem.visible = mapPolyline.count > 2
136 text: qsTr("Remove vertex" )
137 onTriggered: mapPolyline.removeVertex(menu._removeVertexIndex)
141 text: qsTr("Edit position..." )
142 onTriggered: editPositionDialogFactory.open({ coordinate: mapPolyline.path[menu._removeVertexIndex] })
146 QGCPopupDialogFactory {
147 id: editPositionDialogFactory
149 dialogComponent: editPositionDialog
153 id: editPositionDialog
156 onCoordinateChanged: mapPolyline.adjustVertex(menu._removeVertexIndex,coordinate)
161 id: polylineComponent
164 line.width: lineWidth
165 line.color: lineColor
166 path: mapPolyline.path
167 visible: _root.visible
168 opacity: _root.opacity
173 id: splitHandleComponent
177 anchorPoint.x: sourceItem.width / 2
178 anchorPoint.y: sourceItem.height / 2
179 z: _zorderSplitHandle
180 opacity: _root.opacity
182 property int vertexIndex
184 sourceItem: SplitIndicator {
185 onClicked: mapPolyline.splitSegment(mapQuickItem.vertexIndex)
191 id: splitHandlesComponent
194 model: mapPolyline.path
197 property var _splitHandle
198 property var _vertices: mapPolyline.path
200 opacity: _root.opacity
202 function _setHandlePosition() {
203 var nextIndex = index + 1
204 var distance = _vertices[index].distanceTo(_vertices[nextIndex])
205 var azimuth = _vertices[index].azimuthTo(_vertices[nextIndex])
206 _splitHandle.coordinate = _vertices[index].atDistanceAndAzimuth(distance / 2, azimuth)
209 Component.onCompleted: {
210 if (index + 1 <= _vertices.length - 1) {
211 _splitHandle = splitHandleComponent.createObject(mapControl)
212 _splitHandle.vertexIndex = index
214 mapControl.addMapItem(_splitHandle)
218 Component.onDestruction: {
220 _splitHandle.destroy()
227 // Control which is used to drag polygon vertices
229 id: dragAreaComponent
231 MissionItemIndicatorDrag {
232 mapControl: _root.mapControl
235 opacity: _root.opacity
237 property int polylineVertex
239 property bool _creationComplete: false
241 Component.onCompleted: _creationComplete = true
243 onItemCoordinateChanged: {
244 if (_creationComplete) {
245 // During component creation some bad coordinate values got through which screws up draw
246 mapPolyline.adjustVertex(polylineVertex, itemCoordinate)
251 menu.popUpWithIndex(polylineVertex)
258 id: dragHandleComponent
262 anchorPoint.x: dragHandle.width / 2
263 anchorPoint.y: dragHandle.height / 2
265 opacity: _root.opacity
267 property int polylineVertex
269 sourceItem: Rectangle {
271 width: ScreenTools.defaultFontPixelHeight * 1.5
274 color: Qt.rgba(1,1,1,0.8)
275 border.color: Qt.rgba(0,0,0,0.25)
281 // Add all polygon vertex drag handles to the map
283 id: dragHandlesComponent
286 model: mapPolyline.pathModel
289 property var _visuals: [ ]
291 opacity: _root.opacity
293 Component.onCompleted: {
294 var dragHandle = dragHandleComponent.createObject(mapControl)
295 dragHandle.coordinate = Qt.binding(function() { return object.coordinate })
296 dragHandle.polylineVertex = Qt.binding(function() { return index })
297 mapControl.addMapItem(dragHandle)
298 var dragArea = dragAreaComponent.createObject(mapControl, { "itemIndicator": dragHandle, "itemCoordinate": object.coordinate })
299 dragArea.polylineVertex = Qt.binding(function() { return index })
300 _visuals.push(dragHandle)
301 _visuals.push(dragArea)
304 Component.onDestruction: {
305 for (var i=0; i<_visuals.length; i++) {
306 _visuals[i].destroy()
318 anchors.horizontalCenter: mapControl.left
319 anchors.horizontalCenterOffset: mapControl.centerViewport.left + (mapControl.centerViewport.width / 2)
320 y: mapControl.centerViewport.top
321 z: QGroundControl.zOrderMapItems + 2
322 availableWidth: mapControl.centerViewport.width
325 _horizontalPadding: 0
327 visible: !mapPolyline.traceMode
328 onClicked: _resetPolyline()
332 _horizontalPadding: 0
333 text: mapPolyline.traceMode ? qsTr("Done Tracing") : qsTr("Trace")
335 if (mapPolyline.traceMode) {
336 if (mapPolyline.count < 2) {
337 _restorePreviousVertices()
339 mapPolyline.traceMode = false
341 _saveCurrentVertices()
342 mapPolyline.traceMode = true
349 _horizontalPadding: 0
350 text: qsTr("Load KML/SHP...")
351 onClicked: kmlOrSHPLoadDialog.openForLoad()
352 visible: !mapPolyline.traceMode
357 // Mouse area to capture clicks for tracing a polyline
359 id: traceMouseAreaComponent
362 anchors.fill: mapControl
363 preventStealing: true
364 z: QGroundControl.zOrderMapItems + 1 // Over item indicators
366 onClicked: (mouse) => {
367 if (mouse.button === Qt.LeftButton && _root.interactive) {
368 mapPolyline.appendVertex(mapControl.toCoordinate(Qt.point(mouse.x, mouse.y), false /* clipToViewPort */))