9 changed files with 422 additions and 387 deletions
@ -0,0 +1,63 @@
@@ -0,0 +1,63 @@
|
||||
/**************************************************************************** |
||||
* |
||||
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org> |
||||
* |
||||
* QGroundControl is licensed according to the terms in the file |
||||
* COPYING.md in the root of the source code directory. |
||||
* |
||||
****************************************************************************/ |
||||
|
||||
import QtQuick 2.4 |
||||
import QtLocation 5.3 |
||||
|
||||
import QGroundControl 1.0 |
||||
import QGroundControl.ScreenTools 1.0 |
||||
import QGroundControl.Controls 1.0 |
||||
|
||||
/// Use the drag a MissionItemIndicator |
||||
Rectangle { |
||||
id: itemDragger |
||||
x: itemIndicator.x - _expandMargin |
||||
y: itemIndicator.y - _expandMargin |
||||
width: itemIndicator.width + (_expandMargin * 2) |
||||
height: itemIndicator.height + (_expandMargin * 2) |
||||
color: "transparent" |
||||
z: QGroundControl.zOrderMapItems + 1 // Above item icons |
||||
|
||||
// These are handy for debugging so left in for now |
||||
//border.width: 1 |
||||
//border.color: "white" |
||||
|
||||
// Properties which must be specific by consumer |
||||
property var itemIndicator ///< The mission item indicator to drag around |
||||
property var itemCoordinate ///< Coordinate we are updating during drag |
||||
|
||||
property bool _preventCoordinateBindingLoop: false |
||||
property real _expandMargin: ScreenTools.isMobile ? ScreenTools.defaultFontPixelWidth : 0 |
||||
|
||||
onXChanged: liveDrag() |
||||
onYChanged: liveDrag() |
||||
|
||||
function liveDrag() { |
||||
if (!itemDragger._preventCoordinateBindingLoop && Drag.active) { |
||||
var point = Qt.point(itemDragger.x + _expandMargin + itemIndicator.anchorPoint.x, itemDragger.y + _expandMargin + itemIndicator.anchorPoint.y) |
||||
var coordinate = map.toCoordinate(point) |
||||
itemDragger._preventCoordinateBindingLoop = true |
||||
coordinate.altitude = itemCoordinate.altitude |
||||
itemCoordinate = coordinate |
||||
itemDragger._preventCoordinateBindingLoop = false |
||||
} |
||||
} |
||||
|
||||
Drag.active: itemDrag.drag.active |
||||
|
||||
MouseArea { |
||||
id: itemDrag |
||||
anchors.fill: parent |
||||
drag.target: parent |
||||
drag.minimumX: 0 |
||||
drag.minimumY: 0 |
||||
drag.maximumX: itemDragger.parent.width - parent.width |
||||
drag.maximumY: itemDragger.parent.height - parent.height |
||||
} |
||||
} |
@ -0,0 +1,307 @@
@@ -0,0 +1,307 @@
|
||||
/**************************************************************************** |
||||
* |
||||
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org> |
||||
* |
||||
* QGroundControl is licensed according to the terms in the file |
||||
* COPYING.md in the root of the source code directory. |
||||
* |
||||
****************************************************************************/ |
||||
|
||||
import QtQuick 2.4 |
||||
import QtLocation 5.3 |
||||
|
||||
import QGroundControl 1.0 |
||||
import QGroundControl.ScreenTools 1.0 |
||||
import QGroundControl.Controls 1.0 |
||||
|
||||
|
||||
/// Polygon drawing item. Add to your control and call methods to get support for polygon drawing and adjustment. |
||||
Item { |
||||
id: _root |
||||
|
||||
// These properties must be provided by the consumer |
||||
property var map ///< Map control |
||||
property var callbackObject ///< Callback item |
||||
|
||||
// These properties can be queried by the consumer |
||||
property bool drawingPolygon: false |
||||
property bool adjustingPolygon: false |
||||
property bool polygonReady: _currentPolygon ? _currentPolygon.path.length > 2 : false ///< true: enough points have been captured to create a closed polygon |
||||
|
||||
property var _helpLabel ///< Dynamically added help label component |
||||
property var _newPolygon ///< Dynamically added polygon which represents all polygon points including the one currently being drawn |
||||
property var _currentPolygon ///< Dynamically added polygon which represents the currently completed polygon |
||||
property var _nextPointLine ///< Dynamically added line which goes from last polygon point to the new one being drawn |
||||
property var _mouseArea ///< Dynamically added MouseArea which handles all clicking and mouse movement |
||||
property var _vertexDragList: [ ] ///< Dynamically added vertex drag points |
||||
|
||||
/// Begin capturing a new polygon |
||||
/// polygonCaptureStarted will be signalled through callbackObject |
||||
function startCapturePolygon() { |
||||
_helpLabel = helpLabelComponent.createObject (map) |
||||
_newPolygon = newPolygonComponent.createObject (map) |
||||
_currentPolygon = currentPolygonComponent.createObject(map) |
||||
_nextPointLine = nextPointComponent.createObject (map) |
||||
_mouseArea = mouseAreaComponent.createObject (map) |
||||
|
||||
map.addMapItem(_newPolygon) |
||||
map.addMapItem(_currentPolygon) |
||||
map.addMapItem(_nextPointLine) |
||||
|
||||
drawingPolygon = true |
||||
callbackObject.polygonCaptureStarted() |
||||
} |
||||
|
||||
/// Finish capturing the polygon |
||||
/// polygonCaptureFinished will be signalled through callbackObject |
||||
/// @return true: polygon completed, false: not enough points to complete polygon |
||||
function finishCapturePolygon() { |
||||
if (!polygonReady) { |
||||
return false |
||||
} |
||||
var polygonPath = _currentPolygon.path |
||||
_cancelCapturePolygon() |
||||
callbackObject.polygonCaptureFinished(polygonPath) |
||||
return true |
||||
} |
||||
|
||||
function startAdjustPolygon(vertexCoordinates) { |
||||
adjustingPolygon = true |
||||
for (var i=0; i<vertexCoordinates.length; i++) { |
||||
var dragItem = Qt.createQmlObject( |
||||
"import QtQuick 2.5; " + |
||||
"import QtLocation 5.3; " + |
||||
"import QGroundControl.ScreenTools 1.0; " + |
||||
"" + |
||||
"Rectangle {" + |
||||
" id: vertexDrag; " + |
||||
" width: _sideLength + _expandMargin; " + |
||||
" height: _sideLength + _expandMargin; " + |
||||
" color: 'red'; " + |
||||
"" + |
||||
" property var coordinate; " + |
||||
" property int index; " + |
||||
"" + |
||||
" readonly property real _sideLength: ScreenTools.defaultFontPixelWidth * 2; " + |
||||
" readonly property real _halfSideLength: _sideLength / 2; " + |
||||
"" + |
||||
" property real _expandMargin: ScreenTools.isMobile ? ScreenTools.defaultFontPixelWidth : 0;" + |
||||
"" + |
||||
" Drag.active: dragMouseArea.drag.active; " + |
||||
"" + |
||||
" onXChanged: updateCoordinate(); " + |
||||
" onYChanged: updateCoordinate(); " + |
||||
"" + |
||||
" function updateCoordinate() { " + |
||||
" vertexDrag.coordinate = map.toCoordinate(Qt.point(vertexDrag.x + _expandMargin + _halfSideLength, vertexDrag.y + _expandMargin + _halfSideLength), false); " + |
||||
" callbackObject.polygonAdjustVertex(vertexDrag.index, vertexDrag.coordinate); " + |
||||
" } " + |
||||
"" + |
||||
" function updatePosition() { " + |
||||
" var vertexPoint = map.fromCoordinate(coordinate, false); " + |
||||
" vertexDrag.x = vertexPoint.x - _expandMargin - _halfSideLength; " + |
||||
" vertexDrag.y = vertexPoint.y - _expandMargin - _halfSideLength; " + |
||||
" } " + |
||||
"" + |
||||
" Connections { " + |
||||
" target: map; " + |
||||
" onCenterChanged: updatePosition(); " + |
||||
" onZoomLevelChanged: updatePosition(); " + |
||||
" } " + |
||||
"" + |
||||
" MouseArea { " + |
||||
" id: dragMouseArea; " + |
||||
" anchors.fill: parent; " + |
||||
" drag.target: parent; " + |
||||
" drag.minimumX: 0; " + |
||||
" drag.minimumY: 0; " + |
||||
" drag.maximumX: map.width - parent.width; " + |
||||
" drag.maximumY: map.height - parent.height; " + |
||||
" } " + |
||||
"} ", |
||||
map) |
||||
dragItem.z = QGroundControl.zOrderMapItems + 1 |
||||
dragItem.coordinate = vertexCoordinates[i] |
||||
dragItem.index = i |
||||
dragItem.updatePosition() |
||||
_vertexDragList.push(dragItem) |
||||
callbackObject.polygonAdjustStarted() |
||||
} |
||||
} |
||||
|
||||
function finishAdjustPolygon() { |
||||
_cancelAdjustPolygon() |
||||
callbackObject.polygonAdjustFinished() |
||||
} |
||||
|
||||
/// Cancels an in progress draw or adjust |
||||
function cancelPolygonEdit() { |
||||
_cancelAdjustPolygon() |
||||
_cancelCapturePolygon() |
||||
} |
||||
|
||||
function _cancelAdjustPolygon() { |
||||
adjustingPolygon = false |
||||
for (var i=0; i<_vertexDragList.length; i++) { |
||||
_vertexDragList[i].destroy() |
||||
} |
||||
_vertexDragList = [] |
||||
} |
||||
|
||||
function _cancelCapturePolygon() { |
||||
_helpLabel.destroy() |
||||
_newPolygon.destroy() |
||||
_currentPolygon.destroy() |
||||
_nextPointLine.destroy() |
||||
_mouseArea.destroy() |
||||
drawingPolygon = false |
||||
} |
||||
|
||||
Component { |
||||
id: helpLabelComponent |
||||
|
||||
QGCMapLabel { |
||||
id: polygonHelp |
||||
anchors.topMargin: parent.height - ScreenTools.availableHeight |
||||
anchors.top: parent.top |
||||
anchors.left: parent.left |
||||
anchors.right: parent.right |
||||
horizontalAlignment: Text.AlignHCenter |
||||
map: _root.map |
||||
text: qsTr("Click to add point %1").arg(ScreenTools.isMobile || !polygonReady ? "" : qsTr("- Right Click to end polygon")) |
||||
|
||||
Connections { |
||||
target: _root |
||||
|
||||
onDrawingPolygonChanged: { |
||||
if (drawingPolygon) { |
||||
polygonHelp.text = qsTr("Click to add point") |
||||
} |
||||
polygonHelp.visible = drawingPolygon |
||||
} |
||||
|
||||
onPolygonReadyChanged: { |
||||
if (polygonReady && !ScreenTools.isMobile) { |
||||
polygonHelp.text = qsTr("Click to add point - Right Click to end polygon") |
||||
} |
||||
} |
||||
|
||||
onAdjustingPolygonChanged: { |
||||
if (adjustingPolygon) { |
||||
polygonHelp.text = qsTr("Adjust polygon by dragging corners") |
||||
} |
||||
polygonHelp.visible = adjustingPolygon |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
Component { |
||||
id: mouseAreaComponent |
||||
|
||||
MouseArea { |
||||
anchors.fill: map |
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton |
||||
hoverEnabled: true |
||||
z: QGroundControl.zOrderMapItems + 1 |
||||
|
||||
property bool justClicked: false |
||||
|
||||
onClicked: { |
||||
if (mouse.button == Qt.LeftButton) { |
||||
justClicked = true |
||||
if (_newPolygon.path.length > 2) { |
||||
// Make sure the new line doesn't intersect the existing polygon |
||||
var lastSegment = _newPolygon.path.length - 2 |
||||
var newLineA = map.fromCoordinate(_newPolygon.path[lastSegment], false /* clipToViewPort */) |
||||
var newLineB = map.fromCoordinate(_newPolygon.path[lastSegment+1], false /* clipToViewPort */) |
||||
for (var i=0; i<lastSegment; i++) { |
||||
var oldLineA = map.fromCoordinate(_newPolygon.path[i], false /* clipToViewPort */) |
||||
var oldLineB = map.fromCoordinate(_newPolygon.path[i+1], false /* clipToViewPort */) |
||||
if (QGroundControl.linesIntersect(newLineA, newLineB, oldLineA, oldLineB)) { |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
|
||||
var clickCoordinate = map.toCoordinate(Qt.point(mouse.x, mouse.y)) |
||||
var polygonPath = _newPolygon.path |
||||
if (polygonPath.length == 0) { |
||||
// Add first coordinate |
||||
polygonPath.push(clickCoordinate) |
||||
} else { |
||||
// Add subsequent coordinate |
||||
if (ScreenTools.isMobile) { |
||||
// Since mobile has no mouse, the onPositionChangedHandler will not fire. We have to add the coordinate |
||||
// here instead. |
||||
justClicked = false |
||||
polygonPath.push(clickCoordinate) |
||||
} else { |
||||
// The onPositionChanged handler for mouse movement will have already added the coordinate to the array. |
||||
// Just update it to the final position |
||||
polygonPath[_newPolygon.path.length - 1] = clickCoordinate |
||||
} |
||||
} |
||||
_currentPolygon.path = polygonPath |
||||
_newPolygon.path = polygonPath |
||||
} else if (polygonReady) { |
||||
finishCapturePolygon() |
||||
} |
||||
} |
||||
|
||||
onPositionChanged: { |
||||
if (ScreenTools.isMobile) { |
||||
// We don't track mouse drag on mobile |
||||
return |
||||
} |
||||
if (_newPolygon.path.length) { |
||||
var dragCoordinate = map.toCoordinate(Qt.point(mouse.x, mouse.y)) |
||||
var polygonPath = _newPolygon.path |
||||
if (justClicked){ |
||||
// Add new drag coordinate |
||||
polygonPath.push(dragCoordinate) |
||||
justClicked = false |
||||
} |
||||
|
||||
// Update drag line |
||||
_nextPointLine.path = [ _newPolygon.path[_newPolygon.path.length - 2], dragCoordinate ] |
||||
|
||||
polygonPath[_newPolygon.path.length - 1] = dragCoordinate |
||||
_newPolygon.path = polygonPath |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// Polygon being drawn, including new point |
||||
Component { |
||||
id: newPolygonComponent |
||||
|
||||
MapPolygon { |
||||
color: "blue" |
||||
opacity: 0.5 |
||||
visible: path.length > 2 |
||||
} |
||||
} |
||||
|
||||
/// Current complete polygon |
||||
Component { |
||||
id: currentPolygonComponent |
||||
|
||||
MapPolygon { |
||||
color: 'green' |
||||
opacity: 0.5 |
||||
visible: polygonReady |
||||
} |
||||
} |
||||
|
||||
/// Next line for polygon |
||||
Component { |
||||
id: nextPointComponent |
||||
|
||||
MapPolyline { |
||||
line.color: "green" |
||||
line.width: 3 |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue