Commit ab5abb37 authored by Valentin Platzgummer's avatar Valentin Platzgummer

proper pictures added to MeasurementItemEditor.qml

parent 1b05f323
......@@ -18,7 +18,7 @@
<file alias="counter-clockwise-arrow.svg">resources/counter-clockwise-arrow.svg</file>
<file alias="chevron-down.svg">resources/chevron-down.svg</file>
<file alias="chevron-up.svg">resources/chevron-up.svg</file>
<file alias="DropArrow.svg">resources/DropArrow.svg</file>
<file alias="DropArrow.svg">resources/DropArrow.svg</file>
<file alias="gear-black.svg">resources/gear-black.svg</file>
<file alias="gear-white.svg">resources/gear-white.svg</file>
<file alias="helicoptericon.svg">resources/helicoptericon.svg</file>
......@@ -34,7 +34,7 @@
<file alias="Play">resources/Play.svg</file>
<file alias="PowerButton">resources/PowerButton.svg</file>
<file alias="QGCLogoBlack">resources/QGCLogoBlack.svg</file>
<file alias="QGCLogoFull">resources/QGCLogoFull.svg</file>
<file alias="QGCLogoFull">resources/QGCLogoFull.svg</file>
<file alias="QGCLogoWhite">resources/QGCLogoWhite.svg</file>
<file alias="QGCLogoArrow">resources/QGCLogoArrow.svg</file>
<file alias="QGroundControlConnect">resources/QGroundControlConnect.svg</file>
......@@ -56,6 +56,7 @@
<file alias="street.png">resources/street.png</file>
<file alias="measurement.png">resources/measurement.png</file>
<file alias="calculator.png">resources/calculator.png</file>
<file alias="fish.svg">resources/fish.svg</file>
</qresource>
<qresource prefix="/res/firmware">
<file alias="3drradio.png">resources/firmware/3drradio.png</file>
......
......@@ -293,6 +293,7 @@
<file alias="MeasurementComplexItem/AreaDataEditor.qml">src/MeasurementComplexItem/qml/AreaDataEditor.qml</file>
<file alias="MeasurementComplexItem/ParameterEditor.qml">src/MeasurementComplexItem/qml/ParameterEditor.qml</file>
<file alias="MeasurementComplexItem/qmldir">src/MeasurementComplexItem/qml/MeasurementComplexItem.qmldir</file>
<file alias="MeasurementComplexItem/NemoEditor.qml">src/MeasurementComplexItem/qml/NemoEditor.qml</file>
</qresource>
<qresource prefix="/FirstRunPromptDialogs">
<file alias="UnitsFirstRunPrompt.qml">src/FirstRunPromptDialogs/UnitsFirstRunPrompt.qml</file>
......
[Dolphin]
PreviewsShown=true
Timestamp=2020,12,19,15,18,21
Version=4
fish.svg: from https://commons.wikimedia.org/wiki/File:Font_Awesome_5_solid_fish.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M327.1 96c-89.97 0-168.54 54.77-212.27 101.63L27.5 131.58c-12.13-9.18-30.24.6-27.14 14.66L24.54 256 .35 365.77c-3.1 14.06 15.01 23.83 27.14 14.66l87.33-66.05C158.55 361.23 237.13 416 327.1 416 464.56 416 576 288 576 256S464.56 96 327.1 96zm87.43 184c-13.25 0-24-10.75-24-24 0-13.26 10.75-24 24-24 13.26 0 24 10.74 24 24 0 13.25-10.75 24-24 24z"/></svg>
<!--
Font Awesome Free 5.2.0 by @fontawesome - https://fontawesome.com
License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
-->
\ No newline at end of file
......@@ -126,8 +126,9 @@ bool AreaData::isCorrect(bool showError) {
// ss << "safeAreaENU: " << bg::wkt(safeAreaENU) << std::endl;
// qDebug() << ss.str().c_str();
if (!bg::covered_by(measurementAreaENU, safeAreaENU)) {
_processError(tr("Measurement Area not inside Safe Area. Please adjust "
"the Measurement Area.\n"),
_processError(tr("Measurement Area is not covered by Safe "
"Area. Please adjust "
"the areas accordingly.\n"),
showError);
return false;
}
......@@ -228,10 +229,10 @@ void AreaData::intersection(bool showError) {
boost::geometry::intersection(measurementAreaENU, safeAreaENU, outputENU);
if (outputENU.size() < 1 || outputENU[0].outer().size() < 4) {
_processError(
"Intersection did't deliver any result. Measurement Area and "
"Safe Area must touch each other.",
showError);
_processError("Intersection did't deliver any result. The Measurement "
"Area(s) and "
"The Safe Area must touch each other.",
showError);
return;
}
......@@ -266,11 +267,29 @@ void AreaData::intersection(bool showError) {
}
}
MeasurementArea *AreaData::measurementArea() {
return getGeoArea<MeasurementArea *>(_areaList);
QVector<MeasurementArea *> AreaData::measurementAreaArray() {
return getGeoAreaList<MeasurementArea *, QVector>(_areaList);
}
QVector<SafeArea *> AreaData::safeAreaArray() {
return getGeoAreaList<SafeArea *, QVector>(_areaList);
}
SafeArea *AreaData::safeArea() { return getGeoArea<SafeArea *>(_areaList); }
QmlObjectListModel *AreaData::measurementAreaList() {
_measurementAreaList.clear();
auto array = getGeoAreaList<MeasurementArea *, QVector>(_areaList);
for (auto area : array)
_measurementAreaList.append(area);
return &_measurementAreaList;
}
QmlObjectListModel *AreaData::safeAreaList() {
_safeAreaList.clear();
auto array = getGeoAreaList<SafeArea *, QVector>(_areaList);
for (auto &area : array)
_safeAreaList.append(area);
return &_safeAreaList;
}
bool AreaData::operator==(const AreaData &other) const {
if (_areaList.count() == other._areaList.count()) {
......@@ -442,13 +461,13 @@ bool AreaData::_getAreas(MeasurementArea **measurementArea, SafeArea **safeArea,
*measurementArea = getGeoArea<MeasurementArea *>(_areaList);
if (*measurementArea == nullptr) {
_processError(
tr("Measurement Area missing. Please define a measurement area."),
tr("Measurement Area is missing. Please define a Measurement Area."),
showError);
return false;
}
*safeArea = getGeoArea<SafeArea *>(_areaList);
if (*safeArea == nullptr) {
_processError(tr("Safe Area missing. Please define a safe area."),
_processError(tr("Safe Area is missing. Please define a Safe Area."),
showError);
return false;
}
......
......@@ -20,6 +20,10 @@ public:
AreaData &operator=(const AreaData &other);
Q_PROPERTY(QmlObjectListModel *areaList READ areaList NOTIFY areaListChanged)
Q_PROPERTY(QmlObjectListModel *measurementAreaList READ measurementAreaList
NOTIFY areaListChanged)
Q_PROPERTY(
QmlObjectListModel *safeAreaList READ safeAreaList NOTIFY areaListChanged)
Q_PROPERTY(QString errorString READ errorString NOTIFY error)
// Member Methodes
......@@ -70,8 +74,10 @@ public:
Q_INVOKABLE bool initialized();
Q_INVOKABLE void intersection(bool showError = true);
Q_INVOKABLE MeasurementArea *measurementArea();
Q_INVOKABLE SafeArea *safeArea();
QVector<MeasurementArea *> measurementAreaArray();
QVector<SafeArea *> safeAreaArray();
QmlObjectListModel *measurementAreaList();
QmlObjectListModel *safeAreaList();
bool operator==(const AreaData &other) const;
bool operator!=(const AreaData &other) const;
......@@ -97,5 +103,7 @@ private:
QGeoCoordinate _origin;
QmlObjectListModel _areaList;
QmlObjectListModel _measurementAreaList;
QmlObjectListModel _safeAreaList;
QString _errorString;
};
......@@ -83,9 +83,9 @@ private:
std::map<QString, Creator> _creatorMap;
};
#define pGeneratorFactory ::routing::GeneratorFactory::instance()
#define REGISTER_GENERATOR(type, creator) \
namespace { \
auto registered = \
GeneratorFactory::instance() -> registerGenerator(type, creator); \
auto registered = pGeneratorFactory -> registerGenerator(type, creator); \
}
} // namespace routing
......@@ -3,6 +3,8 @@
#include <QScopedPointer>
#include <QtGlobal>
// from https://stackoverflow.com/questions/46172607/qt-singleton-implementation
template <class T> class GenericSingelton {
private:
typedef T *(*CreateInstanceFunction)();
......
......@@ -247,8 +247,7 @@ bool MeasurementComplexItem::load(const QJsonObject &complexObject,
QString e;
// create generator
auto gen = routing::GeneratorFactory::instance()->create(
jsonGen, e, &parent /*parent*/);
auto gen = pGeneratorFactory->create(jsonGen, e, &parent /*parent*/);
if (gen != nullptr) {
// remove generators of same type and insert this generator.
......@@ -267,7 +266,7 @@ bool MeasurementComplexItem::load(const QJsonObject &complexObject,
errorString.append(
tr("Error loading generator of type ") +
jsonGen[routing::GeneratorBase::typeKey].toString() + ".\n");
if (!routing::GeneratorFactory::instance()->registered(
if (!pGeneratorFactory->registered(
jsonGen[routing::GeneratorBase::typeKey].toString())) {
errorString.append(tr("This type is unknown.\n"));
qCritical()
......@@ -360,8 +359,10 @@ bool MeasurementComplexItem::load(const QJsonObject &complexObject,
// Check if variants are covered by safe area.
if (variantsSuccess) {
auto safeArea = _pCurrentData->safeArea();
if (safeArea != nullptr) {
auto safeAreaArray = _pCurrentData->safeAreaArray();
if (safeAreaArray.size() > 0 && safeAreaArray.at(0) != nullptr) {
auto safeArea = safeAreaArray[0];
QGeoCoordinate origin =
safeArea->pathModel().value<QGCQGeoCoordinate *>(0)->coordinate();
snake::FPolygon safeAreaENU;
......@@ -733,8 +734,11 @@ void MeasurementComplexItem::_updateFlightpathSegments() {
if (hasCollisionOld != hasCollision) {
emit terrainCollisionChanged(hasCollision);
}
if (_pAreaData->measurementArea() != nullptr) {
_pAreaData->measurementArea()->setShowAltColor(hasCollision);
auto measurementAreaArray = _pAreaData->measurementAreaArray();
for (auto area : measurementAreaArray) {
if (area != nullptr) {
area->setShowAltColor(hasCollision);
}
}
_masterController->missionController()->recalcTerrainProfile();
......@@ -782,6 +786,20 @@ void MeasurementComplexItem::_updateRoute() {
if (this->_pAreaData->isCorrect()) {
auto measurmentAreaArray = _pAreaData->measurementAreaArray();
bool measurementComplete = true;
for (const auto &area : measurmentAreaArray) {
if (!area->measurementCompleted()) {
measurementComplete = false;
}
}
if (measurementComplete) {
qCDebug(MeasurementComplexItemLog)
<< "_updateWorker(): measurement complete!";
return;
}
// Prepare data.
auto origin = this->_pAreaData->origin();
origin.setAltitude(0);
......@@ -1039,13 +1057,13 @@ void MeasurementComplexItem::resetGenerators() {
removeGenerator(0);
}
auto lg = routing::GeneratorFactory::instance()->create(
routing::LinearGenerator::typeString, this);
auto lg =
pGeneratorFactory->create(routing::LinearGenerator::typeString, this);
lg->setData(this->_pAreaData);
addGenerator(lg);
auto cg = routing::GeneratorFactory::instance()->create(
routing::CircularGenerator::typeString, this);
auto cg =
pGeneratorFactory->create(routing::CircularGenerator::typeString, this);
cg->setData(this->_pAreaData);
addGenerator(cg);
}
......@@ -1139,6 +1157,24 @@ void MeasurementComplexItem::abortEditing() {
}
}
void MeasurementComplexItem::reset() {
if (editing()) {
*_pEditorData = *_pAreaData;
}
}
bool MeasurementComplexItem::initialize(const QGeoCoordinate &bottomLeft,
const QGeoCoordinate &topRight) {
bool r1 = _pAreaData->initialize(bottomLeft, topRight);
bool r2 = _pEditorData->initialize(bottomLeft, topRight);
return r1 && r2;
}
bool MeasurementComplexItem::initialized() {
return _pCurrentData->initialized();
}
void MeasurementComplexItem::_storeRoutingData(
MeasurementComplexItem::PtrRoutingData pRoute) {
if (this->_state == STATE::ROUTING) {
......
......@@ -174,6 +174,31 @@ public:
//! editingStart().
//!
Q_INVOKABLE void abortEditing();
//!
//! \brief reset Resets the areas to the state before startEditing().
//!
//! Resets the areas to the state before startEditing(). Does nothing if
//! editinge() == false.
//!
Q_INVOKABLE void reset();
//!
//! \brief initialize Initializes the areas in a valid way, such that they
//! area inside the bounding box. \param bottomLeft bottom left corner of the
//! bounding box. \param topRight top right corner of the bounding box. \note
//! Behavior is undefined, if \p bottomLeft and \p topRight are not the bottom
//! left and the top right corner of the bounding box. \return Returns true on
//! succes, false either.
//!
Q_INVOKABLE bool initialize(const QGeoCoordinate &bottomLeft,
const QGeoCoordinate &topRight);
//!
//! \brief initialized Checks if area data is initialized
//! \return Returns true if area list contains a SafeArea and a
//! MeasurementArea and both areas have at least three vertices, returns false
//! either.
//!
Q_INVOKABLE bool initialized();
// Property getters
const AreaData *areaData() const;
......
......@@ -12,6 +12,7 @@
#include <QTimer>
#include "GenericSingelton.h"
#include "geometry/MeasurementArea.h"
#include "geometry/snake.h"
#include "nemo_interface/QNemoHeartbeat.h"
......@@ -426,8 +427,15 @@ bool NemoInterface::Impl::setStatus(NemoInterface::STATUS s) {
// ===============================================================
// NemoInterface
NemoInterface::NemoInterface(QObject *parent)
: QObject(parent), pImpl(std::make_unique<NemoInterface::Impl>(this)) {}
NemoInterface::NemoInterface()
: QObject(), pImpl(std::make_unique<NemoInterface::Impl>(this)) {}
NemoInterface *NemoInterface::createInstance() { return new NemoInterface(); }
NemoInterface *NemoInterface::instance() {
return GenericSingelton<NemoInterface>::instance(
NemoInterface::createInstance);
}
NemoInterface::~NemoInterface() {}
......@@ -449,9 +457,7 @@ bool NemoInterface::hasTileData(const TileData &tileData) const {
return this->pImpl->hasTileData(tileData);
}
int NemoInterface::status() const { return integral(this->pImpl->status()); }
NemoInterface::STATUS NemoInterface::statusEnum() const {
NemoInterface::STATUS NemoInterface::status() const {
return this->pImpl->status();
}
......
......@@ -12,7 +12,14 @@ class NemoInterface : public QObject {
class Impl;
using PImpl = std::unique_ptr<Impl>;
NemoInterface();
NemoInterface(NemoInterface &other) = delete;
static NemoInterface *createInstance();
public:
~NemoInterface() override;
static NemoInterface *instance();
enum class STATUS {
NOT_CONNECTED = 0,
HEARTBEAT_DETECTED = 1,
......@@ -20,11 +27,9 @@ public:
TIMEOUT = -1,
INVALID_HEARTBEAT = -2
};
Q_ENUM(STATUS)
explicit NemoInterface(QObject *parent = nullptr);
~NemoInterface() override;
Q_PROPERTY(int status READ status NOTIFY statusChanged)
Q_PROPERTY(STATUS status READ status NOTIFY statusChanged)
Q_PROPERTY(QString statusString READ statusString NOTIFY statusChanged)
Q_PROPERTY(QVector<int> progress READ progress NOTIFY progressChanged)
Q_PROPERTY(QString editorQml READ editorQml CONSTANT)
......@@ -40,8 +45,7 @@ public:
void setAutoPublish(bool ap);
void setHoldProgress(bool hp);
int status() const;
STATUS statusEnum() const;
STATUS status() const;
QString statusString() const;
QVector<int> progress() const;
QString editorQml();
......@@ -55,3 +59,5 @@ signals:
private:
PImpl pImpl;
};
#define pNemoInterface NemoInterface::instance()
......@@ -56,8 +56,14 @@ private:
// Example usage:
// QmlObjecListModel list;
// .... add areas ....
// auto area = getArea<WimaMeasurementArea *>(list); // returns the first
// WimaMeasurementArea or nullptr
// auto area = getGeoArea<MeasurementArea *>(list); // returns the first
// MeasurementArea or nullptr
//! \example
//!
//! QmlObjecListModel list;
//! // .... add areas ....
//! auto area = getGeoArea<MeasurementArea *>(list); // returns the first
//! MeasurementArea or nullptr
template <class AreaPtr, class QObjectList>
inline AreaPtr getGeoArea(QObjectList &list) {
static_assert(std::is_pointer<AreaPtr>::value,
......@@ -72,5 +78,28 @@ inline AreaPtr getGeoArea(QObjectList &list) {
return nullptr;
}
//! \example
//!
//! QmlObjecListModel list;
//! // .... add areas ....
//! auto areaArray = getGeoAreaArray<MeasurementArea *>(list); // returns a
//! QList<MeasurementArea*>
//! // containing all MeasurementArea's inside list
template <class AreaPtr, template <class> class Container = QList,
class QObjectList>
inline Container<AreaPtr> getGeoAreaList(QObjectList &list) {
static_assert(std::is_pointer<AreaPtr>::value,
"AreaPtr must be a pointer type.");
Container<AreaPtr> out;
for (int i = 0; i < list.count(); ++i) {
auto obj = list[i];
auto area = qobject_cast<AreaPtr>(obj);
if (area != nullptr) {
out.append(area);
}
}
return out;
}
bool copyAreaList(const QmlObjectListModel &from, QmlObjectListModel &to,
QObject *parent);
......@@ -2,6 +2,7 @@
#include "QtConcurrentRun"
#include "nemo_interface/SnakeTile.h"
#include "snake.h"
#include <ctime>
#include <boost/units/systems/si.hpp>
......@@ -170,7 +171,7 @@ MeasurementArea::MeasurementArea(QObject *parent)
this /* QObject parent */)),
_showTiles(SettingsFact(settingsGroup, _metaDataMap[showTilesKey],
this /* QObject parent */)),
_state(STATE::IDLE) {
_holdProgress(false), _state(STATE::IDLE) {
init();
}
......@@ -188,7 +189,7 @@ MeasurementArea::MeasurementArea(const MeasurementArea &other, QObject *parent)
this /* QObject parent */)),
_showTiles(SettingsFact(settingsGroup, _metaDataMap[showTilesKey],
this /* QObject parent */)),
_state(STATE::IDLE) {
_holdProgress(false), _state(STATE::IDLE) {
init();
disableUpdate();
......@@ -272,6 +273,19 @@ int MeasurementArea::maxTiles() const { return SNAKE_MAX_TILES; }
bool MeasurementArea::ready() const { return this->_state == STATE::IDLE; }
bool MeasurementArea::measurementCompleted() const {
if (ready()) {
for (const auto &p : _progress) {
if (p != 100) {
return false;
}
}
return true;
} else {
return false;
}
}
bool MeasurementArea::saveToJson(QJsonObject &json) {
if (ready()) {
if (this->GeoArea::saveToJson(json)) {
......@@ -406,15 +420,41 @@ bool MeasurementArea::isCorrect() {
bool MeasurementArea::setProgress(const QVector<int> &p) {
if (ready()) {
if (p.size() == this->tiles()->count() && this->_progress != p) {
if (!_holdProgress && p.size() == this->tiles()->count() &&
this->_progress != p) {
this->_progress = p;
emit progressChanged();
emit progressAccepted();
return true;
}
}
emit progressNotAccepted();
return false;
}
void MeasurementArea::randomProgress() {
if (ready()) {
std::srand(std::time(nullptr));
for (auto &p : _progress) {
p += std::rand() % 100;
if (p > 100) {
p = 100;
}
}
emit progressChanged();
}
}
void MeasurementArea::resetProgress() {
if (ready()) {
for (auto &p : _progress) {
p = 0;
}
emit progressChanged();
}
}
//!
//! \brief MeasurementArea::doUpdate
//! \pre MeasurementArea::deferUpdate must be called first, don't call
......@@ -576,3 +616,12 @@ void MeasurementArea::setState(MeasurementArea::STATE s) {
}
}
}
bool MeasurementArea::holdProgress() const { return _holdProgress; }
void MeasurementArea::setHoldProgress(bool holdProgress) {
if (_holdProgress != holdProgress) {
_holdProgress = holdProgress;
emit holdProgressChanged();
}
}
......@@ -46,6 +46,8 @@ public:
Q_PROPERTY(QmlObjectListModel *tiles READ tiles NOTIFY tilesChanged)
Q_PROPERTY(int maxTiles READ maxTiles NOTIFY maxTilesChanged)
Q_PROPERTY(QVector<int> progress READ progressQml NOTIFY progressChanged)
Q_PROPERTY(bool holdProgress READ holdProgress WRITE setHoldProgress NOTIFY
holdProgressChanged)
// Overrides from GeoArea
QString mapVisualQML(void) const override;
......@@ -69,10 +71,24 @@ public:
int maxTiles() const;
bool ready() const;
bool measurementCompleted() const;
// Static Variables
static const char *settingsGroup;
static const char *nameString;
//!
//! \brief holdProgress
//! \return Returns a copy of the holdProgress variable.
//!
bool holdProgress() const;
//!
//! \brief setHoldProgress Sets the holdProgress variable to \p holdProgress.
//! \note If holdProgress() == true, than setProgress() will do nothing, but
//! return false and emit the progressNotAccepted() signal.
//!
void setHoldProgress(bool holdProgress);
signals:
void tilesChanged();
void maxTilesChanged();
......@@ -80,9 +96,12 @@ signals:
void progressAccepted();
void progressNotAccepted();
void readyChanged();
void holdProgressChanged();
public slots:
bool setProgress(const QVector<int> &p);
Q_INVOKABLE void randomProgress();
Q_INVOKABLE void resetProgress();
private slots:
void doUpdate();
......@@ -105,6 +124,7 @@ private:
SettingsFact _showTiles;
QVector<int> _progress;
bool _holdProgress;
// Tile stuff.
// Tile stuff.
mutable QTimer _timer;
......
import QtQuick 2.0
import Qt.labs.settings 1.0
import QtQuick.Layouts 1.11
import QtQuick.Controls 1.4
import QGroundControl.Controls 1.0
......@@ -40,17 +41,18 @@ GridLayout {
}
}
ExclusiveGroup {
id: areaGroup
}
QGCLabel {
id: tipLabel
text: _root.errorString
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
text: qsTr("Use the Area Editor to modify areas.")
Layout.fillWidth: true
horizontalAlignment: Text.AlignLeft
color: "orange"
Layout.columnSpan: parent.columns
Layout.fillWidth: true
visible: !_root.areasCorrect
}
ExclusiveGroup {
id: areaGroup
}
Repeater {
......@@ -135,7 +137,7 @@ GridLayout {
id: commandsHeader
Layout.fillWidth: true
Layout.columnSpan: parent.columns
text: qsTr("Commands and Errors")
text: qsTr("Commands")
}
GridLayout {
......@@ -146,16 +148,6 @@ GridLayout {
Layout.fillWidth: true
visible: commandsHeader.checked
QGCLabel {
text: qsTr("Message: ") + _root.errorString
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
color: "orange"
Layout.columnSpan: parent.columns
Layout.fillWidth: true
visible: !_root.areasCorrect
}
QGCButton {
text: "Intersection"
enabled: _root.checked
......@@ -168,10 +160,44 @@ GridLayout {
QGCButton {
text: "Reset"
onClicked: {
_root.reset()
}
Layout.fillWidth: true
}
QGCButton {
text: "Abort"
onClicked: {
_root.abort()
}
Layout.fillWidth: true
}
}
SectionHeader {
id: hintHeader
Layout.fillWidth: true
Layout.columnSpan: parent.columns
text: qsTr("Hints")
}
GridLayout {
columnSpacing: _margin
rowSpacing: _margin
columns: 2
Layout.columnSpan: 2
Layout.fillWidth: true
visible: hintHeader.checked
QGCLabel {
id: hintLabel
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignLeft
text: qsTr("Use the Intersection button to clip the Measurement Area(s).
Use the Reset button to restore the areas to the state before entering this tab.
Use the Abort button to reset the areas and leave the tab.")
Layout.fillWidth: true
Layout.columnSpan: parent.columns
}
}
......@@ -193,4 +219,8 @@ GridLayout {
}
}
}
Settings {
property alias showHint: hintHeader.checked
}
}
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
......@@ -6,25 +8,24 @@
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
import QtQuick 2.3
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtLocation 5.3
import QtPositioning 5.3
import QtLocation 5.3
import QtPositioning 5.3
import QGroundControl 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Palette 1.0
import QGroundControl.Controls 1.0
import QGroundControl.FlightMap 1.0
import QGroundControl 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Palette 1.0
import QGroundControl.Controls 1.0
import QGroundControl.FlightMap 1.0
Item {
id: _root
property var map: undefined ///< Map control to place item in
property var geoArea: undefined ///< GeoArea derived class
property var map: undefined ///< Map control to place item in
property var geoArea: undefined ///< GeoArea derived class
opacity: 0.3
opacity: 0.2
signal clicked(int sequenceNumber)
......@@ -35,31 +36,30 @@ Item {
// Area polygon
QGCMapPolygonVisuals {
id: mapPolygonVisuals
mapControl: _root.map
mapPolygon: _root.geoArea
interactive: geoArea.interactive
borderWidth: 3
borderColor: "green"
interiorColor: "green"
altColor: QGroundControl.globalPalette.surveyPolygonTerrainCollision
z: QGroundControl.zOrderMapItems-1
interiorOpacity: _root.opacity
id: mapPolygonVisuals
mapControl: _root.map
mapPolygon: _root.geoArea
interactive: geoArea.interactive
borderWidth: 3
interiorColor: "green"
altColor: QGroundControl.globalPalette.surveyPolygonTerrainCollision
z: QGroundControl.zOrderMapItems - 1
interiorOpacity: _root.opacity
}
// Add Snake tiles to the map
Component {
id: tileComponent
Item{
Item {
id: root
property MapPolygon polygon
MapPolygon{
id:mapPolygon
path: []
MapPolygon {
id: mapPolygon
path: []
}
Component.onCompleted: {
......@@ -90,27 +90,27 @@ Item {
property bool enable: geoArea.showTiles.value
model: enable ? geoArea.tiles : []
Item{
Item {
property var _tileComponent
property int _progress: _root.geoArea.progress[index] ?
_root.geoArea.progress[index] : 0
property int _progress: _root.geoArea.progress[index] ? _root.geoArea.progress[index] : 0
Component.onCompleted: {
_tileComponent = tileComponent.createObject(map)
_tileComponent.polygon.path =
Qt.binding(function(){return object.path})
_tileComponent.polygon.path = Qt.binding(function () {
return object.path
})
_tileComponent.polygon.opacity = 0.6
_tileComponent.polygon.border.color = "black"
_tileComponent.polygon.border.width = 1
_tileComponent.polygon.color =
Qt.binding(function(){return getColor(_progress)})
_tileComponent.polygon.color = Qt.binding(function () {
return getColor(_progress)
})
}
Component.onDestruction: {
_tileComponent.destroy()
}
}
}
}
......@@ -4,3 +4,4 @@ LinearGenerator 1.0 LinearGenerator.qml
CircularGenerator 1.0 CircularGenerator.qml
SafeAreaEditor 1.0 SafeAreaEditor.qml
MeasurementAreaEditor 1.0 MeasurementAreaEditor.qml
NemoEditor 1.0 NemoEditor.qml
......@@ -60,7 +60,7 @@ Rectangle {
Component.onCompleted: currentIndex = editing ? areaEditorIndex : parameterEditorIndex
QGCTabButton {
icon.source: "/qmlimages/PatternCamera.png"
icon.source: "qrc:/res/waypoint.svg"
icon.height: ScreenTools.defaultFontPixelHeight
}
QGCTabButton {
......@@ -68,7 +68,7 @@ Rectangle {
icon.height: ScreenTools.defaultFontPixelHeight
}
QGCTabButton {
icon.source: "/qmlimages/PatternPresets.png"
icon.source: "qrc:/res/fish.svg"
icon.height: ScreenTools.defaultFontPixelHeight
}
......@@ -124,6 +124,14 @@ Rectangle {
missionItem: _root._missionItem
availableWidth: mainColumn.width
}
MCI.NemoEditor {
id: nemoEditor
checked: visible
missionItem: _root._missionItem
availableWidth: mainColumn.width
}
}
} // main Column
} // Rectangle
......@@ -56,9 +56,9 @@ Item {
Component.onCompleted: {
console.assert(map != undefined, "please set the map property")
if (!_missionItem.areaData.initialized()){
if (!_missionItem.initialized()){
var bbox = boundingBox()
_missionItem.areaData.initialize(bbox[0], bbox[1])
_missionItem.initialize(bbox[0], bbox[1])
}
// _addEntryCoordinate()
// _addExitCoordinate()
......
import QtQuick 2.0
import Qt.labs.settings 1.0
import QtQuick.Layouts 1.11
import QtQuick.Controls 1.4
import QGroundControl.Controls 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.ScreenTools 1.0
import MeasurementComplexItem 1.0 as MCI
GridLayout {
id: _root
property bool checked: true
property var missionItem: undefined
property int availableWidth: 300
property bool error: errorString.lenght >= 0
readonly property bool running: _nemoInterface.running
property string errorString: ""
signal abort
property var _areaData: missionItem.areaData
property real _margin: ScreenTools.defaultFontPixelWidth / 2
property var _nemoInterface: MCI.NemoInterface
property bool _holding
columnSpacing: _margin
rowSpacing: _margin
columns: 2
Component.onCompleted: {
console.assert(missionItem !== undefined,
"please set the missionItem property")
_holding = false
_stopHolding()
}
QGCLabel {
text: _root.errorString
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignLeft
color: "orange"
Layout.columnSpan: parent.columns
Layout.fillWidth: true
visible: !_root.areasCorrect
}
QGCButton {
text: running ? qsTr("Stop") : qsTr("Start")
Layout.columnSpan: parent.columns
Layout.fillWidth: true
onPressed: {
if (running) {
_nemoInterface.stop()
} else {
_nemoInterface.start()
}
}
}
QGCLabel {
text: qsTr("Status: ") + _nemoInterface.statusString
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignVCenter
Layout.columnSpan: parent.columns
Layout.fillWidth: true
}
SectionHeader {
id: progressHeader
Layout.fillWidth: true
Layout.columnSpan: parent.columns
text: qsTr("Progress")
}
GridLayout {
columnSpacing: _margin
rowSpacing: _margin
columns: 2
Layout.columnSpan: parent.columns
Layout.fillWidth: true
visible: progressHeader.checked
QGCButton {
text: !_holding ? qsTr("Hold") : qsTr("Stop Holding")
Layout.fillWidth: true
Layout.columnSpan: parent.columns
onPressed: {
if (_holding) {
_stopHolding()
_holding = false
} else {
_holdProgress()
_holding = true
}
}
}
QGCButton {
text: qsTr("Random")
Layout.columnSpan: parent.columns
Layout.fillWidth: true
onPressed: {
_randomProgress()
}
}
QGCButton {
text: qsTr("Reset")
Layout.columnSpan: parent.columns
Layout.fillWidth: true
onPressed: {
_resetProgress()
}
}
}
// bussy indicator
ColumnLayout {
Layout.fillWidth: true
spacing: _margin
Layout.maximumWidth: parent.width
BusyIndicator {
id: indicator
property bool calculating: missionItem.calculating
running: calculating
visible: calculating || timer.running
onCalculatingChanged: {
if (!calculating) {
// defer hiding
timer.restart()
}
}
Timer {
id: timer
interval: 1000
repeat: false
running: false
}
}
} // indicator column
SectionHeader {
id: hintHeader
Layout.fillWidth: true
Layout.columnSpan: parent.columns
text: qsTr("Hints")
}
GridLayout {
columnSpacing: _margin
rowSpacing: _margin
columns: 2
Layout.columnSpan: 2
Layout.fillWidth: true
visible: hintHeader.checked
QGCLabel {
id: hintLabel
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignLeft
text: qsTr("Use this tab to connect to a device implementing the Nemo Interface.
Use the Random button to simulate measurement progress.")
Layout.fillWidth: true
Layout.columnSpan: parent.columns
}
}
Settings {
property alias showHint: hintHeader.checked
}
function _holdProgress() {
var areaArray = _areaData.measurementAreaList
for (var i = 0; i < areaArray.count; ++i) {
var area = areaArray.get(i)
if (area) {
area.holdProgress = true
} else {
console.log("empty area!")
}
}
}
function _stopHolding() {
var areaArray = _areaData.measurementAreaList
for (var i = 0; i < areaArray.count; ++i) {
var area = areaArray.get(i)
if (area) {
area.holdProgress = false
} else {
console.log("empty area!")
}
}
}
function _randomProgress() {
var areaArray = _areaData.measurementAreaList
for (var i = 0; i < areaArray.count; ++i) {
var area = areaArray.get(i)
if (area) {
area.randomProgress()
} else {
console.log("empty area!")
}
}
}
function _resetProgress() {
var areaArray = _areaData.measurementAreaList
for (var i = 0; i < areaArray.count; ++i) {
var area = areaArray.get(i)
if (area) {
area.resetProgress()
} else {
console.log("empty area!")
}
}
}
}
......@@ -39,11 +39,10 @@ Item {
mapPolygon: geoArea
interactive: geoArea.interactive
borderWidth: 2
borderColor: "blue"
interiorColor: "blue"
altColor: QGroundControl.globalPalette.surveyPolygonTerrainCollision
z: QGroundControl.zOrderMapItems-1
interiorOpacity: 0.3
interiorOpacity: 0.2
}
Item {
......
......@@ -7,157 +7,155 @@
*
****************************************************************************/
#ifndef MissionItem_H
#define MissionItem_H
#include <QGeoCoordinate>
#include <QJsonObject>
#include <QObject>
#include <QString>
#include <QtQml>
#include <QTextStream>
#include <QJsonObject>
#include <QGeoCoordinate>
#include <QtQml>
#include "QGCMAVLink.h"
#include "QGC.h"
#include "QmlObjectListModel.h"
#include "Fact.h"
#include "QGC.h"
#include "QGCLoggingCategory.h"
#include "QGCMAVLink.h"
#include "QmlObjectListModel.h"
class SurveyComplexItem;
class RouteComplexItem;
class SimpleMissionItem;
class MissionController;
#ifdef UNITTEST_BUILD
class MissionItemTest;
class MissionItemTest;
#endif
// Represents a Mavlink mission command.
class MissionItem : public QObject
{
Q_OBJECT
class MissionItem : public QObject {
Q_OBJECT
public:
MissionItem(QObject* parent = nullptr);
MissionItem(int sequenceNumber,
MAV_CMD command,
MAV_FRAME frame,
double param1,
double param2,
double param3,
double param4,
double param5,
double param6,
double param7,
bool autoContinue,
bool isCurrentItem,
QObject* parent = nullptr);
MissionItem(const MissionItem& other, QObject* parent = nullptr);
~MissionItem();
const MissionItem& operator=(const MissionItem& other);
MAV_CMD command (void) const { return (MAV_CMD)_commandFact.rawValue().toInt(); }
bool isCurrentItem (void) const { return _isCurrentItem; }
int sequenceNumber (void) const { return _sequenceNumber; }
MAV_FRAME frame (void) const { return (MAV_FRAME)_frameFact.rawValue().toInt(); }
bool autoContinue (void) const { return _autoContinueFact.rawValue().toBool(); }
double param1 (void) const { return _param1Fact.rawValue().toDouble(); }
double param2 (void) const { return _param2Fact.rawValue().toDouble(); }
double param3 (void) const { return _param3Fact.rawValue().toDouble(); }
double param4 (void) const { return _param4Fact.rawValue().toDouble(); }
double param5 (void) const { return _param5Fact.rawValue().toDouble(); }
double param6 (void) const { return _param6Fact.rawValue().toDouble(); }
double param7 (void) const { return _param7Fact.rawValue().toDouble(); }
QGeoCoordinate coordinate (void) const;
int doJumpId (void) const { return _doJumpId; }
/// @return Flight speed change value if this item supports it. If not it returns NaN.
double specifiedFlightSpeed(void) const;
/// @return Flight gimbal yaw change value if this item supports it. If not it returns NaN.
double specifiedGimbalYaw(void) const;
/// @return Flight gimbal pitch change value if this item supports it. If not it returns NaN.
double specifiedGimbalPitch(void) const;
void setCommand (MAV_CMD command);
void setSequenceNumber (int sequenceNumber);
void setIsCurrentItem (bool isCurrentItem);
void setFrame (MAV_FRAME frame);
void setAutoContinue (bool autoContinue);
void setParam1 (double param1);
void setParam2 (double param2);
void setParam3 (double param3);
void setParam4 (double param4);
void setParam5 (double param5);
void setParam6 (double param6);
void setParam7 (double param7);
void save(QJsonObject& json) const;
bool load(QTextStream &loadStream);
bool load(const QJsonObject& json, int sequenceNumber, QString& errorString);
bool relativeAltitude(void) const { return frame() == MAV_FRAME_GLOBAL_RELATIVE_ALT; }
MissionItem(QObject *parent = nullptr);
MissionItem(int sequenceNumber, MAV_CMD command, MAV_FRAME frame,
double param1, double param2, double param3, double param4,
double param5, double param6, double param7, bool autoContinue,
bool isCurrentItem, QObject *parent = nullptr);
MissionItem(const MissionItem &other, QObject *parent = nullptr);
~MissionItem();
const MissionItem &operator=(const MissionItem &other);
MAV_CMD command(void) const {
return (MAV_CMD)_commandFact.rawValue().toInt();
}
bool isCurrentItem(void) const { return _isCurrentItem; }
int sequenceNumber(void) const { return _sequenceNumber; }
MAV_FRAME frame(void) const {
return (MAV_FRAME)_frameFact.rawValue().toInt();
}
bool autoContinue(void) const {
return _autoContinueFact.rawValue().toBool();
}
double param1(void) const { return _param1Fact.rawValue().toDouble(); }
double param2(void) const { return _param2Fact.rawValue().toDouble(); }
double param3(void) const { return _param3Fact.rawValue().toDouble(); }
double param4(void) const { return _param4Fact.rawValue().toDouble(); }
double param5(void) const { return _param5Fact.rawValue().toDouble(); }
double param6(void) const { return _param6Fact.rawValue().toDouble(); }
double param7(void) const { return _param7Fact.rawValue().toDouble(); }
QGeoCoordinate coordinate(void) const;
int doJumpId(void) const { return _doJumpId; }
/// @return Flight speed change value if this item supports it. If not it
/// returns NaN.
double specifiedFlightSpeed(void) const;
/// @return Flight gimbal yaw change value if this item supports it. If not it
/// returns NaN.
double specifiedGimbalYaw(void) const;
/// @return Flight gimbal pitch change value if this item supports it. If not
/// it returns NaN.
double specifiedGimbalPitch(void) const;
void setCommand(MAV_CMD command);
void setSequenceNumber(int sequenceNumber);
void setIsCurrentItem(bool isCurrentItem);
void setFrame(MAV_FRAME frame);
void setAutoContinue(bool autoContinue);
void setParam1(double param1);
void setParam2(double param2);
void setParam3(double param3);
void setParam4(double param4);
void setParam5(double param5);
void setParam6(double param6);
void setParam7(double param7);
void save(QJsonObject &json) const;
bool load(QTextStream &loadStream);
bool load(const QJsonObject &json, int sequenceNumber, QString &errorString);
bool relativeAltitude(void) const {
return frame() == MAV_FRAME_GLOBAL_RELATIVE_ALT;
}
signals:
void isCurrentItemChanged (bool isCurrentItem);
void sequenceNumberChanged (int sequenceNumber);
void specifiedFlightSpeedChanged(double flightSpeed);
void specifiedGimbalYawChanged (double gimbalYaw);
void specifiedGimbalPitchChanged(double gimbalPitch);
void isCurrentItemChanged(bool isCurrentItem);
void sequenceNumberChanged(int sequenceNumber);
void specifiedFlightSpeedChanged(double flightSpeed);
void specifiedGimbalYawChanged(double gimbalYaw);
void specifiedGimbalPitchChanged(double gimbalPitch);
private slots:
void _param1Changed(QVariant value);
void _param2Changed(QVariant value);
void _param3Changed(QVariant value);
void _param1Changed(QVariant value);
void _param2Changed(QVariant value);
void _param3Changed(QVariant value);
private:
bool _convertJsonV1ToV2(const QJsonObject& json, QJsonObject& v2Json, QString& errorString);
bool _convertJsonV2ToV3(QJsonObject& json, QString& errorString);
Fact _autoContinueFact;
Fact _commandFact;
Fact _frameFact;
Fact _param1Fact;
Fact _param2Fact;
Fact _param3Fact;
Fact _param4Fact;
Fact _param5Fact;
Fact _param6Fact;
Fact _param7Fact;
int _sequenceNumber;
int _doJumpId;
bool _isCurrentItem;
// Keys for Json save
static const char* _jsonFrameKey;
static const char* _jsonCommandKey;
static const char* _jsonAutoContinueKey;
static const char* _jsonParamsKey;
static const char* _jsonDoJumpIdKey;
// Deprecated V2 format keys
static const char* _jsonCoordinateKey;
// Deprecated V1 format keys
static const char* _jsonParam1Key;
static const char* _jsonParam2Key;
static const char* _jsonParam3Key;
static const char* _jsonParam4Key;
friend class SurveyComplexItem;
friend class RouteComplexItem;
friend class SimpleMissionItem;
friend class MissionController;
bool _convertJsonV1ToV2(const QJsonObject &json, QJsonObject &v2Json,
QString &errorString);
bool _convertJsonV2ToV3(QJsonObject &json, QString &errorString);
Fact _autoContinueFact;
Fact _commandFact;
Fact _frameFact;
Fact _param1Fact;
Fact _param2Fact;
Fact _param3Fact;
Fact _param4Fact;
Fact _param5Fact;
Fact _param6Fact;
Fact _param7Fact;
int _sequenceNumber;
int _doJumpId;
bool _isCurrentItem;
// Keys for Json save
static const char *_jsonFrameKey;
static const char *_jsonCommandKey;
static const char *_jsonAutoContinueKey;
static const char *_jsonParamsKey;
static const char *_jsonDoJumpIdKey;
// Deprecated V2 format keys
static const char *_jsonCoordinateKey;
// Deprecated V1 format keys
static const char *_jsonParam1Key;
static const char *_jsonParam2Key;
static const char *_jsonParam3Key;
static const char *_jsonParam4Key;
friend class SurveyComplexItem;
friend class RouteComplexItem;
friend class SimpleMissionItem;
friend class MissionController;
#ifdef UNITTEST_BUILD
friend class MissionItemTest;
friend class MissionItemTest;
#endif
};
......
......@@ -186,6 +186,11 @@ static QObject *shapeFileHelperSingletonFactory(QQmlEngine *, QJSEngine *) {
return new ShapeFileHelper;
}
QObject *getNemoInterface(QQmlEngine *engine, QJSEngine *) {
engine->setObjectOwnership(pNemoInterface, QQmlEngine::CppOwnership);
return pNemoInterface;
}
QGCApplication::QGCApplication(int &argc, char *argv[], bool unitTesting)
: QApplication(argc, argv), _runningUnitTests(unitTesting) {
_app = this;
......@@ -665,13 +670,13 @@ void QGCApplication::_initCommon() {
#endif
qmlRegisterUncreatableType<routing::LinearGenerator>(
"RouteComplexItem", 1, 0, "LinearGenerator", kRefOnly);
qmlRegisterType<AreaData>("RouteComplexItem", 1, 0, "AreaData");
qmlRegisterUncreatableType<NemoInterface>("RouteComplexItem", 1, 0,
"NemoInterface", kRefOnly);
"MeasurementComplexItem", 1, 0, "LinearGenerator", kRefOnly);
qmlRegisterType<AreaData>("MeasurementComplexItem", 1, 0, "AreaData");
qmlRegisterSingletonType<NemoInterface>("MeasurementComplexItem", 1, 0,
"NemoInterface", getNemoInterface);
qmlRegisterInterface<routing::GeneratorBase>("GeneratorBase");
qmlRegisterUncreatableType<routing::CircularGenerator>(
"RouteComplexItem", 1, 0, "CircularGenerator", kRefOnly);
"MeasurementComplexItem", 1, 0, "CircularGenerator", kRefOnly);
qmlRegisterType<GeoTagController>(kQGCControllers, 1, 0, "GeoTagController");
qmlRegisterType<MavlinkConsoleController>(kQGCControllers, 1, 0,
......
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