Commit 912e993b authored by Valentin Platzgummer's avatar Valentin Platzgummer

wima planer edited

parent 6fd60bb5
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -15,7 +15,8 @@ template <> ClipperLib::cInt get<1>(ClipperLib::IntPoint &p) { return p.Y; }
CSWorker::CSWorker(QObject *parent)
: QThread(parent), _deltaR(2 * bu::si::meter),
_deltaAlpha(3 * bu::degree::degree), _minLength(10 * bu::si::meter),
_calculating(false), _stop(false), _restart(false) {}
_useDepotSafeArea(false), _calculating(false), _stop(false),
_restart(false) {}
CSWorker::~CSWorker() {
this->_stop = true;
......@@ -34,11 +35,46 @@ void CSWorker::update(const QList<QGeoCoordinate> &polygon,
// Sample input.
Lock lk(this->_mutex);
this->_polygon = polygon;
for (auto &v : this->_polygon) {
v.setAltitude(0);
}
this->_origin = origin;
this->_origin.setAltitude(0);
this->_deltaR = deltaR;
this->_deltaAlpha = deltaAlpha;
this->_minLength = minLength;
lk.unlock();
this->_useDepotSafeArea = false;
if (!this->isRunning()) {
this->start();
} else {
Lock lk(this->_mutex);
this->_restart = true;
this->_cv.notify_one();
}
}
void CSWorker::update(const QGeoCoordinate &depot,
const QList<QGeoCoordinate> &safeArea,
const QList<QGeoCoordinate> &polygon,
const QGeoCoordinate &origin, snake::Length deltaR,
snake::Length minLength, snake::Angle deltaAlpha) {
// Sample input.
Lock lk(this->_mutex);
this->_depot = depot;
this->_safeArea = safeArea;
this->_polygon = polygon;
for (auto &v : this->_polygon) {
v.setAltitude(0);
}
this->_origin = origin;
this->_origin.setAltitude(0);
this->_deltaR = deltaR;
this->_deltaAlpha = deltaAlpha;
this->_minLength = minLength;
lk.unlock();
this->_useDepotSafeArea = true;
if (!this->isRunning()) {
this->start();
......@@ -53,7 +89,15 @@ void CSWorker::run() {
qWarning() << "CSWorker::run(): thread start.";
while (!this->_stop) {
// Copy input.
QGeoCoordinate depot;
QList<QGeoCoordinate> safeArea;
Lock lk(this->_mutex);
if (this->_useDepotSafeArea) {
depot = this->_depot;
safeArea = this->_safeArea;
} else {
safeArea = this->_polygon;
}
const auto polygon = this->_polygon;
const auto origin = this->_origin;
const auto deltaR = this->_deltaR;
......@@ -74,11 +118,16 @@ void CSWorker::run() {
emit calculatingChanged();
// Convert geo polygon to ENU polygon.
snake::BoostPolygon polygonENU;
snake::BoostPolygon safeAreaENU;
snake::BoostPoint originENU{0, 0};
snake::BoostPoint depotENU;
snake::areaToEnu(origin, polygon, polygonENU);
snake::areaToEnu(origin, safeArea, safeAreaENU);
snake::toENU(origin, depot, depotENU);
std::string error;
// Check validity.
if (!bg::is_valid(polygonENU, error)) {
if (!bg::is_valid(polygonENU, error) ||
!bg::is_valid(safeAreaENU, error)) {
#ifdef DEBUG_CIRCULAR_SURVEY
qWarning() << "CSWorker::run(): "
"invalid polygon.";
......@@ -159,7 +208,9 @@ void CSWorker::run() {
}
// Clip sectors to polygonENU.
ClipperLib::Path polygonClipper;
auto &outer = polygonENU.outer();
snake::BoostPolygon shrinked;
snake::offsetPolygon(polygonENU, shrinked, -0.1);
auto &outer = shrinked.outer();
polygonClipper.reserve(outer.size() - 1);
for (auto it = outer.begin(); it < outer.end() - 1; ++it) {
auto x = ClipperLib::cInt(std::round(it->get<0>() * CLIPPER_SCALE));
......@@ -176,6 +227,9 @@ void CSWorker::run() {
// Extract transects from PolyTree and convert them to
// BoostLineString
snake::Transects transectsENU;
if (this->_useDepotSafeArea) {
transectsENU.push_back(snake::BoostLineString{depotENU});
}
for (const auto &child : transectsClipper.Childs) {
snake::BoostLineString transect;
transect.reserve(child->Contour.size());
......@@ -233,44 +287,49 @@ void CSWorker::run() {
}
}
// Remove short transects
for (auto it = transectsENU.begin(); it < transectsENU.end();) {
auto begin = this->_useDepotSafeArea ? transectsENU.begin() + 1
: transectsENU.begin();
for (auto it = begin; it < transectsENU.end();) {
if (bg::length(*it) < minLength.value()) {
it = transectsENU.erase(it);
} else {
++it;
}
}
// Move transect with min. distance to the front.
auto minDist = std::numeric_limits<double>::max();
auto minIt = transectsENU.begin();
bool reverse = false;
for (auto it = transectsENU.begin(); it < transectsENU.end(); ++it) {
auto distFront = bg::distance(originENU, it->front());
auto distBack = bg::distance(originENU, it->back());
if (distFront < minDist) {
minDist = distFront;
minIt = it;
reverse = false;
}
if (distBack < minDist) {
minDist = distBack;
minIt = it;
reverse = true;
if (!this->_useDepotSafeArea) {
// Move transect with min. distance to the front.
auto minDist = std::numeric_limits<double>::max();
auto minIt = transectsENU.begin();
bool reverse = false;
for (auto it = transectsENU.begin(); it < transectsENU.end(); ++it) {
auto distFront = bg::distance(originENU, it->front());
auto distBack = bg::distance(originENU, it->back());
if (distFront < minDist) {
minDist = distFront;
minIt = it;
reverse = false;
}
if (distBack < minDist) {
minDist = distBack;
minIt = it;
reverse = true;
}
}
}
// Swap and reverse (if necessary).
if (minIt != transectsENU.begin()) {
auto minTransect = *minIt;
if (reverse) {
snake::BoostLineString rev;
for (auto it = minTransect.end() - 1; it >= minTransect.begin();
--it) {
rev.push_back(*it);
// Swap and reverse (if necessary).
if (minIt != transectsENU.begin()) {
auto minTransect = *minIt;
if (reverse) {
snake::BoostLineString rev;
for (auto it = minTransect.end() - 1; it >= minTransect.begin();
--it) {
rev.push_back(*it);
}
minTransect = rev;
}
minTransect = rev;
*minIt = *transectsENU.begin();
*transectsENU.begin() = minTransect;
}
*minIt = *transectsENU.begin();
*transectsENU.begin() = minTransect;
}
#ifdef SHOW_CIRCULAR_SURVEY_TIME
qWarning() << "CSWorker::run(): transect gen. time: "
......@@ -305,9 +364,9 @@ void CSWorker::run() {
};
std::string errorString;
// Route transects;
bool success = snake::route(polygonENU, transectsENU, transectsInfo,
bool success = snake::route(safeAreaENU, transectsENU, transectsInfo,
route, stopLambda, errorString);
if (!success && !this->_restart) {
if ((!success || route.size() < 3) && !this->_restart) {
#ifdef DEBUG_CIRCULAR_SURVEY
qWarning() << "CSWorker::run(): "
"routing failed.";
......@@ -318,19 +377,38 @@ void CSWorker::run() {
"restart requested.";
#endif
} else {
// Remove return path.
// Find index of first waypoint.
std::size_t idxFirst = 0;
const auto &info1 =
this->_useDepotSafeArea ? transectsInfo[1] : transectsInfo[0];
const auto &firstTransect = transectsENU[info1.index];
const auto &firstWaypoint =
info1.reversed ? firstTransect.back() : firstTransect.front();
double th = 0.001;
for (std::size_t i = 0; i < route.size(); ++i) {
auto dist = bg::distance(route[i], firstWaypoint);
if (dist < th) {
idxFirst = i;
break;
}
}
// Find index of last waypoint.
std::size_t idxLast = 0;
const auto &info = transectsInfo.back();
const auto &lastTransect = transectsENU[info.index];
const auto &lastWaypoint =
info.reversed ? lastTransect.front() : lastTransect.back();
auto &wp = route.back();
while (wp != lastWaypoint) {
route.pop_back();
wp = route.back();
for (long i = route.size() - 1; i >= 0; --i) {
auto dist = bg::distance(route[i], lastWaypoint);
if (dist < th) {
idxLast = i;
break;
}
}
// Convert to geo coordinates and notify main thread.
auto pRoute = PtrRoute(new Route());
for (const auto &vertex : route) {
for (std::size_t i = idxFirst; i <= idxLast; ++i) {
auto vertex = route[i];
QGeoCoordinate c;
snake::fromENU(origin, vertex, c);
pRoute->append(c);
......
......@@ -31,6 +31,11 @@ public slots:
void update(const QList<QGeoCoordinate> &polygon,
const QGeoCoordinate &origin, snake::Length deltaR,
snake::Length minLength, snake::Angle deltaAlpha);
void update(const QGeoCoordinate &depot,
const QList<QGeoCoordinate> &safeArea,
const QList<QGeoCoordinate> &polygon,
const QGeoCoordinate &origin, snake::Length deltaR,
snake::Length minLength, snake::Angle deltaAlpha);
signals:
void ready(PtrRoute pTransects);
......@@ -43,6 +48,8 @@ private:
mutable std::mutex _mutex;
mutable std::condition_variable _cv;
// Internal data
QGeoCoordinate _depot;
QList<QGeoCoordinate> _safeArea;
QList<QGeoCoordinate> _polygon;
QGeoCoordinate _origin;
snake::Length _deltaR;
......@@ -51,6 +58,7 @@ private:
std::size_t _maxWaypoints;
// State
std::atomic_bool _useDepotSafeArea;
std::atomic_bool _calculating;
std::atomic_bool _stop;
std::atomic_bool _restart;
......
......@@ -36,8 +36,8 @@ CircularSurvey::CircularSurvey(Vehicle *vehicle, bool flyView,
_deltaR(settingsGroup, _metaDataMap[deltaRName]),
_deltaAlpha(settingsGroup, _metaDataMap[deltaAlphaName]),
_minLength(settingsGroup, _metaDataMap[transectMinLengthName]),
_isInitialized(false), _pWorker(std::make_unique<CSWorker>()),
_needsStoring(false), _needsReversal(false) {
_pWorker(std::make_unique<CSWorker>()), _needsStoring(false),
_needsReversal(false) {
Q_UNUSED(kmlOrShpFile)
_editorQml = "qrc:/qml/CircularSurveyItemEditor.qml";
......@@ -50,6 +50,10 @@ CircularSurvey::CircularSurvey(Vehicle *vehicle, bool flyView,
&CircularSurvey::_rebuildTransects);
connect(this, &CircularSurvey::refPointChanged, this,
&CircularSurvey::_rebuildTransects);
connect(this, &CircularSurvey::depotChanged, this,
&CircularSurvey::_rebuildTransects);
connect(this, &CircularSurvey::safeAreaChanged, this,
&CircularSurvey::_rebuildTransects);
// Connect worker.
qRegisterMetaType<PtrRoute>("PtrRoute");
connect(this->_pWorker.get(), &CSWorker::ready, this,
......@@ -78,21 +82,40 @@ void CircularSurvey::setRefPoint(const QGeoCoordinate &refPt) {
}
}
void CircularSurvey::setIsInitialized(bool isInitialized) {
if (isInitialized != _isInitialized) {
_isInitialized = isInitialized;
emit isInitializedChanged();
}
}
QGeoCoordinate CircularSurvey::refPoint() const { return _referencePoint; }
Fact *CircularSurvey::deltaR() { return &_deltaR; }
Fact *CircularSurvey::deltaAlpha() { return &_deltaAlpha; }
bool CircularSurvey::isInitialized() { return _isInitialized; }
bool CircularSurvey::hidePolygon() const { return _hidePolygon; }
QGeoCoordinate CircularSurvey::depot() const { return this->_depot; }
QList<QGeoCoordinate> CircularSurvey::safeArea() const {
return this->_safeArea;
}
void CircularSurvey::setHidePolygon(bool hide) {
if (this->_hidePolygon != hide) {
this->_hidePolygon = hide;
emit hidePolygonChanged();
}
}
void CircularSurvey::setDepot(const QGeoCoordinate &depot) {
if (this->_depot != depot) {
this->_depot = depot;
emit depotChanged();
}
}
void CircularSurvey::setSafeArea(const QList<QGeoCoordinate> &safeArea) {
if (this->_safeArea != safeArea) {
this->_safeArea = safeArea;
emit safeAreaChanged();
}
}
bool CircularSurvey::load(const QJsonObject &complexObject, int sequenceNumber,
QString &errorString) {
......@@ -161,7 +184,6 @@ bool CircularSurvey::load(const QJsonObject &complexObject, int sequenceNumber,
_referencePoint.setLongitude(complexObject[refPointLongitudeName].toDouble());
_referencePoint.setLatitude(complexObject[refPointLatitudeName].toDouble());
_referencePoint.setAltitude(complexObject[refPointAltitudeName].toDouble());
setIsInitialized(true);
_ignoreRecalc = false;
......@@ -319,12 +341,21 @@ void CircularSurvey::_rebuildTransectsPhase1(void) {
} else {
this->_transects.clear();
auto polygon = this->_surveyAreaPolygon.coordinateList();
this->_pWorker->update(
polygon, this->_referencePoint,
this->_deltaR.rawValue().toDouble() * bu::si::meter,
this->_minLength.rawValue().toDouble() * bu::si::meter,
snake::Angle(this->_deltaAlpha.rawValue().toDouble() *
bu::degree::degree));
if (this->_depot.isValid() && this->_safeArea.size() >= 3) {
this->_pWorker->update(
this->_depot, this->_safeArea, polygon, this->_referencePoint,
this->_deltaR.rawValue().toDouble() * bu::si::meter,
this->_minLength.rawValue().toDouble() * bu::si::meter,
snake::Angle(this->_deltaAlpha.rawValue().toDouble() *
bu::degree::degree));
} else {
this->_pWorker->update(
polygon, this->_referencePoint,
this->_deltaR.rawValue().toDouble() * bu::si::meter,
this->_minLength.rawValue().toDouble() * bu::si::meter,
snake::Angle(this->_deltaAlpha.rawValue().toDouble() *
bu::degree::degree));
}
}
}
......@@ -351,7 +382,9 @@ void CircularSurvey::_setTransects(CircularSurvey::PtrRoute pRoute) {
Fact *CircularSurvey::transectMinLength() { return &_minLength; }
bool CircularSurvey::calculating() { return this->_pWorker->calculating(); }
bool CircularSurvey::calculating() const {
return this->_pWorker->calculating();
}
/*!
\class CircularSurveyComplexItem
......
......@@ -28,48 +28,43 @@ public:
Q_PROPERTY(Fact *deltaR READ deltaR CONSTANT)
Q_PROPERTY(Fact *deltaAlpha READ deltaAlpha CONSTANT)
Q_PROPERTY(Fact *transectMinLength READ transectMinLength CONSTANT)
Q_PROPERTY(bool isInitialized READ isInitialized WRITE setIsInitialized NOTIFY
isInitializedChanged)
Q_PROPERTY(bool calculating READ calculating NOTIFY calculatingChanged)
Q_PROPERTY(bool hidePolygon READ hidePolygon NOTIFY hidePolygon)
Q_INVOKABLE void resetReference(void);
Q_INVOKABLE void reverse(void);
// Property setters
void setRefPoint(const QGeoCoordinate &refPt);
// Set this to true if survey was automatically generated, prevents
// initialisation from gui.
void setIsInitialized(bool isInitialized);
void setHidePolygon(bool hide);
void setDepot(const QGeoCoordinate &depot);
void setSafeArea(const QList<QGeoCoordinate> &safeArea);
// Property getters
QGeoCoordinate refPoint() const;
Fact *deltaR();
Fact *deltaAlpha();
Fact *transectMinLength();
bool calculating();
// Is true if survey was automatically generated, prevents initialisation from
// gui.
bool isInitialized();
bool calculating() const;
bool hidePolygon() const;
QGeoCoordinate depot() const;
QList<QGeoCoordinate> safeArea() const;
// Overrides from ComplexMissionItem
// Overrides
bool load(const QJsonObject &complexObject, int sequenceNumber,
QString &errorString) final;
QString mapVisualQML(void) const final;
// Overrides from TransectStyleComplexItem
void save(QJsonArray &planItems) final;
bool specifiesCoordinate(void) const final;
QString &errorString) override final;
QString mapVisualQML(void) const override final;
void save(QJsonArray &planItems) override final;
bool specifiesCoordinate(void) const override final;
void appendMissionItems(QList<MissionItem *> &items,
QObject *missionItemParent) final;
void applyNewAltitude(double newAltitude) final;
double timeBetweenShots(void) final;
// Overrides from VisualMissionionItem
QString commandDescription(void) const final;
QString commandName(void) const final;
QString abbreviation(void) const final;
bool readyForSave(void) const final;
double additionalTimeDelay(void) const final;
QObject *missionItemParent) override final;
void applyNewAltitude(double newAltitude) override final;
double timeBetweenShots(void) override final;
QString commandDescription(void) const override final;
QString commandName(void) const override final;
QString abbreviation(void) const override final;
bool readyForSave(void) const override final;
double additionalTimeDelay(void) const override final;
static const char *settingsGroup;
static const char *deltaRName;
......@@ -82,8 +77,10 @@ public:
signals:
void refPointChanged();
void isInitializedChanged();
void calculatingChanged();
void hidePolygonChanged();
void depotChanged();
void safeAreaChanged();
private slots:
// Overrides from TransectStyleComplexItem
......@@ -109,14 +106,14 @@ private:
// minimal transect lenght, transects are rejected if they are shorter than
// this value
SettingsFact _minLength;
// indicates if the polygon and refpoint etc. are initialized, prevents
// reinitialisation from gui and execution of _rebuildTransectsPhase1 during
// init from gui
bool _isInitialized;
using PtrWorker = std::shared_ptr<CSWorker>;
PtrWorker _pWorker;
PtrRoute _pRoute;
bool _needsStoring;
bool _needsReversal;
bool _hidePolygon;
QGeoCoordinate _depot;
QList<QGeoCoordinate> _safeArea;
};
......@@ -135,14 +135,14 @@ bool WimaMeasurementArea::loadFromJson(const QJsonObject &json,
}
if (json.contains(tileWidthName) && json[tileWidthName].isDouble()) {
_tileHeight.setRawValue(json[tileWidthName].toDouble());
_tileWidth.setRawValue(json[tileWidthName].toDouble());
} else {
errorString.append(tr("Could not load tile width!\n"));
retVal = false;
}
if (json.contains(minTileAreaName) && json[minTileAreaName].isDouble()) {
_tileHeight.setRawValue(json[minTileAreaName].toDouble());
_minTileArea.setRawValue(json[minTileAreaName].toDouble());
} else {
errorString.append(tr("Could not load minimal tile area!\n"));
retVal = false;
......@@ -150,7 +150,7 @@ bool WimaMeasurementArea::loadFromJson(const QJsonObject &json,
if (json.contains(transectDistanceName) &&
json[transectDistanceName].isDouble()) {
_tileHeight.setRawValue(json[transectDistanceName].toDouble());
_transectDistance.setRawValue(json[transectDistanceName].toDouble());
} else {
errorString.append(tr("Could not load transect distance!\n"));
retVal = false;
......@@ -158,14 +158,14 @@ bool WimaMeasurementArea::loadFromJson(const QJsonObject &json,
if (json.contains(minTransectLengthName) &&
json[minTransectLengthName].isDouble()) {
_tileHeight.setRawValue(json[minTransectLengthName].toDouble());
_minTransectLength.setRawValue(json[minTransectLengthName].toDouble());
} else {
errorString.append(tr("Could not load minimal transect length!\n"));
retVal = false;
}
if (json.contains(showTilesName) && json[showTilesName].isBool()) {
_tileHeight.setRawValue(json[showTilesName].toDouble());
_showTiles.setRawValue(json[showTilesName].toBool());
} else {
errorString.append(tr("Could not load show tiles !\n"));
retVal = false;
......
#include "WimaServiceArea.h"
const char* WimaServiceArea::wimaServiceAreaName = "Service Area";
const char *WimaServiceArea::wimaServiceAreaName = "Service Area";
WimaServiceArea::WimaServiceArea(QObject *parent)
: WimaArea (parent)
{
init();
}
WimaServiceArea::WimaServiceArea(QObject *parent) : WimaArea(parent) { init(); }
WimaServiceArea::WimaServiceArea(const WimaServiceArea &other, QObject *parent)
: WimaArea (other, parent)
{
init();
: WimaArea(other, parent) {
init();
}
/*!
......@@ -21,63 +14,53 @@ WimaServiceArea::WimaServiceArea(const WimaServiceArea &other, QObject *parent)
*
* Calls the inherited operator WimaArea::operator=().
*/
WimaServiceArea &WimaServiceArea::operator=(const WimaServiceArea &other)
{
WimaArea::operator=(other);
return *this;
}
WimaServiceArea &WimaServiceArea::operator=(const WimaServiceArea &other) {
WimaArea::operator=(other);
void WimaServiceArea::setTakeOffPosition(const QGeoCoordinate &coordinate)
{
if(_takeOffPosition != coordinate){
_takeOffPosition = coordinate;
emit takeOffPositionChanged();
}
return *this;
}
void WimaServiceArea::setLandPosition(const QGeoCoordinate &coordinate)
{
if(_landPosition != coordinate){
_landPosition = coordinate;
emit landPositionChanged();
}
void WimaServiceArea::setDepot(const QGeoCoordinate &coordinate) {
if (_depot != coordinate) {
_depot = coordinate;
emit depotChanged();
}
}
void WimaServiceArea::saveToJson(QJsonObject &json)
{
this->WimaArea::saveToJson(json);
json[areaTypeName] = wimaServiceAreaName;
void WimaServiceArea::saveToJson(QJsonObject &json) {
this->WimaArea::saveToJson(json);
json[areaTypeName] = wimaServiceAreaName;
}
bool WimaServiceArea::loadFromJson(const QJsonObject &json, QString &errorString)
{
if ( this->WimaArea::loadFromJson(json, errorString)) {
bool retVal = true;
// code for loading here
return retVal;
} else {
qWarning() << errorString;
return false;
}
bool WimaServiceArea::loadFromJson(const QJsonObject &json,
QString &errorString) {
if (this->WimaArea::loadFromJson(json, errorString)) {
bool retVal = true;
// code for loading here
return retVal;
} else {
qWarning() << errorString;
return false;
}
}
void print(const WimaServiceArea &area)
{
QString message;
print(area, message);
qWarning() << message;
void print(const WimaServiceArea &area) {
QString message;
print(area, message);
qWarning() << message;
}
void print(const WimaServiceArea &area, QString &outputStr)
{
print(static_cast<const WimaArea&>(area), outputStr);
outputStr.append(QString("Takeoff Position: %s\n").arg(area._takeOffPosition.toString(QGeoCoordinate::Degrees)));
outputStr.append(QString("Land Position: %s\n").arg(area._landPosition.toString(QGeoCoordinate::Degrees)));
void print(const WimaServiceArea &area, QString &outputStr) {
print(static_cast<const WimaArea &>(area), outputStr);
outputStr.append(QString("Depot Position: %s\n")
.arg(area._depot.toString(QGeoCoordinate::Degrees)));
}
void WimaServiceArea::init()
{
this->setObjectName(wimaServiceAreaName);
void WimaServiceArea::init() {
this->setObjectName(wimaServiceAreaName);
connect(this, &WimaServiceArea::centerChanged, [this] {
if (!this->_depot.isValid()) {
this->setDepot(this->center());
}
});
}
#pragma once
#include <QObject>
#include "WimaArea.h"
#include "WimaTrackerPolyline.h"
#include <QObject>
class WimaServiceArea : public WimaArea
{
Q_OBJECT
class WimaServiceArea : public WimaArea {
Q_OBJECT
public:
WimaServiceArea(QObject* parent = nullptr);
WimaServiceArea(const WimaServiceArea& other, QObject* parent);
WimaServiceArea& operator=(const WimaServiceArea &other);
Q_PROPERTY(const QGeoCoordinate& takeOffPosition READ takeOffPosition WRITE setTakeOffPosition NOTIFY takeOffPositionChanged)
Q_PROPERTY(const QGeoCoordinate& landPosition READ landPosition WRITE setLandPosition NOTIFY landPositionChanged)
WimaServiceArea(QObject *parent = nullptr);
WimaServiceArea(const WimaServiceArea &other, QObject *parent);
WimaServiceArea &operator=(const WimaServiceArea &other);
// Overrides from WimaPolygon
QString mapVisualQML (void) const { return "WimaServiceAreaMapVisual.qml";}
QString editorQML (void) const { return "WimaServiceAreaEditor.qml";}
Q_PROPERTY(QGeoCoordinate depot READ depot WRITE setDepot NOTIFY depotChanged)
// Property acessors
const QGeoCoordinate& takeOffPosition (void) const { return _takeOffPosition;}
const QGeoCoordinate& landPosition (void) const { return _landPosition;}
// Overrides from WimaPolygon
QString mapVisualQML(void) const { return "WimaServiceAreaMapVisual.qml"; }
QString editorQML(void) const { return "WimaServiceAreaEditor.qml"; }
// Member Methodes
void saveToJson(QJsonObject& json);
bool loadFromJson(const QJsonObject& json, QString& errorString);
// Property acessors
const QGeoCoordinate &depot(void) const { return _depot; }