Commit 1b05f323 authored by Valentin Platzgummer's avatar Valentin Platzgummer

MeasurementItemEditor improved

parent 31d4efc3
......@@ -34,14 +34,13 @@ DebugBuild {
DEFINES += DEBUG
#DEFINES += SNAKE_SHOW_TIME
#DEFINES += SNAKE_DEBUG
DEFINES += SNAKE_SHOW_TIME
DEFINES += DEBUG_CIRCULAR_SURVEY
#DEFINES += SNAKE_SHOW_TIME
DEFINES += ROS_BRIDGE_DEBUG
}
else {
DESTDIR = $${OUT_PWD}/release
#DEFINES += ROS_BRIDGE_DEBUG
DEFINES += SNAKE_SHOW_TIME
#DEFINES += SNAKE_SHOW_TIME
#DEFINES += SNAKE_DEBUG
DEFINES += NDEBUG
}
......
......@@ -18,8 +18,7 @@ AreaData::AreaData(QObject *parent) : QObject(parent) {}
AreaData::~AreaData() {}
AreaData::AreaData(const AreaData &other, QObject *parent)
: QObject(parent), _showErrorMessages(true) {
AreaData::AreaData(const AreaData &other, QObject *parent) : QObject(parent) {
*this = other;
}
......@@ -93,21 +92,21 @@ const QmlObjectListModel *AreaData::areaList() const { return &_areaList; }
QGeoCoordinate AreaData::origin() const { return _origin; }
bool AreaData::isCorrect() {
bool AreaData::isCorrect(bool showError) {
if (!initialized()) {
qCWarning(AreaDataLog) << "isCorrect(): not initialized";
return false;
}
// Check if areas are correct
if (!_areasCorrect()) {
if (!_areasCorrect(showError)) {
return false;
}
// Check if areas where added.
MeasurementArea *measurementArea = nullptr;
SafeArea *safeArea = nullptr;
if (!_getAreas(&measurementArea, &safeArea)) {
if (!_getAreas(&measurementArea, &safeArea, showError)) {
return false;
}
......@@ -128,7 +127,8 @@ bool AreaData::isCorrect() {
// 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"));
"the Measurement Area.\n"),
showError);
return false;
}
......@@ -209,11 +209,11 @@ bool AreaData::initialized() {
measurementArea->count() >= 3 && safeArea->count() >= 3;
}
void AreaData::intersection() {
if (initialized() && _areasCorrect()) {
void AreaData::intersection(bool showError) {
if (initialized() && _areasCorrect(showError)) {
MeasurementArea *measurementArea = nullptr;
SafeArea *safeArea = nullptr;
if (_getAreas(&measurementArea, &safeArea)) {
if (_getAreas(&measurementArea, &safeArea, showError)) {
// convert to ENU
const auto origin = this->origin();
......@@ -230,7 +230,8 @@ void AreaData::intersection() {
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.");
"Safe Area must touch each other.",
showError);
return;
}
......@@ -238,7 +239,8 @@ void AreaData::intersection() {
_processError(
"Hint: Only simple polygons can be displayed. If Intersection"
"produces polygons with holes or multi polygons, only "
"partial information can be displayed.");
"partial information can be displayed.",
showError);
}
// Shrink the result if safeAreaENU doesn't cover it.
......@@ -247,9 +249,10 @@ void AreaData::intersection() {
while (!bg::covered_by(large, safeAreaENU)) {
snake::offsetPolygon(large, small, -0.1);
large = std::move(small);
qDebug() << "intersection(): shrink";
}
// Check if result is different from input.
if (!bg::equals(large, measurementAreaENU)) {
// Convert.
measurementArea->clear();
for (auto it = large.outer().begin(); it != large.outer().end() - 1;
......@@ -260,6 +263,7 @@ void AreaData::intersection() {
}
}
}
}
}
MeasurementArea *AreaData::measurementArea() {
......@@ -302,7 +306,7 @@ bool AreaData::load(const QJsonObject &obj, QString &errorString) {
// load MeasurementArea
if (jsonArea[GeoArea::areaTypeKey].toString() ==
MeasurementArea::name) {
MeasurementArea::nameString) {
auto area = getGeoArea<MeasurementArea *>(_areaList);
......@@ -325,7 +329,8 @@ bool AreaData::load(const QJsonObject &obj, QString &errorString) {
}
}
// load SafeArea
else if (jsonArea[GeoArea::areaTypeKey].toString() == SafeArea::name) {
else if (jsonArea[GeoArea::areaTypeKey].toString() ==
SafeArea::nameString) {
auto area = getGeoArea<SafeArea *>(_areaList);
if (area == nullptr) {
......@@ -394,7 +399,6 @@ bool AreaData::save(QJsonObject &obj) {
} else {
qDebug(AreaDataLog) << "save(): not able to save area: "
<< area->objectName();
_processError(tr("Not able to save area: ") + area->objectName());
return false;
}
}
......@@ -411,21 +415,21 @@ void AreaData::_setOrigin(const QGeoCoordinate &origin) {
}
}
void AreaData::_processError(const QString &str) {
void AreaData::_processError(const QString &str, bool showError) {
this->_errorString = str;
emit error();
if (_showErrorMessages) {
if (showError) {
qgcApp()->informationMessageBoxOnMainThread(tr("Area Editor"),
this->errorString());
}
}
bool AreaData::_areasCorrect() {
bool AreaData::_areasCorrect(bool showError) {
// Check if areas are correct.
for (int i = 0; i < _areaList.count(); ++i) {
auto *area = _areaList.value<GeoArea *>(0);
auto *area = _areaList.value<GeoArea *>(i);
if (!area->isCorrect()) {
_processError(area->errorString());
_processError(area->errorString(), showError);
return false;
}
}
......@@ -433,30 +437,25 @@ bool AreaData::_areasCorrect() {
return true;
}
bool AreaData::_getAreas(MeasurementArea **measurementArea,
SafeArea **safeArea) {
bool AreaData::_getAreas(MeasurementArea **measurementArea, SafeArea **safeArea,
bool showError) {
*measurementArea = getGeoArea<MeasurementArea *>(_areaList);
if (*measurementArea == nullptr) {
_processError(
tr("Measurement Area missing. Please define a measurement area."));
tr("Measurement Area 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 missing. Please define a safe area."),
showError);
return false;
}
return true;
}
void AreaData::setShowErrorMessages(bool showErrorMessages) {
if (showErrorMessages != _showErrorMessages) {
_showErrorMessages = showErrorMessages;
emit showErrorMessagesChanged();
}
}
void AreaData::_updateOrigin() {
auto *measurementArea = getGeoArea<MeasurementArea *>(_areaList);
if (measurementArea != nullptr) {
......@@ -464,6 +463,4 @@ void AreaData::_updateOrigin() {
}
}
bool AreaData::showErrorMessages() const { return _showErrorMessages; }
QString AreaData::errorString() const { return _errorString; }
......@@ -20,8 +20,7 @@ public:
AreaData &operator=(const AreaData &other);
Q_PROPERTY(QmlObjectListModel *areaList READ areaList NOTIFY areaListChanged)
Q_PROPERTY(bool showErrorMessages READ showErrorMessages WRITE
setShowErrorMessages NOTIFY showErrorMessagesChanged)
Q_PROPERTY(QString errorString READ errorString NOTIFY error)
// Member Methodes
//!
......@@ -51,7 +50,7 @@ public:
//! \note Origin might change if the list of areas changes.
QGeoCoordinate origin() const;
Q_INVOKABLE bool isCorrect();
Q_INVOKABLE bool isCorrect(bool showError = true);
//!
//! \brief initialize Initializes the areas in a valid way, such that they
//! area inside the bounding box. \param bottomLeft bottom left corner of the
......@@ -69,7 +68,7 @@ public:
//! either.
//!
Q_INVOKABLE bool initialized();
Q_INVOKABLE void intersection();
Q_INVOKABLE void intersection(bool showError = true);
Q_INVOKABLE MeasurementArea *measurementArea();
Q_INVOKABLE SafeArea *safeArea();
......@@ -82,25 +81,21 @@ public:
QString errorString() const; // Contains a message about the last error.
bool showErrorMessages() const;
void setShowErrorMessages(bool showErrorMessages);
signals:
void areaListChanged();
void originChanged();
void error(); // Emitted if errorString() contains a new message.
void showErrorMessagesChanged();
private slots:
void _updateOrigin();
private:
void _setOrigin(const QGeoCoordinate &origin);
void _processError(const QString &str);
bool _areasCorrect();
bool _getAreas(MeasurementArea **measurementArea, SafeArea **safeArea);
void _processError(const QString &str, bool showError);
bool _areasCorrect(bool showError);
bool _getAreas(MeasurementArea **measurementArea, SafeArea **safeArea,
bool showError);
QGeoCoordinate _origin;
QmlObjectListModel _areaList;
QString _errorString;
bool _showErrorMessages;
};
......@@ -406,6 +406,7 @@ void CircularGenerator::setMeasurementArea(MeasurementArea *area) {
&CircularGenerator::resetReferenceIfInvalid);
connect(_measurementArea, &MeasurementArea::pathChanged, this,
&GeneratorBase::generatorChanged);
resetReferenceIfInvalid();
}
emit generatorChanged();
......@@ -438,16 +439,13 @@ bool circularTransects(const snake::FPoint &reference,
distances.reserve(polygon.outer().size());
std::vector<snake::Angle> angles;
angles.reserve(polygon.outer().size());
//#ifdef DEBUG_CIRCULAR_SURVEY
// qCDebug(CircularGeneratorLog) << "circularTransects():";
//#endif
for (const auto &p : polygon.outer()) {
snake::Length distance = bg::distance(reference, p) * si::meter;
distances.push_back(distance);
snake::Angle alpha = (std::atan2(p.get<1>(), p.get<0>())) * si::radian;
alpha = alpha < 0 * si::radian ? alpha + 2 * M_PI * si::radian : alpha;
angles.push_back(alpha);
//#ifdef DEBUG_CIRCULAR_SURVEY
// qCDebug(CircularGeneratorLog) << "distances, angles,
// coordinates:"; qCDebug(CircularGeneratorLog) <<
// to_string(distance).c_str(); qCDebug(CircularGeneratorLog)
......@@ -455,7 +453,6 @@ bool circularTransects(const snake::FPoint &reference,
// qCDebug(CircularGeneratorLog) << "x = " << p.get<0>() << "y
// = "
// << p.get<1>();
//#endif
}
auto rMin = deltaR; // minimal circle radius
......@@ -484,7 +481,6 @@ bool circularTransects(const snake::FPoint &reference,
vector<ClipperLib::Path> sectors(nTran, ClipperLib::Path());
const auto nSectors =
long(std::round(((alpha2 - alpha1) / deltaAlpha).value()));
//#ifdef DEBUG_CIRCULAR_SURVEY
// qCDebug(CircularGeneratorLog) << "circularTransects(): sector
// parameres:"; qCDebug(CircularGeneratorLog) << "alpha1: " <<
// to_string(snake::Degree(alpha1)).c_str();
......@@ -499,7 +495,6 @@ bool circularTransects(const snake::FPoint &reference,
// qCDebug(CircularGeneratorLog)
// << "rMax: " << to_string(rMax).c_str();
// qCDebug(CircularGeneratorLog) << "nTran: " << nTran;
//#endif
using ClipperCircle =
GenericCircle<ClipperLib::cInt, ClipperLib::IntPoint>;
for (auto &sector : sectors) {
......
......@@ -67,6 +67,7 @@ bool GeneratorFactory::registerGenerator(const QString &type,
GeneratorFactory::Creator creator) {
const auto pair = _creatorMap.insert(std::make_pair(type, creator));
auto success = pair.second;
Q_ASSERT(success);
return success;
}
......
......@@ -33,12 +33,12 @@ const char *MeasurementComplexItem::jsonComplexItemTypeValue =
const QString MeasurementComplexItem::name(tr("Measurement"));
namespace {
const char *variantKey = "Variant";
const char *variantIndexKey = "VariantIndex";
const char *altitudeKey = "Altitude";
const char *areaDataKey = "AreaData";
const char *variantNamesKey = "VariantNames";
const char *generatorsKey = "Generators";
const char *variantsKey = "Variants";
const char *generatorArrayKey = "GeneratorArray";
const char *variantArrayKey = "VariantArray";
const char *generatorIndexKey = "GeneratorIndex";
} // namespace
......@@ -51,17 +51,39 @@ MeasurementComplexItem::MeasurementComplexItem(
QStringLiteral(":/json/MeasurementComplexItem.SettingsGroup.json"),
this)),
_altitude(settingsGroup, _metaDataMap[altitudeKey]),
_variant(settingsGroup, _metaDataMap[variantKey]),
_variantIndex(settingsGroup, _metaDataMap[variantIndexKey]),
_pAreaData(new AreaData(this)), _pEditorData(new AreaData(this)),
_pCurrentData(_pAreaData), _pGenerator(nullptr),
_pWorker(new RoutingThread(this)) {
// Setup altitude.
_altitude.setRawValue(qgcApp()
->toolbox()
->settingsManager()
->appSettings()
->defaultMissionItemAltitude()
->rawValue());
connect(&_altitude, &SettingsFact::rawValueChanged, [this] {
emit this->minAMSLAltitudeChanged(this->_altitude.rawValue().toDouble());
});
connect(&_altitude, &SettingsFact::rawValueChanged, [this] {
emit this->maxAMSLAltitudeChanged(this->_altitude.rawValue().toDouble());
});
connect(&_altitude, &SettingsFact::rawValueChanged, [this] {
emit this->amslEntryAltChanged(this->_altitude.rawValue().toDouble());
});
connect(&_altitude, &SettingsFact::rawValueChanged, [this] {
emit this->amslExitAltChanged(this->_altitude.rawValue().toDouble());
});
connect(&_altitude, &SettingsFact::rawValueChanged, this,
&MeasurementComplexItem::_onAltitudeChanged);
Q_UNUSED(kmlOrShpFile)
_editorQml = "qrc:/qml/MeasurementItemEditor.qml";
// Connect facts.
connect(&this->_variant, &Fact::rawValueChanged, this,
&MeasurementComplexItem::_changeVariant);
connect(&this->_variantIndex, &Fact::rawValueChanged, this,
&MeasurementComplexItem::_changeVariantIndex);
// Connect worker.
connect(this->_pWorker, &RoutingThread::result, this,
......@@ -106,10 +128,6 @@ MeasurementComplexItem::MeasurementComplexItem(
resetGenerators();
startEditing();
qCritical() << "ToDo: _altitude connections missing.";
qCritical() << "ToDo: remove generatorNameList and use GeneratorBase::name() "
"instead.";
}
MeasurementComplexItem::~MeasurementComplexItem() {}
......@@ -173,10 +191,10 @@ bool MeasurementComplexItem::load(const QJsonObject &complexObject,
setSequenceNumber(sequenceNumber);
startEditing();
// load variant
if (complexObject.contains(variantKey) &&
complexObject[variantKey].isDouble()) {
_variant.setRawValue(complexObject[variantKey].toInt());
// load variant index
if (complexObject.contains(variantIndexKey) &&
complexObject[variantIndexKey].isDouble()) {
_variantIndex.setRawValue(complexObject[variantIndexKey].toInt());
}
// load altitude
......@@ -194,14 +212,11 @@ bool MeasurementComplexItem::load(const QJsonObject &complexObject,
complexObject[areaDataKey].isObject()) {
QString e;
if (_pCurrentData->load(complexObject[areaDataKey].toObject(), e)) {
_pCurrentData->setShowErrorMessages(false);
if (!_pCurrentData->isCorrect()) {
if (!_pCurrentData->isCorrect(false /*don't show gui message*/)) {
errorString.append(_pCurrentData->errorString());
_pCurrentData->setShowErrorMessages(true);
abortEditing();
return false;
}
_pCurrentData->setShowErrorMessages(true);
} else {
// this is critical, proceeding is not
......@@ -218,13 +233,13 @@ bool MeasurementComplexItem::load(const QJsonObject &complexObject,
}
// load Generators.
if (complexObject.contains(generatorsKey) &&
complexObject[generatorsKey].isArray()) {
if (complexObject.contains(generatorArrayKey) &&
complexObject[generatorArrayKey].isArray()) {
QVector<PtrGenerator> generatorList;
QObject parent;
for (const auto valueRef : complexObject[generatorsKey].toArray()) {
for (const auto valueRef : complexObject[generatorArrayKey].toArray()) {
const auto jsonGen = valueRef.toObject();
if (jsonGen.contains(routing::GeneratorBase::typeKey) &&
......@@ -276,7 +291,7 @@ bool MeasurementComplexItem::load(const QJsonObject &complexObject,
// insert generators
for (const auto gen : generatorList) {
gen->setParent(this);
addGenerator(gen->name(), gen);
addGenerator(gen);
}
}
} else {
......@@ -303,11 +318,11 @@ bool MeasurementComplexItem::load(const QJsonObject &complexObject,
// load Route Variants
bool variantsSuccess = true;
QVector<Variant> variantVector;
if (complexObject.contains(variantsKey) &&
complexObject[variantsKey].isArray()) {
if (complexObject.contains(variantArrayKey) &&
complexObject[variantArrayKey].isArray()) {
// load variants to variantVector for further processing.
for (const auto valueRef : complexObject[variantsKey].toArray()) {
for (const auto valueRef : complexObject[variantArrayKey].toArray()) {
if (valueRef.isArray()) {
const auto jsonVariant = valueRef.toArray();
Variant variant;
......@@ -333,6 +348,16 @@ bool MeasurementComplexItem::load(const QJsonObject &complexObject,
}
}
// Check if variantVector and variants are non empty
if (variantVector.size() == 0) {
variantsSuccess = false;
}
for (const auto &var : variantVector) {
if (var.size() == 0) {
variantsSuccess = false;
}
}
// Check if variants are covered by safe area.
if (variantsSuccess) {
auto safeArea = _pCurrentData->safeArea();
......@@ -362,11 +387,8 @@ bool MeasurementComplexItem::load(const QJsonObject &complexObject,
variantsSuccess = false;
}
if (!variantsSuccess) {
stopEditing(); // stop editing and trigger update
} else {
if (variantsSuccess) {
_variantVector.swap(variantVector);
qCritical() << "add variant names and set variant";
// load variant names
bool variantNamesLoaded = true;
......@@ -374,7 +396,7 @@ bool MeasurementComplexItem::load(const QJsonObject &complexObject,
complexObject[variantNamesKey].isArray()) {
QStringList variantNames;
for (const auto &name : complexObject[variantNamesKey]) {
for (const auto &name : complexObject[variantNamesKey].toArray()) {
if (name.isString()) {
variantNames.append(name.toString());
} else {
......@@ -413,11 +435,14 @@ bool MeasurementComplexItem::load(const QJsonObject &complexObject,
emit variantNamesChanged();
}
_changeVariant();
stopEditing(
false /*doUpdate*/); // does noting if editing was already stopped
_changeVariantIndex();
} else {
stopEditing(); // stop editing and trigger update
}
return true;
}
......@@ -460,7 +485,7 @@ void MeasurementComplexItem::save(QJsonArray &planItems) {
jsonComplexItemTypeValue;
// Variant and altitude.
saveObject[variantKey] = double(_variant.rawValue().toUInt());
saveObject[variantIndexKey] = double(_variantIndex.rawValue().toUInt());
saveObject[altitudeKey] = double(_altitude.rawValue().toUInt());
// Variant names.
......@@ -483,17 +508,16 @@ void MeasurementComplexItem::save(QJsonArray &planItems) {
QJsonArray generatorArray;
for (int i = 0; i < _generatorList.size(); ++i) {
auto const gen = _generatorList[i];
auto const &name = _generatorNameList[i];
QJsonObject obj;
if (!gen->save(obj)) {
qCDebug(MeasurementComplexItemLog)
<< "save(): not able to save generator: " << name;
<< "save(): not able to save generator with name: " << gen->name();
return;
} else {
generatorArray.append(obj);
}
}
saveObject[generatorsKey] = generatorArray;
saveObject[generatorArrayKey] = generatorArray;
// generator index
saveObject[generatorIndexKey] = generatorIndex();
......@@ -509,7 +533,7 @@ void MeasurementComplexItem::save(QJsonArray &planItems) {
}
variantsArray.append(variant);
}
saveObject[variantsKey] = variantsArray;
saveObject[variantArrayKey] = variantsArray;
planItems.append(saveObject);
} else {
......@@ -614,7 +638,6 @@ void MeasurementComplexItem::setMissionFlightStatus(
void MeasurementComplexItem::applyNewAltitude(double newAltitude) {
this->_altitude.setRawValue(newAltitude);
qWarning() << "applyNewAltitude(): impl. missing.";
}
double MeasurementComplexItem::additionalTimeDelay() const { return 0; }
......@@ -678,11 +701,8 @@ bool MeasurementComplexItem::_idle(MeasurementComplexItem::STATE state) {
}
void MeasurementComplexItem::_updateFlightpathSegments() {
if (_cTerrainCollisionSegments != 0) {
bool hasCollisionOld = _cTerrainCollisionSegments > 0;
_cTerrainCollisionSegments = 0;
emit terrainCollisionChanged(false);
qCritical() << "add alt color here...";
}
_flightPathSegments.beginReset();
_flightPathSegments.clearAndDeleteContents();
......@@ -708,12 +728,41 @@ void MeasurementComplexItem::_updateFlightpathSegments() {
_flightPathSegments.endReset();
if (_cTerrainCollisionSegments != 0) {
emit terrainCollisionChanged(true);
// Terrain collsision.
bool hasCollision = _cTerrainCollisionSegments > 0;
if (hasCollisionOld != hasCollision) {
emit terrainCollisionChanged(hasCollision);
}
if (_pAreaData->measurementArea() != nullptr) {
_pAreaData->measurementArea()->setShowAltColor(hasCollision);
}
_masterController->missionController()->recalcTerrainProfile();
}
void MeasurementComplexItem::_onAltitudeChanged() {
// Apply altitude to variants and route.
auto alt = _altitude.rawValue().toDouble();
for (auto &var : _variantVector) {
Variant *pVar;
if (var.size() > 0) {
pVar = &var;
} else {
pVar = &_route;
}
for (auto &qVariant : *pVar) {
auto vertex = qVariant.value<QGeoCoordinate>();
vertex.setAltitude(alt);
qVariant = QVariant::fromValue(vertex);
}
}
if (_route.size() > 0) {
emit routeChanged();
}
}
void MeasurementComplexItem::_setAreaData(
MeasurementComplexItem::PtrAreaData data) {
if (_pCurrentData != data) {
......@@ -796,9 +845,9 @@ void MeasurementComplexItem::_updateRoute() {
}
}
void MeasurementComplexItem::_changeVariant() {
void MeasurementComplexItem::_changeVariantIndex() {
if (idle()) {
auto variant = this->_variant.rawValue().toUInt();
auto variant = this->_variantIndex.rawValue().toUInt();
// Find old variant. Old variant corresponts with empty list.
std::size_t old_variant = std::numeric_limits<std::size_t>::max();
......@@ -828,14 +877,14 @@ void MeasurementComplexItem::_changeVariant() {
<< "Variant out of bounds (variant =" << variant << ").";
qCDebug(MeasurementComplexItemLog) << "Resetting variant to zero.";
disconnect(&this->_variant, &Fact::rawValueChanged, this,
&MeasurementComplexItem::_changeVariant);
this->_variant.setCookedValue(QVariant(0));
connect(&this->_variant, &Fact::rawValueChanged, this,
&MeasurementComplexItem::_changeVariant);
disconnect(&this->_variantIndex, &Fact::rawValueChanged, this,
&MeasurementComplexItem::_changeVariantIndex);
this->_variantIndex.setCookedValue(QVariant(0));
connect(&this->_variantIndex, &Fact::rawValueChanged, this,
&MeasurementComplexItem::_changeVariantIndex);
if (this->_variantVector.size() > 0) {
this->_changeVariant();
this->_changeVariantIndex();
}
}
}
......@@ -904,63 +953,60 @@ int MeasurementComplexItem::lastSequenceNumber() const {
return _sequenceNumber + std::max(0, this->_route.size() - 1);
}
bool MeasurementComplexItem::addGenerator(const QString &name,
routing::GeneratorBase *g) {
if (name.isEmpty()) {
qCDebug(MeasurementComplexItemLog) << "addGenerator(): empty name string.";
return false;
}
bool MeasurementComplexItem::addGenerator(routing::GeneratorBase *g) {
if (!g) {
if (g == nullptr) {
qCDebug(MeasurementComplexItemLog) << "addGenerator(): empty generator.";
Q_ASSERT(g != nullptr);
return false;
}
if (this->_generatorNameList.contains(name)) {
qCDebug(MeasurementComplexItemLog) << "addGenerator(): generator "
"already registered.";
for (const auto &otherGenerator : _generatorList) {
if (otherGenerator->name() == g->name()) {
qCDebug(MeasurementComplexItemLog)
<< "addGenerator(): generator with name " << g->name()
<< " already added.";
Q_ASSERT(otherGenerator->name() == g->name());
return false;
} else {
this->_generatorNameList.push_back(name);
}
}
this->_generatorList.push_back(g);
if (this->_generatorList.size() == 1) {
_setGenerator(g);
}
emit generatorNameListChanged();
emit generatorListChanged();
return true;
}
}
bool MeasurementComplexItem::removeGenerator(const QString &name) {
auto index = this->_generatorNameList.indexOf(name);
if (index >= 0) {
return removeGenerator(generatorIndex(name));
}
bool MeasurementComplexItem::removeGenerator(int index) {
if (index >= 0 && index < this->_generatorList.size()) {
// Is this the current generator?
const auto &g = this->_generatorList.at(index);
if (g == this->_pGenerator) {
if (index > 0) {
_setGenerator(this->_generatorList.at(index - 1));
} else if (index + 1 < _generatorList.size()) {
_setGenerator(this->_generatorList.at(index + 1));
} else {
_setGenerator(nullptr);
}
}
this->_generatorNameList.removeAt(index);
auto gen = this->_generatorList.takeAt(index);
gen->deleteLater();
emit generatorNameListChanged();
return true;
} else {
qCDebug(MeasurementComplexItemLog)
<< "removeGenerator(): generator " << name << " not registered.";
return false;
// Should the generator be deleted?
if (gen->parent() == this || gen->parent() == nullptr) {
gen->deleteLater();
}
}
bool MeasurementComplexItem::removeGenerator(int index) {
if (index >= 0 && index < this->_generatorNameList.size()) {
return removeGenerator(this->_generatorNameList.at(index));
emit generatorListChanged();
return true;
} else {
qCDebug(MeasurementComplexItemLog) << "removeGenerator(): index (" << index
<< ") out"
......@@ -971,15 +1017,7 @@ bool MeasurementComplexItem::removeGenerator(int index) {
}
bool MeasurementComplexItem::switchToGenerator(const QString &name) {
auto index = this->_generatorNameList.indexOf(name);
if (index >= 0) {
_setGenerator(this->_generatorList.at(index));
return true;
} else {
qCDebug(MeasurementComplexItemLog)
<< "switchToGenerator(): generator " << name << " not registered.";
return false;
}
return switchToGenerator(generatorIndex(name));
}
bool MeasurementComplexItem::switchToGenerator(int index) {
......@@ -991,7 +1029,7 @@ bool MeasurementComplexItem::switchToGenerator(int index) {
<< "switchToGenerator(): index (" << index
<< ") out"
"of bounds ( "
<< this->_generatorNameList.size() << " ).";
<< this->_generatorList.size() << " ).";
return false;
}
}
......@@ -1000,14 +1038,29 @@ void MeasurementComplexItem::resetGenerators() {
while (_generatorList.size() > 0) {
removeGenerator(0);
}
auto lg = new routing::LinearGenerator(this->_pAreaData, this);
addGenerator(lg->name(), lg);
auto cg = new routing::CircularGenerator(this->_pAreaData, this);
addGenerator(cg->name(), cg);
auto lg = routing::GeneratorFactory::instance()->create(
routing::LinearGenerator::typeString, this);
lg->setData(this->_pAreaData);
addGenerator(lg);
auto cg = routing::GeneratorFactory::instance()->create(
routing::CircularGenerator::typeString, this);
cg->setData(this->_pAreaData);
addGenerator(cg);
}
QList<MeasurementComplexItem::PtrGenerator>
MeasurementComplexItem::generatorList() const {
return _generatorList;
}
QStringList MeasurementComplexItem::generatorNameList() const {
return this->_generatorNameList;
QStringList list;
for (const auto gen : _generatorList) {
list.append(gen->name());
}
return list;
}
routing::GeneratorBase *MeasurementComplexItem::generator() {
......@@ -1039,6 +1092,18 @@ int MeasurementComplexItem::generatorIndex() const {
return this->_generatorList.indexOf(this->_pGenerator);
}
int MeasurementComplexItem::generatorIndex(const QString &name) {
int index = -1;
for (int i = 0; i < _generatorList.size(); ++i) {
const auto gen = _generatorList[i];
if (gen->name() == name) {
index = i;
break;
}
}
return index;
}
void MeasurementComplexItem::startEditing() {
if (!editing()) {
*_pEditorData = *_pAreaData;
......@@ -1121,11 +1186,11 @@ void MeasurementComplexItem::_storeRoutingData(
emit variantNamesChanged();
// Set variant to 0.
disconnect(&this->_variant, &Fact::rawValueChanged, this,
&MeasurementComplexItem::_changeVariant);
this->_variant.setCookedValue(QVariant(0));
connect(&this->_variant, &Fact::rawValueChanged, this,
&MeasurementComplexItem::_changeVariant);
disconnect(&this->_variantIndex, &Fact::rawValueChanged, this,
&MeasurementComplexItem::_changeVariantIndex);
this->_variantIndex.setCookedValue(QVariant(0));
connect(&this->_variantIndex, &Fact::rawValueChanged, this,
&MeasurementComplexItem::_changeVariantIndex);
// Select first variant as route.
this->_route.swap(this->_variantVector.first());
......@@ -1140,7 +1205,7 @@ void MeasurementComplexItem::_storeRoutingData(
}
}
Fact *MeasurementComplexItem::variant() { return &_variant; }
Fact *MeasurementComplexItem::variantIndex() { return &_variantIndex; }
Fact *MeasurementComplexItem::altitude() { return &this->_altitude; }
......
......@@ -34,12 +34,12 @@ public:
const QString &kmlOrShpFile, QObject *parent);
~MeasurementComplexItem();
Q_PROPERTY(Fact *variant READ variant CONSTANT)
Q_PROPERTY(Fact *altitude READ variant CONSTANT)
Q_PROPERTY(Fact *variantIndex READ variantIndex CONSTANT)
Q_PROPERTY(Fact *altitude READ altitude CONSTANT)
Q_PROPERTY(
QStringList variantNames READ variantNames NOTIFY variantNamesChanged)
Q_PROPERTY(QStringList generatorNameList READ generatorNameList NOTIFY
generatorNameListChanged)
generatorListChanged)
Q_PROPERTY(bool calculating READ calculating NOTIFY calculatingChanged)
Q_PROPERTY(bool editing READ editing NOTIFY editingChanged)
Q_PROPERTY(bool idle READ idle NOTIFY idleChanged)
......@@ -95,18 +95,56 @@ public:
virtual QString abbreviation(void) const override final;
// Generator
bool addGenerator(const QString &name, routing::GeneratorBase *g);
//!
//! \brief addGenerator Adds a generator.
//!
//! Adds a generator. The generator will be added to the generatorList() and
//! it's name to the generatorNameList(). Generators are identified by index
//! or name(), hence their name must be unique. A generator can not be added
//! if name() is already inside generatorNameList(). \param g Pointer to a
//! generator. \return Returns true if the generator was addes successfully,
//! false either.
//!
bool addGenerator(routing::GeneratorBase *g);
//!
//! \brief removeGenerator Removes the generator.
//! \param name The name of the generator to be removed.
//! \return Returns true if the generator was removed successfully.
//! \note The generator will be deleted if this or nullptr is it's parent.
bool removeGenerator(const QString &name);
//!
//! \brief removeGenerator Removes the generator.
//! \param index The index of the generator to be removed
//! \return Returns true if the generator was removed successfully.
//! \note See above.
bool removeGenerator(int index);
Q_INVOKABLE bool switchToGenerator(const QString &name);
Q_INVOKABLE bool switchToGenerator(int index);
//!
//! \brief resetGenerators Resets the generators as they where after creation
//! of this object.
//!
Q_INVOKABLE void resetGenerators();
QList<PtrGenerator> generatorList() const;
QStringList generatorNameList() const;
routing::GeneratorBase *generator();
const routing::GeneratorBase *generator() const;
routing::GeneratorBase *generator(int index);
const routing::GeneratorBase *generator(int index) const;
//!
//! \brief generatorIndex
//! \return Returns the index of the current generator.
int generatorIndex() const;
//!
//! \brief generatorIndex
//! \param name
//! \return Returns the index of the generator with the name \p name, or -1 if
//! the generator is unknown.
//!
int generatorIndex(const QString &name);
// Editing.
//!
......@@ -142,9 +180,9 @@ public:
AreaData *areaData();
QVariantList route();
Fact *variant();
Fact *altitude();
Fact *variantIndex();
QStringList variantNames() const;
Fact *altitude();
bool calculating() const;
bool editing() const; // set to true on creation
......@@ -158,7 +196,7 @@ public:
signals:
void variantNamesChanged();
void generatorNameListChanged();
void generatorListChanged();
void generatorChanged();
void calculatingChanged();
......@@ -173,7 +211,7 @@ private slots:
// Worker functions.
void _storeRoutingData(PtrRoutingData pRoute);
void _updateRoute();
void _changeVariant();
void _changeVariantIndex();
void _reverseRoute();
private:
......@@ -184,6 +222,7 @@ private:
static bool _editing(STATE state);
static bool _idle(STATE state);
void _updateFlightpathSegments();
void _onAltitudeChanged();
// Hirarcical stuff.
int _sequenceNumber;
......@@ -195,7 +234,7 @@ private:
// Facts
QMap<QString, FactMetaData *> _metaDataMap;
SettingsFact _altitude;
SettingsFact _variant;
SettingsFact _variantIndex;
QStringList _variantNames;
// Area data
......@@ -205,7 +244,6 @@ private:
// Generators
QList<PtrGenerator> _generatorList;
QStringList _generatorNameList;
PtrGenerator _pGenerator;
// Routing.
......
......@@ -9,7 +9,7 @@
QGC_LOGGING_CATEGORY(GeoAreaLog, "GeoAreaLog")
const char *GeoArea::name = "GeoArea";
const char *GeoArea::nameString = "GeoArea";
const char *GeoArea::areaTypeKey = "AreaType";
const char *GeoArea::settingsGroup = "GeoArea";
......@@ -59,7 +59,7 @@ bool GeoArea::isCorrect() {
std::stringstream ss;
ss << bg::wkt(polygonENU);
qCWarning(GeoAreaLog) << "polygonENU: " << ss.str().c_str();
setErrorString(tr("Area invalid. Area must be a simple polygon."));
setErrorString(this->objectName() + tr(" must be a simple polygon."));
}
}
return false;
......@@ -81,7 +81,7 @@ bool GeoArea::covers(const QGeoCoordinate &c) {
}
void GeoArea::init() {
this->setObjectName(name);
this->setObjectName(nameString);
// connect(this, &GeoArea::pathChanged, [this] {
// if (this->objectName() != "Tile") {
// qDebug() << this->objectName() << " path: " << this->path() << "\n";
......
......@@ -30,12 +30,13 @@ public:
//!
//! \brief covers Checks if GeoArea covers c.
//! \param c
//! \return Returns true if c is inside, or on the border of GeoArea.
//! \return Returns true if c is inside, or on the border of GeoArea, false
//! either.
//!
Q_INVOKABLE bool covers(const QGeoCoordinate &c);
// static Members
static const char *name;
static const char *nameString;
static const char *areaTypeKey;
static const char *settingsGroup;
......
......@@ -5,14 +5,22 @@
#include <boost/units/systems/si.hpp>
#include "JsonHelper.h"
#include "QGCLoggingCategory.h"
#include <QJsonArray>
#ifndef SNAKE_MAX_TILES
#define SNAKE_MAX_TILES 1000
#endif
QGC_LOGGING_CATEGORY(MeasurementAreaLog, "MeasurementAreaLog")
namespace {
const char *tileCenterPointsKey = "TileCenterPoints";
const char *tileArrayKey = "TileArray";
} // namespace
TileData::TileData() : tiles(this) {}
TileData::~TileData() { tiles.clearAndDeleteContents(); }
......@@ -50,6 +58,82 @@ bool TileData::operator!=(const TileData &other) const {
return !this->operator==(other);
}
void TileData::saveToJson(QJsonObject &json) {
// save center points
QJsonValue jsonCenterPoints;
JsonHelper::saveGeoCoordinateArray(tileCenterPoints, false, jsonCenterPoints);
json[tileCenterPointsKey] = std::move(jsonCenterPoints);
// save tiles
QJsonArray jsonTiles;
for (int i = 0; i < tiles.count(); ++i) {
auto tile = tiles.value<SnakeTile *>(i);
if (tile != nullptr) {
QJsonObject jsonTile;
tile->saveToJson(jsonTile);
jsonTiles.append(jsonTile);
} else {
qCritical() << "TileData::saveToJson(): Object other than SnakeTile "
"inside tiles (QmlObjectListModel))";
Q_ASSERT(tile != nullptr);
}
}
json[tileArrayKey] = std::move(jsonTiles);
}
bool TileData::loadFromJson(const QJsonObject &json, QString &errorString) {
clear();
// load tiles
if (json.contains(tileArrayKey) && json[tileArrayKey].isArray()) {
QString e;
for (const auto &jsonTile : json[tileArrayKey].toArray()) {
auto tile = new SnakeTile(this);
if (tile->loadFromJson(jsonTile.toObject(), e)) {
tiles.append(tile);
} else {
tile->deleteLater();
errorString.append(e);
return false;
}
}
} else {
errorString.append(tr("Not able to load tiles.\n"));
qCWarning(MeasurementAreaLog)
<< "Not able to load tiles. tileArrayKey missing or wrong type.";
if (json.contains(tileArrayKey)) {
qCWarning(MeasurementAreaLog)
<< "tile array type: " << json[tileArrayKey].type();
}
return false;
}
// load center points
if (json.contains(tileCenterPointsKey) &&
json[tileCenterPointsKey].isArray()) {
QString e;
if (!JsonHelper::loadGeoCoordinateArray(json[tileCenterPointsKey], false,
tileCenterPoints, e)) {
errorString.append(e);
errorString.append("\n");
return false;
}
} else {
errorString.append(tr("Not able to load center points.\n"));
qCWarning(MeasurementAreaLog)
<< "Not able to load center points. tileCenterPointsKey missing or "
"wrong type.";
if (json.contains(tileCenterPointsKey)) {
qCWarning(MeasurementAreaLog)
<< "center points type: " << json[tileCenterPointsKey].type();
}
return false;
}
return true;
}
void TileData::clear() {
this->tiles.clearAndDeleteContents();
this->tileCenterPoints.clear();
......@@ -68,7 +152,9 @@ const char *tileHeightKey = "TileHeight";
const char *tileWidthName = "TileWidth";
const char *minTileAreaKey = "MinTileAreaPercent";
const char *showTilesKey = "ShowTiles";
const char *MeasurementArea::name = "Measurement Area";
const char *progressKey = "Progress";
const char *tileKey = "Tiles";
const char *MeasurementArea::nameString = "Measurement Area";
MeasurementArea::MeasurementArea(QObject *parent)
: GeoArea(parent),
......@@ -193,7 +279,20 @@ bool MeasurementArea::saveToJson(QJsonObject &json) {
json[tileWidthName] = _tileWidth.rawValue().toDouble();
json[minTileAreaKey] = _minTileAreaPercent.rawValue().toDouble();
json[showTilesKey] = _showTiles.rawValue().toBool();
json[areaTypeKey] = name;
json[areaTypeKey] = nameString;
// save progess
QJsonArray jsonProgess;
for (const auto &p : _progress) {
jsonProgess.append(p);
}
json[progressKey] = std::move(jsonProgess);
// save tiles
QJsonObject jsonTiles;
_tileData.saveToJson(jsonTiles);
json[tileKey] = std::move(jsonTiles);
return true;
} else {
qCDebug(MeasurementAreaLog)
......@@ -211,6 +310,7 @@ bool MeasurementArea::loadFromJson(const QJsonObject &json,
disableUpdate();
bool retVal = true;
// load parameters necessary for tile calculation.
if (!json.contains(tileHeightKey) || !json[tileHeightKey].isDouble()) {
errorString.append(tr("Could not load tile height!\n"));
retVal = false;
......@@ -232,15 +332,59 @@ bool MeasurementArea::loadFromJson(const QJsonObject &json,
_minTileAreaPercent.setRawValue(json[minTileAreaKey].toDouble());
}
if (!json.contains(showTilesKey) || !json[showTilesKey].isBool()) {
errorString.append(tr("Could not load show tiles !\n"));
retVal = false;
} else {
// load less important parameters
if (json.contains(showTilesKey) || !json[showTilesKey].isBool()) {
_showTiles.setRawValue(json[showTilesKey].toBool());
}
// load tiles and progress
bool tileError = false;
if (json.contains(tileKey) && json[tileKey].isObject()) {
QString e;
if (!_tileData.loadFromJson(json[tileKey].toObject(), e)) {
qCWarning(MeasurementAreaLog) << "TileData::loadFromJson(): " << e;
tileError = true;
} else {
progressChanged();
}
} else {
tileError = true;
}
bool progressError = false;
QVector<int> prog;
if (json.contains(progressKey) && json[progressKey].isArray()) {
for (const auto &p : json[progressKey].toArray()) {
if (p.isDouble()) {
prog.append(p.toDouble());
} else {
progressError = true;
break;
}
}
// check if entries are in range
if (!progressError) {
for (const auto &p : prog) {
if (p < 0 || p > 100) {
progressError = true;
break;
}
}
}
} else {
progressError = true;
}
if (!progressError) {
_progress.swap(prog);
progressChanged();
}
// do update if error occurred.
enableUpdate();
if (progressError || tileError) {
doUpdate();
}
return retVal;
} else {
......@@ -408,7 +552,7 @@ void MeasurementArea::enableUpdate() {
}
void MeasurementArea::init() {
this->setObjectName(name);
this->setObjectName(nameString);
connect(&this->_tileHeight, &Fact::rawValueChanged, this,
&MeasurementArea::deferUpdate);
connect(&this->_tileWidth, &Fact::rawValueChanged, this,
......
......@@ -21,6 +21,9 @@ public:
bool operator==(const TileData &other) const;
bool operator!=(const TileData &other) const;
void saveToJson(QJsonObject &json);
bool loadFromJson(const QJsonObject &json, QString &errorString);
void clear();
std::size_t size() const;
};
......@@ -68,7 +71,7 @@ public:
// Static Variables
static const char *settingsGroup;
static const char *name;
static const char *nameString;
signals:
void tilesChanged();
......
......@@ -8,7 +8,7 @@
QGC_LOGGING_CATEGORY(SafeAreaLog, "SafeAreaLog")
const char *SafeArea::name = "Safe Area";
const char *SafeArea::nameString = "Safe Area";
const char *depotKey = "Depot Point";
SafeArea::SafeArea(QObject *parent) : GeoArea(parent) { init(); }
......@@ -84,7 +84,7 @@ bool SafeArea::setDepot(const QGeoCoordinate &newDepot) {
bool SafeArea::saveToJson(QJsonObject &json) {
if (this->GeoArea::saveToJson(json)) {
json[areaTypeKey] = name;
json[areaTypeKey] = nameString;
QJsonValue jsonDepot;
JsonHelper::saveGeoCoordinate(_depot, false, jsonDepot);
......@@ -135,6 +135,6 @@ bool SafeArea::isCorrect() {
}
void SafeArea::init() {
this->setObjectName(name);
this->setObjectName(nameString);
connect(this, &GeoArea::pathChanged, this, &SafeArea::putDepotInside);
}
......@@ -27,7 +27,7 @@ public:
QGeoCoordinate depotQml(void) const;
// static Members
static const char *name;
static const char *nameString;
signals:
void depotChanged(void);
......
......@@ -4,14 +4,14 @@
"QGC.MetaData.Facts":
[
{
"name": "Variant",
"shrotDesc": "Route variant.",
"name": "VariantIndex",
"shrotDesc": "Route variant index.",
"type": "uint64",
"default": 0
},
{
"name": "Altitude",
"shrotDesc": "Altitude",
"shrotDesc": "Altitude.",
"type": "double",
"units": "m",
"min": 1,
......
......@@ -7,11 +7,15 @@ import QGroundControl.FactControls 1.0
import QGroundControl.ScreenTools 1.0
GridLayout {
id:_root
id: _root
property bool checked: true
property var missionItem: undefined
property int availableWidth: 300
property bool areasCorrect: false
property string errorString: ""
signal abort
property var _areaData: missionItem.areaData
property real _margin: ScreenTools.defaultFontPixelWidth / 2
......@@ -21,12 +25,35 @@ GridLayout {
columns: 2
Component.onCompleted: {
console.assert(missionItem !== undefined, "please set the missionItem property")
console.assert(missionItem !== undefined,
"please set the missionItem property")
if (checked) {
areasCorrectTimer.start()
}
}
onCheckedChanged: {
if (checked) {
areasCorrectTimer.start()
} else {
areasCorrectTimer.stop()
}
}
ExclusiveGroup {
id: areaGroup
}
ExclusiveGroup{id:areaGroup}
QGCLabel {
id: tipLabel
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
text: qsTr("Use the Area Editor to modify areas.")
Layout.fillWidth: true
Layout.columnSpan: parent.columns
}
Repeater{
Repeater {
id: areaSelector
property int selectedIndex: -1
......@@ -39,36 +66,37 @@ GridLayout {
Layout.columnSpan: 2
onCheckedChanged: {
if (checked){
if (checked) {
areaSelector.selectedIndex = index
}
}
Component.onCompleted: {
if (index === 0){
if (index === 0) {
checked = true
}
object.interactive = Qt.binding(function(){return checked && _root.checked})
object.interactive = Qt.binding(function () {
return checked && _root.checked
})
}
}
} // area Repeater
ColumnLayout {
id:editorParent
id: editorParent
Layout.fillWidth: true
Layout.maximumWidth: parent.width
Layout.columnSpan: 2
}
Repeater{
id:areaEditorRepeater
Repeater {
id: areaEditorRepeater
Layout.maximumWidth: parent.width
model: _missionItem.areaData.areaList
delegate: Item{
id:editor
delegate: Item {
id: editor
visible: index == areaSelector.selectedIndex
property var _visualItem: undefined
......@@ -78,12 +106,19 @@ GridLayout {
if (geoArea.editorQML && !_visualItem) {
var component = Qt.createComponent(geoArea.editorQML)
if (component.status === Component.Error) {
console.log("Error loading Qml: ", geoArea.editorQML, component.errorString())
console.log("Error loading Qml: ", geoArea.editorQML,
component.errorString())
} else {
_visualItem = component.createObject(editorParent, {
geoArea: editor.geoArea,
visible: Qt.binding(function(){return editor.visible}),
availableWidth: Qt.binding(function(){return editorParent.width})})
"geoArea": editor.geoArea,
"visible": Qt.binding(function () {
return editor.visible
}),
"availableWidth": Qt.binding(
function () {
return editorParent.width
})
})
}
}
}
......@@ -96,23 +131,66 @@ GridLayout {
} // editor
} // areaEditorRepeater
QGCButton{
text: "Check Rules"
enabled: _root.checked
SectionHeader {
id: commandsHeader
Layout.fillWidth: true
onClicked: {
_areaData.isCorrect()
Layout.columnSpan: parent.columns
text: qsTr("Commands and Errors")
}
GridLayout {
columnSpacing: _margin
rowSpacing: _margin
columns: 2
Layout.columnSpan: 2
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{
QGCButton {
text: "Intersection"
enabled: _root.checked
Layout.fillWidth: true
Layout.columnSpan: parent.columns
onClicked: {
_areaData.intersection()
}
}
}
QGCButton {
text: "Reset"
onClicked: {
_root.abort()
}
Layout.fillWidth: true
Layout.columnSpan: parent.columns
}
}
Timer {
id: areasCorrectTimer
running: false
interval: 100
repeat: true
onTriggered: {
_root.areasCorrect = _missionItem.areaData.isCorrect(
false /*show gui message*/
)
if (!_root.areasCorrect) {
_root.errorString = _missionItem.areaData.errorString
} else {
_root.errorString = ""
}
}
}
}
......@@ -41,7 +41,7 @@ GridLayout {
}
QGCButton {
text: qsTr("Reset Ref.")
text: qsTr("Reset Reference")
onClicked: generator.resetReference();
Layout.fillWidth: true
Layout.columnSpan: 2
......
......@@ -3,7 +3,7 @@ import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.4
import QtQuick.Dialogs 1.2
import QtQuick.Extras 1.4
import QtQuick.Layouts 1.2
import QtQuick.Layouts 1.3
import QGroundControl 1.0
import QGroundControl.ScreenTools 1.0
......@@ -25,89 +25,105 @@ Rectangle {
// The following properties must be available up the hierarchy chain
//property real availableWidth ///< Width for control
//property var missionItem ///< Mission Item for editor
property real _margin: ScreenTools.defaultFontPixelWidth / 2
property real _fieldWidth: ScreenTools.defaultFontPixelWidth * 10.5
property var _vehicle: QGroundControl.multiVehicleManager.activeVehicle ?
QGroundControl.multiVehicleManager.activeVehicle :
QGroundControl.multiVehicleManager.offlineEditingVehicle
property var _vehicle: QGroundControl.multiVehicleManager.activeVehicle ? QGroundControl.multiVehicleManager.activeVehicle : QGroundControl.multiVehicleManager.offlineEditingVehicle
property var _missionItem: missionItem
property var _areaData: missionItem.areaData
QGCPalette { id: qgcPal; colorGroupEnabled: true }
QGCPalette {
id: qgcPal
colorGroupEnabled: true
}
ColumnLayout { // main Column
Column {
// main Column
id: mainColumn
anchors.margins: _margin
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
QGCTabBar {
id: tabBar
anchors.left: parent.left
anchors.right: parent.right
enabled: !editing || editing && correct
readonly property int areaEditorIndex: 0
readonly property int parameterEditorIndex: 1
readonly property int nemoControlsIndex: 2
property bool editing: _missionItem.editing
property bool correct: false
QGCLabel {
id: tipLabel
Layout.fillWidth: true
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
text: qsTr("Use the Area Editor to modify areas.")
visible: areaDataEditor.visible
Component.onCompleted: currentIndex = editing ? areaEditorIndex : parameterEditorIndex
QGCTabButton {
icon.source: "/qmlimages/PatternCamera.png"
icon.height: ScreenTools.defaultFontPixelHeight
}
QGCTabButton {
icon.source: "/qmlimages/PatternGrid.png"
icon.height: ScreenTools.defaultFontPixelHeight
}
QGCTabButton {
icon.source: "/qmlimages/PatternPresets.png"
icon.height: ScreenTools.defaultFontPixelHeight
}
GridLayout {
id: editorSelector
Layout.fillWidth: true
columnSpacing: _margin
rowSpacing: _margin
QGCButton{
text: "Open Area Editor"
visible: parameterEditor.visible
Layout.fillWidth: true
Layout.columnSpan: 2
onClicked:{
_missionItem.startEditing()
onEditingChanged: {
if (editing) {
areasCorrectTimer.start()
} else {
areasCorrectTimer.stop()
}
}
QGCButton{
text: "Done"
Layout.fillWidth: true
visible: areaDataEditor.visible
onClicked: {
if (_areaData.isCorrect()){
onCurrentIndexChanged: {
if (currentIndex === areaEditorIndex) {
_missionItem.startEditing()
} else {
_missionItem.stopEditing()
}
}
}
QGCButton{
text: "Abort"
visible: areaDataEditor.visible
Layout.fillWidth: true
onClicked:{
missionItem.abortEditing()
Timer {
id: areasCorrectTimer
running: false
interval: 100
repeat: true
onTriggered: {
tabBar.correct = _missionItem.areaData.isCorrect(
false /*show gui message*/
)
}
}
}
} // editorSelector
MCI.ParameterEditor{
id:parameterEditor
StackLayout {
width: parent.width
currentIndex: tabBar.currentIndex
MCI.AreaDataEditor {
id: areaEditor
checked: visible
missionItem: _root._missionItem
availableWidth: mainColumn.width
checked: !_missionItem.editing
visible: checked
availableWidth: parent.width
onAbort: {
missionItem.abortEditing()
tabBar.currentIndex = tabBar.parameterEditorIndex
}
}
MCI.AreaDataEditor{
id:areaDataEditor
MCI.ParameterEditor {
id: parameterEditor
checked: visible
missionItem: _root._missionItem
availableWidth: mainColumn.width
checked: _missionItem.editing
visible: checked
}
}
} // main Column
} // Rectangle
......@@ -85,6 +85,7 @@ GridLayout {
GridLayout{
Layout.columnSpan: parent.columns
Layout.maximumWidth: parent.width
columns: 3
columnSpacing: _margin
rowSpacing: _margin
......@@ -99,6 +100,7 @@ GridLayout {
delegate: QGCRadioButton {
checked: index === variantIndex
text: variantRepeater.names[index] ? variantRepeater.names[index]: ""
Layout.fillWidth: true
property int variantIndex: missionItem.variantIndex.value
......
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