29 changed files with 843 additions and 507 deletions
@ -0,0 +1,108 @@
@@ -0,0 +1,108 @@
|
||||
import QtQuick 2.3 |
||||
import QtQuick.Controls 1.2 |
||||
import QtQuick.Layouts 1.2 |
||||
|
||||
import QGroundControl 1.0 |
||||
import QGroundControl.ScreenTools 1.0 |
||||
import QGroundControl.Controls 1.0 |
||||
import QGroundControl.FactControls 1.0 |
||||
import QGroundControl.Palette 1.0 |
||||
|
||||
// Camera section for mission item editors |
||||
Column { |
||||
anchors.left: parent.left |
||||
anchors.right: parent.right |
||||
spacing: _margin |
||||
|
||||
property alias exclusiveGroup: cameraSectionHeader.exclusiveGroup |
||||
property alias showSpacer: cameraSectionHeader.showSpacer |
||||
property alias checked: cameraSectionHeader.checked |
||||
|
||||
property var _camera: missionItem.cameraSection |
||||
property real _fieldWidth: ScreenTools.defaultFontPixelWidth * 16 |
||||
property real _margin: ScreenTools.defaultFontPixelWidth / 2 |
||||
|
||||
SectionHeader { |
||||
id: cameraSectionHeader |
||||
text: qsTr("Camera") |
||||
checked: false |
||||
} |
||||
|
||||
Column { |
||||
anchors.left: parent.left |
||||
anchors.right: parent.right |
||||
spacing: _margin |
||||
visible: cameraSectionHeader.checked |
||||
|
||||
FactComboBox { |
||||
id: cameraActionCombo |
||||
anchors.left: parent.left |
||||
anchors.right: parent.right |
||||
fact: _camera.cameraAction |
||||
indexModel: false |
||||
} |
||||
|
||||
RowLayout { |
||||
anchors.left: parent.left |
||||
anchors.right: parent.right |
||||
spacing: ScreenTools.defaultFontPixelWidth |
||||
visible: cameraActionCombo.currentIndex == 1 |
||||
|
||||
QGCLabel { |
||||
text: qsTr("Time") |
||||
Layout.fillWidth: true |
||||
} |
||||
FactTextField { |
||||
fact: _camera.cameraPhotoIntervalTime |
||||
Layout.preferredWidth: _fieldWidth |
||||
} |
||||
} |
||||
|
||||
RowLayout { |
||||
anchors.left: parent.left |
||||
anchors.right: parent.right |
||||
spacing: ScreenTools.defaultFontPixelWidth |
||||
visible: cameraActionCombo.currentIndex == 2 |
||||
|
||||
QGCLabel { |
||||
text: qsTr("Distance") |
||||
Layout.fillWidth: true |
||||
} |
||||
FactTextField { |
||||
fact: _camera.cameraPhotoIntervalDistance |
||||
Layout.preferredWidth: _fieldWidth |
||||
} |
||||
} |
||||
|
||||
GridLayout { |
||||
anchors.left: parent.left |
||||
anchors.right: parent.right |
||||
columnSpacing: ScreenTools.defaultFontPixelWidth / 2 |
||||
rowSpacing: 0 |
||||
columns: 3 |
||||
|
||||
Item { width: 1; height: 1 } |
||||
QGCLabel { text: qsTr("Pitch") } |
||||
QGCLabel { text: qsTr("Yaw") } |
||||
|
||||
QGCCheckBox { |
||||
id: gimbalCheckBox |
||||
text: qsTr("Gimbal") |
||||
checked: _camera.specifyGimbal |
||||
onClicked: _camera.specifyGimbal = checked |
||||
Layout.fillWidth: true |
||||
} |
||||
FactTextField { |
||||
fact: _camera.gimbalPitch |
||||
implicitWidth: ScreenTools.defaultFontPixelWidth * 9 |
||||
enabled: gimbalCheckBox.checked |
||||
} |
||||
|
||||
FactTextField { |
||||
fact: _camera.gimbalYaw |
||||
implicitWidth: ScreenTools.defaultFontPixelWidth * 9 |
||||
enabled: gimbalCheckBox.checked |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,48 @@
@@ -0,0 +1,48 @@
|
||||
[ |
||||
{ |
||||
"name": "CameraAction", |
||||
"shortDescription": "Specify whether the camera should take photos or video", |
||||
"type": "uint32", |
||||
"enumStrings": "Continue current action,Take photos (time),Take photos (distance),Take video", |
||||
"enumValues": "0,1,2,3", |
||||
"defaultValue": 0 |
||||
}, |
||||
{ |
||||
"name": "CameraPhotoIntervalDistance", |
||||
"shortDescription": "Specify the distance between each photo", |
||||
"type": "double", |
||||
"units": "m", |
||||
"min": 0, |
||||
"decimalPlaces": 1, |
||||
"defaultValue": 1 |
||||
}, |
||||
{ |
||||
"name": "CameraPhotoIntervalTime", |
||||
"shortDescription": "Specify the time between each photo", |
||||
"type": "uint32", |
||||
"units": "secs", |
||||
"min": 1, |
||||
"decimalPlaces": 0, |
||||
"defaultValue": 10 |
||||
}, |
||||
{ |
||||
"name": "GimbalPitch", |
||||
"shortDescription": "Gimbal pitch rotation.", |
||||
"type": "double", |
||||
"units": "deg", |
||||
"min": 0.0, |
||||
"max": 360.0, |
||||
"decimalPlaces": 0, |
||||
"defaultValue": 0 |
||||
}, |
||||
{ |
||||
"name": "GimbalYaw", |
||||
"shortDescription": "Gimbal yaw rotation.", |
||||
"type": "double", |
||||
"units": "deg", |
||||
"min": 0.0, |
||||
"max": 360.0, |
||||
"decimalPlaces": 0, |
||||
"defaultValue": 0 |
||||
} |
||||
] |
@ -0,0 +1,256 @@
@@ -0,0 +1,256 @@
|
||||
/****************************************************************************
|
||||
* |
||||
* (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. |
||||
* |
||||
****************************************************************************/ |
||||
|
||||
#include "CameraSection.h" |
||||
#include "SimpleMissionItem.h" |
||||
|
||||
QGC_LOGGING_CATEGORY(CameraSectionLog, "CameraSectionLog") |
||||
|
||||
const char* CameraSection::_gimbalPitchName = "GimbalPitch"; |
||||
const char* CameraSection::_gimbalYawName = "GimbalYaw"; |
||||
const char* CameraSection::_cameraActionName = "CameraAction"; |
||||
const char* CameraSection::_cameraPhotoIntervalDistanceName = "CameraPhotoIntervalDistance"; |
||||
const char* CameraSection::_cameraPhotoIntervalTimeName = "CameraPhotoIntervalTime"; |
||||
|
||||
QMap<QString, FactMetaData*> CameraSection::_metaDataMap; |
||||
|
||||
CameraSection::CameraSection(QObject* parent) |
||||
: QObject(parent) |
||||
, _available(false) |
||||
, _settingsSpecified(false) |
||||
, _specifyGimbal(false) |
||||
, _gimbalYawFact (0, _gimbalYawName, FactMetaData::valueTypeDouble) |
||||
, _gimbalPitchFact (0, _gimbalPitchName, FactMetaData::valueTypeDouble) |
||||
, _cameraActionFact (0, _cameraActionName, FactMetaData::valueTypeDouble) |
||||
, _cameraPhotoIntervalDistanceFact (0, _cameraPhotoIntervalDistanceName, FactMetaData::valueTypeDouble) |
||||
, _cameraPhotoIntervalTimeFact (0, _cameraPhotoIntervalTimeName, FactMetaData::valueTypeUint32) |
||||
, _dirty(false) |
||||
{ |
||||
if (_metaDataMap.isEmpty()) { |
||||
_metaDataMap = FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/CameraSection.FactMetaData.json"), NULL /* metaDataParent */); |
||||
} |
||||
|
||||
_gimbalPitchFact.setMetaData (_metaDataMap[_gimbalPitchName]); |
||||
_gimbalYawFact.setMetaData (_metaDataMap[_gimbalYawName]); |
||||
_cameraActionFact.setMetaData (_metaDataMap[_cameraActionName]); |
||||
_cameraPhotoIntervalDistanceFact.setMetaData (_metaDataMap[_cameraPhotoIntervalDistanceName]); |
||||
_cameraPhotoIntervalTimeFact.setMetaData (_metaDataMap[_cameraPhotoIntervalTimeName]); |
||||
|
||||
_gimbalPitchFact.setRawValue (_gimbalPitchFact.rawDefaultValue()); |
||||
_gimbalYawFact.setRawValue (_gimbalYawFact.rawDefaultValue()); |
||||
_cameraActionFact.setRawValue (_cameraActionFact.rawDefaultValue()); |
||||
_cameraPhotoIntervalDistanceFact.setRawValue (_cameraPhotoIntervalDistanceFact.rawDefaultValue()); |
||||
_cameraPhotoIntervalTimeFact.setRawValue (_cameraPhotoIntervalTimeFact.rawDefaultValue()); |
||||
|
||||
connect(this, &CameraSection::specifyGimbalChanged, this, &CameraSection::_setDirtyAndUpdateMissionItemCount); |
||||
connect(&_cameraActionFact, &Fact::valueChanged, this, &CameraSection::_setDirtyAndUpdateMissionItemCount); |
||||
|
||||
connect(&_gimbalPitchFact, &Fact::valueChanged, this, &CameraSection::_setDirty); |
||||
connect(&_gimbalYawFact, &Fact::valueChanged, this, &CameraSection::_setDirty); |
||||
connect(&_cameraPhotoIntervalDistanceFact, &Fact::valueChanged, this, &CameraSection::_setDirty); |
||||
connect(&_cameraPhotoIntervalTimeFact, &Fact::valueChanged, this, &CameraSection::_setDirty); |
||||
} |
||||
|
||||
void CameraSection::setSpecifyGimbal(bool specifyGimbal) |
||||
{ |
||||
if (specifyGimbal != _specifyGimbal) { |
||||
_specifyGimbal = specifyGimbal; |
||||
emit specifyGimbalChanged(specifyGimbal); |
||||
} |
||||
} |
||||
|
||||
int CameraSection::missionItemCount(void) const |
||||
{ |
||||
int itemCount = 0; |
||||
|
||||
if (_specifyGimbal) { |
||||
itemCount++; |
||||
} |
||||
if (_cameraActionFact.rawValue().toInt() != CameraActionNone) { |
||||
itemCount++; |
||||
} |
||||
|
||||
return itemCount; |
||||
} |
||||
|
||||
void CameraSection::setDirty(bool dirty) |
||||
{ |
||||
if (_dirty != dirty) { |
||||
_dirty = dirty; |
||||
emit dirtyChanged(_dirty); |
||||
} |
||||
} |
||||
|
||||
void CameraSection::appendMissionItems(QList<MissionItem*>& items, QObject* missionItemParent, int nextSequenceNumber) |
||||
{ |
||||
// IMPORTANT NOTE: If anything changes here you must also change CameraSection::scanForMissionSettings
|
||||
|
||||
if (_specifyGimbal) { |
||||
MissionItem* item = new MissionItem(nextSequenceNumber++, |
||||
MAV_CMD_DO_MOUNT_CONTROL, |
||||
MAV_FRAME_MISSION, |
||||
_gimbalPitchFact.rawValue().toDouble(), |
||||
0, // Gimbal roll
|
||||
_gimbalYawFact.rawValue().toDouble(), |
||||
0, 0, 0, // param 4-6 not used
|
||||
MAV_MOUNT_MODE_MAVLINK_TARGETING, |
||||
true, // autoContinue
|
||||
false, // isCurrentItem
|
||||
missionItemParent); |
||||
items.append(item); |
||||
} |
||||
|
||||
if (_cameraActionFact.rawValue().toInt() != CameraActionNone) { |
||||
MissionItem* item = NULL; |
||||
|
||||
switch (_cameraActionFact.rawValue().toInt()) { |
||||
case TakePhotosIntervalTime: |
||||
item = new MissionItem(nextSequenceNumber++, |
||||
MAV_CMD_IMAGE_START_CAPTURE, |
||||
MAV_FRAME_MISSION, |
||||
_cameraPhotoIntervalTimeFact.rawValue().toInt(), // Interval
|
||||
0, // Unlimited photo count
|
||||
-1, // Max resolution
|
||||
0, 0, // param 4-5 not used
|
||||
0, // Camera ID
|
||||
0, // param 7 not used
|
||||
true, // autoContinue
|
||||
false, // isCurrentItem
|
||||
missionItemParent); |
||||
break; |
||||
|
||||
case TakePhotoIntervalDistance: |
||||
item = new MissionItem(nextSequenceNumber++, |
||||
MAV_CMD_DO_SET_CAM_TRIGG_DIST, |
||||
MAV_FRAME_MISSION, |
||||
_cameraPhotoIntervalDistanceFact.rawValue().toDouble(), // Trigger distance
|
||||
0, 0, 0, 0, 0, 0, // param 2-7 not used
|
||||
true, // autoContinue
|
||||
false, // isCurrentItem
|
||||
missionItemParent); |
||||
break; |
||||
|
||||
case TakeVideo: |
||||
item = new MissionItem(nextSequenceNumber++, |
||||
MAV_CMD_VIDEO_START_CAPTURE, |
||||
MAV_FRAME_MISSION, |
||||
0, // Camera ID
|
||||
-1, // Max fps
|
||||
-1, // Max resolution
|
||||
0, 0, 0, 0, // param 5-7 not used
|
||||
true, // autoContinue
|
||||
false, // isCurrentItem
|
||||
missionItemParent); |
||||
break; |
||||
} |
||||
if (item) { |
||||
items.append(item); |
||||
} |
||||
} |
||||
} |
||||
|
||||
bool CameraSection::scanForCameraSection(QmlObjectListModel* visualItems, int scanIndex) |
||||
{ |
||||
bool foundGimbal = false; |
||||
bool foundCameraAction = false; |
||||
bool stopLooking = false; |
||||
|
||||
qCDebug(CameraSectionLog) << "CameraSection::scanForCameraSection" << visualItems->count() << scanIndex; |
||||
|
||||
// Scan through the initial mission items for possible mission settings
|
||||
|
||||
while (!stopLooking && visualItems->count() > scanIndex) { |
||||
SimpleMissionItem* item = visualItems->value<SimpleMissionItem*>(scanIndex); |
||||
if (!item) { |
||||
// We hit a complex item there can be no more possible mission settings
|
||||
return foundGimbal || foundCameraAction; |
||||
} |
||||
MissionItem& missionItem = item->missionItem(); |
||||
|
||||
qCDebug(CameraSectionLog) << item->command() << missionItem.param1() << missionItem.param2() << missionItem.param3() << missionItem.param4() << missionItem.param5() << missionItem.param6() << missionItem.param7() ; |
||||
|
||||
// See CameraSection::appendMissionItems for specs on what compomises a known camera section item
|
||||
|
||||
switch ((MAV_CMD)item->command()) { |
||||
case MAV_CMD_DO_MOUNT_CONTROL: |
||||
if (!foundGimbal && missionItem.param2() == 0 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == MAV_MOUNT_MODE_MAVLINK_TARGETING) { |
||||
foundGimbal = true; |
||||
setSpecifyGimbal(true); |
||||
gimbalPitch()->setRawValue(missionItem.param1()); |
||||
gimbalYaw()->setRawValue(missionItem.param3()); |
||||
visualItems->removeAt(scanIndex)->deleteLater(); |
||||
} else { |
||||
stopLooking = true; |
||||
} |
||||
break; |
||||
|
||||
case MAV_CMD_IMAGE_START_CAPTURE: |
||||
if (!foundCameraAction && missionItem.param1() != 0 && missionItem.param2() == 0 && missionItem.param3() == -1 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == 0) { |
||||
foundCameraAction = true; |
||||
cameraAction()->setRawValue(TakePhotosIntervalTime); |
||||
cameraPhotoIntervalTime()->setRawValue(missionItem.param1()); |
||||
visualItems->removeAt(scanIndex)->deleteLater(); |
||||
} else { |
||||
stopLooking = true; |
||||
} |
||||
break; |
||||
|
||||
case MAV_CMD_DO_SET_CAM_TRIGG_DIST: |
||||
if (!foundCameraAction && missionItem.param1() != 0 && missionItem.param2() == 0 && missionItem.param3() == 0 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == 0) { |
||||
foundCameraAction = true; |
||||
cameraAction()->setRawValue(TakePhotoIntervalDistance); |
||||
cameraPhotoIntervalDistance()->setRawValue(missionItem.param1()); |
||||
visualItems->removeAt(scanIndex)->deleteLater(); |
||||
} else { |
||||
stopLooking = true; |
||||
} |
||||
break; |
||||
|
||||
case MAV_CMD_VIDEO_START_CAPTURE: |
||||
if (!foundCameraAction && missionItem.param1() == 0 && missionItem.param2() == -1 && missionItem.param3() == -1 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == 0) { |
||||
foundCameraAction = true; |
||||
cameraAction()->setRawValue(TakeVideo); |
||||
visualItems->removeAt(scanIndex)->deleteLater(); |
||||
} else { |
||||
stopLooking = true; |
||||
} |
||||
break; |
||||
|
||||
default: |
||||
stopLooking = true; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
qCDebug(CameraSectionLog) << foundGimbal << foundCameraAction; |
||||
|
||||
_settingsSpecified = foundGimbal || foundCameraAction; |
||||
emit settingsSpecifiedChanged(_settingsSpecified); |
||||
|
||||
return foundGimbal || foundCameraAction; |
||||
} |
||||
|
||||
void CameraSection::_setDirty(void) |
||||
{ |
||||
setDirty(true); |
||||
} |
||||
|
||||
void CameraSection::_setDirtyAndUpdateMissionItemCount(void) |
||||
{ |
||||
emit missionItemCountChanged(missionItemCount()); |
||||
setDirty(true); |
||||
} |
||||
|
||||
void CameraSection::setAvailable(bool available) |
||||
{ |
||||
if (_available != available) { |
||||
_available = available; |
||||
emit availableChanged(available); |
||||
} |
||||
} |
@ -0,0 +1,103 @@
@@ -0,0 +1,103 @@
|
||||
/****************************************************************************
|
||||
* |
||||
* (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. |
||||
* |
||||
****************************************************************************/ |
||||
|
||||
#ifndef CameraSection_H |
||||
#define CameraSection_H |
||||
|
||||
#include "ComplexMissionItem.h" |
||||
#include "MissionItem.h" |
||||
#include "Fact.h" |
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(CameraSectionLog) |
||||
|
||||
class CameraSection : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
|
||||
public: |
||||
CameraSection(QObject* parent = NULL); |
||||
|
||||
enum CameraAction { |
||||
CameraActionNone, |
||||
TakePhotosIntervalTime, |
||||
TakePhotoIntervalDistance, |
||||
TakeVideo |
||||
}; |
||||
Q_ENUMS(CameraAction) |
||||
|
||||
Q_PROPERTY(bool available READ available WRITE setAvailable NOTIFY availableChanged) |
||||
Q_PROPERTY(bool settingsSpecified MEMBER _settingsSpecified NOTIFY settingsSpecifiedChanged) |
||||
Q_PROPERTY(bool specifyGimbal READ specifyGimbal WRITE setSpecifyGimbal NOTIFY specifyGimbalChanged) |
||||
Q_PROPERTY(Fact* gimbalPitch READ gimbalPitch CONSTANT) |
||||
Q_PROPERTY(Fact* gimbalYaw READ gimbalYaw CONSTANT) |
||||
Q_PROPERTY(Fact* cameraAction READ cameraAction CONSTANT) |
||||
Q_PROPERTY(Fact* cameraPhotoIntervalTime READ cameraPhotoIntervalTime CONSTANT) |
||||
Q_PROPERTY(Fact* cameraPhotoIntervalDistance READ cameraPhotoIntervalDistance CONSTANT) |
||||
|
||||
bool available (void) const { return _available; } |
||||
void setAvailable (bool available); |
||||
bool specifyGimbal (void) const { return _specifyGimbal; } |
||||
Fact* gimbalYaw (void) { return &_gimbalYawFact; } |
||||
Fact* gimbalPitch (void) { return &_gimbalPitchFact; } |
||||
Fact* cameraAction (void) { return &_cameraActionFact; } |
||||
Fact* cameraPhotoIntervalTime (void) { return &_cameraPhotoIntervalTimeFact; } |
||||
Fact* cameraPhotoIntervalDistance (void) { return &_cameraPhotoIntervalDistanceFact; } |
||||
|
||||
/// Scans the loaded items for the section items
|
||||
/// @param visualItems Item list
|
||||
/// @param scanIndex Index to start scanning from
|
||||
/// @return true: camera section found
|
||||
bool scanForCameraSection(QmlObjectListModel* visualItems, int scanIndex); |
||||
|
||||
/// Appends the mission items associated with this section
|
||||
/// @param items List to append to
|
||||
/// @param missionItemParent QObject parent for created MissionItems
|
||||
/// @param nextSequenceNumber Sequence number for first item
|
||||
void appendMissionItems(QList<MissionItem*>& items, QObject* missionItemParent, int nextSequenceNumber); |
||||
|
||||
void setSpecifyGimbal (bool specifyGimbal); |
||||
bool dirty (void) const { return _dirty; } |
||||
void setDirty (bool dirty); |
||||
|
||||
/// Returns the number of mission items represented by this section.
|
||||
/// Signals: missionItemCountChanged on change
|
||||
int missionItemCount(void) const; |
||||
|
||||
signals: |
||||
void availableChanged (bool available); |
||||
void settingsSpecifiedChanged (bool settingsSpecified); |
||||
void dirtyChanged (bool dirty); |
||||
bool specifyGimbalChanged (bool specifyGimbal); |
||||
void missionItemCountChanged (int missionItemCount); |
||||
|
||||
private slots: |
||||
void _setDirty(void); |
||||
void _setDirtyAndUpdateMissionItemCount(void); |
||||
|
||||
private: |
||||
bool _available; |
||||
bool _settingsSpecified; |
||||
bool _specifyGimbal; |
||||
Fact _gimbalYawFact; |
||||
Fact _gimbalPitchFact; |
||||
Fact _cameraActionFact; |
||||
Fact _cameraPhotoIntervalDistanceFact; |
||||
Fact _cameraPhotoIntervalTimeFact; |
||||
bool _dirty; |
||||
|
||||
static QMap<QString, FactMetaData*> _metaDataMap; |
||||
|
||||
static const char* _gimbalPitchName; |
||||
static const char* _gimbalYawName; |
||||
static const char* _cameraActionName; |
||||
static const char* _cameraPhotoIntervalDistanceName; |
||||
static const char* _cameraPhotoIntervalTimeName; |
||||
}; |
||||
|
||||
#endif |
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 169 B |
Loading…
Reference in new issue