地面站终端 App
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.

290 lines
9.6 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.
*
****************************************************************************/
import QtQuick 2.7
import QtQuick.Controls 1.4
import QtLocation 5.6
import QtPositioning 5.5
import QGroundControl 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Palette 1.0
import QGroundControl.Controls 1.0
import QGroundControl.FlightMap 1.0
/// Fixed Wing Landing Pattern map visuals
Item {
property var map ///< Map control to place item in
property var _missionItem: object
property var _itemVisuals: [ ]
property var _mouseArea
property var _dragAreas: [ ]
property var _loiterTangentCoordinate
property var _flightPath
readonly property int _flightPathIndex: 0
readonly property int _loiterPointIndex: 1
readonly property int _loiterRadiusIndex: 2
readonly property int _landPointIndex: 3
function hideItemVisuals() {
for (var i=0; i<_itemVisuals.length; i++) {
_itemVisuals[i].destroy()
}
_itemVisuals = [ ]
}
function showItemVisuals() {
if (_itemVisuals.length === 0) {
var itemVisual = flightPathComponent.createObject(map)
map.addMapItem(itemVisual)
_itemVisuals[_flightPathIndex] =itemVisual
itemVisual = loiterPointComponent.createObject(map)
map.addMapItem(itemVisual)
_itemVisuals[_loiterPointIndex] = itemVisual
itemVisual = loiterRadiusComponent.createObject(map)
map.addMapItem(itemVisual)
_itemVisuals[_loiterRadiusIndex] = itemVisual
itemVisual = landPointComponent.createObject(map)
map.addMapItem(itemVisual)
_itemVisuals[_landPointIndex] = itemVisual
}
}
function hideMouseArea() {
if (_mouseArea) {
_mouseArea.destroy()
_mouseArea = undefined
}
}
function showMouseArea() {
if (!_mouseArea) {
_mouseArea = mouseAreaComponent.createObject(map)
map.addMapItem(_mouseArea)
}
}
function hideDragAreas() {
for (var i=0; i<_dragAreas.length; i++) {
_dragAreas[i].destroy()
}
_dragAreas = [ ]
}
function showDragAreas() {
if (_dragAreas.length === 0) {
_dragAreas.push(loiterDragAreaComponent.createObject(map))
_dragAreas.push(landDragAreaComponent.createObject(map))
}
}
function radiansToDegrees(radians) {
return radians * (180.0 / Math.PI)
}
function calcPointTangentToCircleWithCenter() {
if (_missionItem.landingCoordSet) {
console.log("recalc")
var radius = _missionItem.loiterRadius.value
var loiterPointPixels = map.fromCoordinate(_missionItem.loiterCoordinate, false /* clipToViewport */)
var landPointPixels = map.fromCoordinate(_missionItem.landingCoordinate, false /* clipToViewport */)
var dxHypotenuse = loiterPointPixels.x - landPointPixels.x
var dyHypotenuse = loiterPointPixels.y - landPointPixels.y
var oppositeLength = radius
var hypotenuseLength = _missionItem.landingCoordinate.distanceTo(_missionItem.loiterCoordinate)
var adjacentLength = Math.sqrt(Math.pow(hypotenuseLength, 2) - Math.pow(oppositeLength, 2))
var angleToCenterRadians = -Math.atan2(dyHypotenuse, dxHypotenuse)
var angleCenterToTangentRadians = Math.asin(oppositeLength / hypotenuseLength)
var angleToTangentRadians
if (_missionItem.loiterClockwise) {
angleToTangentRadians = angleToCenterRadians - angleCenterToTangentRadians
} else {
angleToTangentRadians = angleToCenterRadians + angleCenterToTangentRadians
}
var angleToTangentDegrees = (radiansToDegrees(angleToTangentRadians) - 90) * -1
/*
Keep in for debugging for now
console.log("dxHypotenuse", dxHypotenuse)
console.log("dyHypotenuse", dyHypotenuse)
console.log("oppositeLength", oppositeLength)
console.log("hypotenuseLength", hypotenuseLength)
console.log("adjacentLength", adjacentLength)
console.log("angleCenterToTangentRadians", angleCenterToTangentRadians, radiansToDegrees(angleCenterToTangentRadians))
console.log("angleToCenterRadians", angleToCenterRadians, radiansToDegrees(angleToCenterRadians))
console.log("angleToTangentDegrees", angleToTangentDegrees)
*/
_loiterTangentCoordinate = _missionItem.landingCoordinate.atDistanceAndAzimuth(adjacentLength, angleToTangentDegrees)
_flightPath = [ _loiterTangentCoordinate, _missionItem.landingCoordinate ]
} else {
_flightPath = undefined
}
}
Component.onCompleted: {
if (_missionItem.landingCoordSet) {
showItemVisuals()
if (_missionItem.isCurrentItem) {
showDragAreas()
}
} else if (_missionItem.isCurrentItem) {
showMouseArea()
}
calcPointTangentToCircleWithCenter()
}
Component.onDestruction: {
hideDragAreas()
hideMouseArea()
hideItemVisuals()
}
Connections {
target: _missionItem
onIsCurrentItemChanged: {
if (_missionItem.isCurrentItem) {
if (_missionItem.landingCoordSet) {
showDragAreas()
} else {
showMouseArea()
}
} else {
hideMouseArea()
hideDragAreas()
}
}
onLandingCoordSetChanged: {
if (_missionItem.landingCoordSet) {
hideMouseArea()
showItemVisuals()
showDragAreas()
} else if (_missionItem.isCurrentItem) {
hideDragAreas()
showMouseArea()
}
calcPointTangentToCircleWithCenter()
}
onLandingCoordinateChanged: calcPointTangentToCircleWithCenter()
onLoiterCoordinateChanged: calcPointTangentToCircleWithCenter()
onLoiterClockwiseChanged: calcPointTangentToCircleWithCenter()
}
// Mouse area to capture landing point coordindate
Component {
id: mouseAreaComponent
MouseArea {
anchors.fill: map
onClicked: {
var coordinate = map.toCoordinate(Qt.point(mouse.x, mouse.y))
coordinate.latitude = coordinate.latitude.toFixed(_decimalPlaces)
coordinate.longitude = coordinate.longitude.toFixed(_decimalPlaces)
coordinate.altitude = coordinate.altitude.toFixed(_decimalPlaces)
_missionItem.landingCoordinate = coordinate
}
}
}
// Control which is used to drag the loiter point
Component {
id: loiterDragAreaComponent
MissionItemIndicatorDrag {
itemIndicator: _itemVisuals[_loiterPointIndex]
itemCoordinate: _missionItem.loiterCoordinate
onItemCoordinateChanged: _missionItem.loiterCoordinate = itemCoordinate
}
}
// Control which is used to drag the loiter point
Component {
id: landDragAreaComponent
MissionItemIndicatorDrag {
itemIndicator: _itemVisuals[_landPointIndex]
itemCoordinate: _missionItem.landingCoordinate
onItemCoordinateChanged: _missionItem.landingCoordinate = itemCoordinate
}
}
// Flight path
Component {
id: flightPathComponent
MapPolyline {
z: QGroundControl.zOrderMapItems - 1 // Under item indicators
line.color: "#be781c"
line.width: 2
path: _flightPath
}
}
// Loiter point
Component {
id: loiterPointComponent
MapQuickItem {
anchorPoint.x: sourceItem.anchorPointX
anchorPoint.y: sourceItem.anchorPointY
z: QGroundControl.zOrderMapItems
coordinate: _missionItem.loiterCoordinate
sourceItem:
MissionItemIndexLabel {
label: "Loiter"
checked: _missionItem.isCurrentItem
onClicked: setCurrentItem(_missionItem.sequenceNumber)
}
}
}
// Loiter radius visual
Component {
id: loiterRadiusComponent
MapCircle {
z: QGroundControl.zOrderMapItems
center: _missionItem.loiterCoordinate
radius: _missionItem.loiterRadius.value
border.width: 2
border.color: "green"
color: "transparent"
}
}
// Land point
Component {
id: landPointComponent
MapQuickItem {
anchorPoint.x: sourceItem.anchorPointX
anchorPoint.y: sourceItem.anchorPointY
z: QGroundControl.zOrderMapItems
coordinate: _missionItem.landingCoordinate
sourceItem:
MissionItemIndexLabel {
label: "Land"
checked: _missionItem.isCurrentItem
onClicked: setCurrentItem(_missionItem.sequenceNumber)
}
}
}
}