You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
389 lines
15 KiB
389 lines
15 KiB
/**************************************************************************** |
|
* |
|
* (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. |
|
* |
|
****************************************************************************/ |
|
|
|
|
|
/** |
|
* @file |
|
* @brief QGC Map Background |
|
* @author Gus Grubba <mavlink@grubba.com> |
|
*/ |
|
|
|
import QtQuick 2.4 |
|
import QtQuick.Controls 1.3 |
|
import QtLocation 5.3 |
|
import QtPositioning 5.3 |
|
|
|
import QGroundControl 1.0 |
|
import QGroundControl.FactSystem 1.0 |
|
import QGroundControl.Controls 1.0 |
|
import QGroundControl.FlightMap 1.0 |
|
import QGroundControl.ScreenTools 1.0 |
|
import QGroundControl.MultiVehicleManager 1.0 |
|
import QGroundControl.Vehicle 1.0 |
|
import QGroundControl.Mavlink 1.0 |
|
|
|
Map { |
|
id: _map |
|
|
|
property string mapName: 'defaultMap' |
|
property bool isSatelliteMap: activeMapType.name.indexOf("Satellite") > -1 || activeMapType.name.indexOf("Hybrid") > -1 |
|
|
|
readonly property real maxZoomLevel: 20 |
|
property variant scaleLengths: [5, 10, 25, 50, 100, 150, 250, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000, 2000000] |
|
|
|
function formatDistance(meters) |
|
{ |
|
var dist = Math.round(meters) |
|
if (dist > 1000 ){ |
|
if (dist > 100000){ |
|
dist = Math.round(dist / 1000) |
|
} |
|
else{ |
|
dist = Math.round(dist / 100) |
|
dist = dist / 10 |
|
} |
|
dist = dist + " km" |
|
} |
|
else{ |
|
dist = dist + " m" |
|
} |
|
return dist |
|
} |
|
|
|
function calculateScale() { |
|
var coord1, coord2, dist, text, f |
|
f = 0 |
|
coord1 = _map.toCoordinate(Qt.point(0, scale.y)) |
|
coord2 = _map.toCoordinate(Qt.point(0 + scaleImage.sourceSize.width, scale.y)) |
|
dist = Math.round(coord1.distanceTo(coord2)) |
|
if (dist === 0) { |
|
// not visible |
|
} else { |
|
for (var i = 0; i < scaleLengths.length - 1; i++) { |
|
if (dist < (scaleLengths[i] + scaleLengths[i+1]) / 2 ) { |
|
f = scaleLengths[i] / dist |
|
dist = scaleLengths[i] |
|
break; |
|
} |
|
} |
|
if (f === 0) { |
|
f = dist / scaleLengths[i] |
|
dist = scaleLengths[i] |
|
} |
|
} |
|
text = formatDistance(dist) |
|
scaleImage.width = (scaleImage.sourceSize.width * f) - 2 * scaleImageLeft.sourceSize.width |
|
scaleText.text = text |
|
} |
|
|
|
zoomLevel: 18 |
|
center: QGroundControl.lastKnownHomePosition |
|
gesture.flickDeceleration: 3000 |
|
|
|
plugin: Plugin { name: "QGroundControl" } |
|
|
|
ExclusiveGroup { id: mapTypeGroup } |
|
|
|
property bool _initialMapPositionSet: false |
|
|
|
Connections { |
|
target: mainWindow |
|
onGcsPositionChanged: { |
|
if (!_initialMapPositionSet) { |
|
_initialMapPositionSet = true |
|
center = mainWindow.gcsPosition |
|
} |
|
} |
|
} |
|
|
|
function updateActiveMapType() { |
|
var fullMapName = QGroundControl.flightMapSettings.mapProvider + " " + QGroundControl.flightMapSettings.mapType |
|
for (var i = 0; i < _map.supportedMapTypes.length; i++) { |
|
if (fullMapName === _map.supportedMapTypes[i].name) { |
|
_map.activeMapType = _map.supportedMapTypes[i] |
|
return |
|
} |
|
} |
|
} |
|
|
|
Component.onCompleted: updateActiveMapType() |
|
|
|
Connections { |
|
target: QGroundControl.flightMapSettings |
|
onMapTypeChanged: updateActiveMapType() |
|
} |
|
|
|
MapQuickItem { |
|
anchorPoint.x: sourceItem.width / 2 |
|
anchorPoint.y: sourceItem.height / 2 |
|
visible: mainWindow.gcsPosition.isValid |
|
coordinate: mainWindow.gcsPosition |
|
sourceItem: MissionItemIndexLabel { |
|
label: "Q" |
|
} |
|
} |
|
|
|
//---- Polygon drawing code |
|
|
|
// |
|
// Usage: |
|
// |
|
// Connections { |
|
// target: map.polygonDraw |
|
// |
|
// onPolygonCaptureStarted: { |
|
// // Polygon creation has started |
|
// } |
|
// |
|
// onPolygonCaptureFinished: { |
|
// // 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 |
|
|
|
Connections { |
|
target: polygonDrawer |
|
|
|
onDrawingPolygonChanged: { |
|
if (polygonDrawer.drawingPolygon) { |
|
polygonHelp.text = qsTr("Click to add point") |
|
} |
|
polygonHelp.visible = polygonDrawer.drawingPolygon |
|
} |
|
|
|
onPolygonReadyChanged: { |
|
if (polygonDrawer.polygonReady && !ScreenTools.isMobile) { |
|
polygonHelp.text = qsTr("Click to add point - Right Click to end polygon") |
|
} |
|
} |
|
|
|
onAdjustingPolygonChanged: { |
|
if (polygonDrawer.adjustingPolygon) { |
|
polygonHelp.text = qsTr("Adjust polygon by dragging corners") |
|
} |
|
polygonHelp.visible = polygonDrawer.adjustingPolygon |
|
} |
|
} |
|
} |
|
|
|
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 adjustingPolygon: false |
|
property bool polygonReady: polygonDrawerPolygon.path.length > 3 ///< true: enough points have been captured to create a closed polygon |
|
|
|
/// New polygon capture has started |
|
signal polygonCaptureStarted |
|
|
|
/// Polygon capture is complete |
|
/// @param coordinates Map coordinates for the polygon points |
|
signal polygonCaptureFinished(var coordinates) |
|
|
|
/// Polygon adjustment has begun |
|
signal polygonAdjustStarted |
|
|
|
/// Polygon Vertex coordinate has been adjusted |
|
signal polygonAdjustVertex(int vertexIndex, var vertexCoordinate) |
|
|
|
/// Polygon adjustment finished |
|
signal polygonAdjustFinished |
|
|
|
property var _vertexDragList: [] |
|
|
|
/// Begin capturing a new polygon |
|
/// polygonCaptureStarted will be signalled |
|
function startCapturePolygon() { |
|
polygonDrawer.drawingPolygon = true |
|
polygonDrawer._clearPolygon() |
|
polygonDrawer.polygonCaptureStarted() |
|
} |
|
|
|
/// Finish capturing the polygon |
|
/// polygonCaptureFinished will be signalled |
|
/// @return true: polygon completed, false: not enough points to complete polygon |
|
function finishCapturePolygon() { |
|
if (!polygonDrawer.polygonReady) { |
|
return false |
|
} |
|
|
|
var polygonPath = polygonDrawerPolygon.path |
|
polygonPath.pop() // get rid of drag coordinate |
|
polygonDrawer._clearPolygon() |
|
polygonDrawer.drawingPolygon = false |
|
polygonDrawer.polygonCaptureFinished(polygonPath) |
|
return true |
|
} |
|
|
|
function startAdjustPolygon(vertexCoordinates) { |
|
polygonDrawer.adjustingPolygon = true |
|
for (var i=0; i<vertexCoordinates.length; i++) { |
|
var mapItem = Qt.createQmlObject( |
|
"import QtQuick 2.5; " + |
|
"import QtLocation 5.3; " + |
|
"import QGroundControl.ScreenTools 1.0; " + |
|
"Rectangle {" + |
|
" id: vertexDrag; " + |
|
" width: _sideLength; " + |
|
" height: _sideLength; " + |
|
" color: 'red'; " + |
|
"" + |
|
" property var coordinate; " + |
|
" property int index; " + |
|
"" + |
|
" readonly property real _sideLength: ScreenTools.defaultFontPixelWidth * 2; " + |
|
" readonly property real _halfSideLength: _sideLength / 2; " + |
|
"" + |
|
" Drag.active: dragMouseArea.drag.active; " + |
|
" Drag.hotSpot.x: _halfSideLength; " + |
|
" Drag.hotSpot.y: _halfSideLength; " + |
|
"" + |
|
" onXChanged: updateCoordinate(); " + |
|
" onYChanged: updateCoordinate(); " + |
|
"" + |
|
" function updateCoordinate() { " + |
|
" vertexDrag.coordinate = _map.toCoordinate(Qt.point(vertexDrag.x + _halfSideLength, vertexDrag.y + _halfSideLength), false); " + |
|
" polygonDrawer.polygonAdjustVertex(vertexDrag.index, vertexDrag.coordinate); " + |
|
" } " + |
|
"" + |
|
" function updatePosition() { " + |
|
" var vertexPoint = _map.fromCoordinate(coordinate, false); " + |
|
" vertexDrag.x = vertexPoint.x - _halfSideLength; " + |
|
" vertexDrag.y = vertexPoint.y - _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) |
|
mapItem.z = QGroundControl.zOrderMapItems + 1 |
|
mapItem.coordinate = vertexCoordinates[i] |
|
mapItem.index = i |
|
mapItem.updatePosition() |
|
polygonDrawer._vertexDragList.push(mapItem) |
|
polygonDrawer.polygonAdjustStarted() |
|
} |
|
} |
|
|
|
function finishAdjustPolygon() { |
|
polygonDrawer.adjustingPolygon = false |
|
for (var i=0; i<polygonDrawer._vertexDragList.length; i++) { |
|
polygonDrawer._vertexDragList[i].destroy() |
|
} |
|
polygonDrawer._vertexDragList = [] |
|
polygonDrawer.polygonAdjustFinished() |
|
} |
|
|
|
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) { |
|
finishCapturePolygon() |
|
} |
|
} |
|
|
|
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 |
|
} |
|
} |
|
} |
|
|
|
/// Polygon being drawn |
|
MapPolygon { |
|
id: polygonDrawerPolygon |
|
color: "blue" |
|
opacity: 0.5 |
|
visible: polygonDrawer.drawingPolygon |
|
} |
|
|
|
/// Next line for polygon |
|
MapPolyline { |
|
id: polygonDrawerNextPoint |
|
line.color: "green" |
|
line.width: 5 |
|
visible: polygonDrawer.drawingPolygon |
|
} |
|
|
|
//---- End Polygon Drawing code |
|
} // Map
|
|
|