Commit a47e3711 authored by Don Gagne's avatar Don Gagne Committed by GitHub

Merge pull request #3793 from DonLakeFlyer/MapPolygon

Map polygon drawing tool
parents b5164290 075a07d4
......@@ -128,4 +128,152 @@ Map {
label: "Q"
}
}
//---- Polygon drawing code
//
// Usage:
//
// Connections {
// target: map.polygonDraw
//
// onPolygonStarted: {
// // Polygon creation has started
// }
//
// onPolygonFinished: {
// // Polygon capture complete, coordinates signal variable contains the polygon points
// }
// }
//
// map.polygonDraqw.startPolgyon() - begin capturing a new polygon
// map.polygonDraqw.endPolygon() - end capture (right-click will also end capture)
// Not sure why this is needed, but trying to reference polygonDrawer directly from other code doesn't work
property alias polygonDraw: polygonDrawer
QGCLabel {
id: polygonHelp
anchors.topMargin: parent.height - ScreenTools.availableHeight
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
horizontalAlignment: Text.AlignHCenter
text: qsTr("Click to add point %1").arg(ScreenTools.isMobile || !polygonDrawer.polygonReady ? "" : qsTr("- Right Click to end polygon"))
visible: polygonDrawer.drawingPolygon
}
MouseArea {
id: polygonDrawer
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
visible: drawingPolygon
z: 1000 // Hack to fix MouseArea layering for now
property alias drawingPolygon: polygonDrawer.hoverEnabled
property bool polygonReady: polygonDrawerPolygon.path.length > 3 ///< true: enough points have been captured to create a closed polygon
/// New polygon capture has started
signal polygonStarted
/// Polygon capture is complete
/// @param coordinates Map coordinates for the polygon points
signal polygonFinished(var coordinates)
/// Begin capturing a new polygon
/// polygonStarted will be signalled
function startPolygon() {
polygonDrawer.drawingPolygon = true
polygonDrawer._clearPolygon()
polygonDrawer.polygonStarted()
}
/// Finish capturing the polygon
/// polygonFinished will be signalled
/// @return true: polygon completed, false: not enough points to complete polygon
function finishPolygon() {
if (!polygonDrawer.polygonReady) {
return false
}
var polygonPath = polygonDrawerPolygon.path
polygonPath.pop() // get rid of drag coordinate
polygonDrawer._clearPolygon()
polygonDrawer.drawingPolygon = false
polygonDrawer.polygonFinished(polygonPath)
return true
}
function _clearPolygon() {
// Simpler methods to clear the path simply don't work due to bugs. This craziness does.
var bogusCoord = _map.toCoordinate(Qt.point(height/2, width/2))
polygonDrawerPolygon.path = [ bogusCoord, bogusCoord ]
polygonDrawerNextPoint.path = [ bogusCoord, bogusCoord ]
polygonDrawerPolygon.path = [ ]
polygonDrawerNextPoint.path = [ ]
}
onClicked: {
if (mouse.button == Qt.LeftButton) {
if (polygonDrawerPolygon.path.length > 2) {
// Make sure the new line doesn't intersect the existing polygon
var lastSegment = polygonDrawerPolygon.path.length - 2
var newLineA = _map.fromCoordinate(polygonDrawerPolygon.path[lastSegment], false /* clipToViewPort */)
var newLineB = _map.fromCoordinate(polygonDrawerPolygon.path[lastSegment+1], false /* clipToViewPort */)
for (var i=0; i<lastSegment; i++) {
var oldLineA = _map.fromCoordinate(polygonDrawerPolygon.path[i], false /* clipToViewPort */)
var oldLineB = _map.fromCoordinate(polygonDrawerPolygon.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 = polygonDrawerPolygon.path
if (polygonPath.length == 0) {
// Add first coordinate
polygonPath.push(clickCoordinate)
} else {
// Update finalized coordinate
polygonPath[polygonDrawerPolygon.path.length - 1] = clickCoordinate
}
// Add next drag coordinate
polygonPath.push(clickCoordinate)
polygonDrawerPolygon.path = polygonPath
} else if (polygonDrawer.polygonReady) {
finishPolygon()
}
}
onPositionChanged: {
if (polygonDrawerPolygon.path.length) {
var dragCoordinate = _map.toCoordinate(Qt.point(mouse.x, mouse.y))
// Update drag line
polygonDrawerNextPoint.path = [ polygonDrawerPolygon.path[polygonDrawerPolygon.path.length - 2], dragCoordinate ]
// Update drag coordinate
var polygonPath = polygonDrawerPolygon.path
polygonPath[polygonDrawerPolygon.path.length - 1] = dragCoordinate
polygonDrawerPolygon.path = polygonPath
}
}
}
MapPolygon {
id: polygonDrawerPolygon
color: "blue"
opacity: 0.5
visible: polygonDrawer.drawingPolygon
}
MapPolyline {
id: polygonDrawerNextPoint
line.color: "green"
line.width: 5
visible: polygonDrawer.drawingPolygon
}
//---- End Polygon Drawing code
} // Map
......@@ -19,8 +19,7 @@ Rectangle {
//property real availableWidth ///< Width for control
//property var missionItem ///< Mission Item for editor
property bool _addPointsMode: false
property real _margin: ScreenTools.defaultFontPixelWidth / 2
property real _margin: ScreenTools.defaultFontPixelWidth / 2
QGCPalette { id: qgcPal; colorGroupEnabled: true }
......@@ -32,16 +31,6 @@ Rectangle {
anchors.right: parent.right
spacing: _margin
Connections {
target: editorMap
onMapClicked: {
if (_addPointsMode) {
missionItem.addPolygonCoordinate(coordinate)
}
}
}
QGCLabel {
wrapMode: Text.WordWrap
font.pointSize: ScreenTools.smallFontPointSize
......@@ -109,14 +98,29 @@ Rectangle {
}
}
Connections {
target: editorMap.polygonDraw
onPolygonStarted: {
missionItem.clearPolygon()
}
onPolygonFinished: {
for (var i=0; i<coordinates.length; i++) {
missionItem.addPolygonCoordinate(coordinates[i])
}
}
}
QGCButton {
text: _addPointsMode ? qsTr("Finish Polygon") : qsTr("Draw Polygon")
text: editorMap.polygonDraw.drawingPolygon ? qsTr("Finish Polygon") : qsTr("Draw Polygon")
enabled: (editorMap.polygonDraw.drawingPolygon && editorMap.polygonDraw.polygonReady) || !editorMap.polygonDraw.drawingPolygon
onClicked: {
if (_addPointsMode) {
_addPointsMode = false
if (editorMap.polygonDraw.drawingPolygon) {
editorMap.polygonDraw.finishPolygon()
} else {
missionItem.clearPolygon()
_addPointsMode = true
editorMap.polygonDraw.startPolygon()
}
}
}
......
......@@ -14,6 +14,8 @@
#include "QGroundControlQmlGlobal.h"
#include <QSettings>
#include <QLineF>
#include <QPointF>
static const char* kQmlGlobalKeyName = "QGCQml";
......@@ -264,3 +266,11 @@ Fact* QGroundControlQmlGlobal::speedUnits(void)
return _speedUnitsFact;
}
bool QGroundControlQmlGlobal::linesIntersect(QPointF line1A, QPointF line1B, QPointF line2A, QPointF line2B)
{
QPointF intersectPoint;
return QLineF(line1A, line1B).intersect(QLineF(line2A, line2B), &intersectPoint) == QLineF::BoundedIntersection &&
intersectPoint != line1A && intersectPoint != line1B;
}
......@@ -130,6 +130,8 @@ public:
/// Updates the logging filter rules after settings have changed
Q_INVOKABLE void updateLoggingFilterRules(void) { QGCLoggingCategoryRegister::instance()->setFilterRulesFromSettings(QString()); }
Q_INVOKABLE bool linesIntersect(QPointF xLine1, QPointF yLine1, QPointF xLine2, QPointF yLine2);
// Property accesors
FlightMapSettings* flightMapSettings () { return _flightMapSettings; }
......
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