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

auto update improved, circular survey issue solved

parent aa921562
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.
......@@ -348,6 +348,13 @@ void CircularSurveyComplexItem::_rebuildTransectsPhase1()
using namespace PolygonCalculus;
using namespace PlanimetryCalculus;
// If the transects are getting rebuilt then any previously loaded mission items are now invalid
if (_loadedMissionItemsParent) {
_loadedMissionItems.clear();
_loadedMissionItemsParent->deleteLater();
_loadedMissionItemsParent = nullptr;
}
// check if input is valid
if ( _surveyAreaPolygon.count() < 3) {
......@@ -410,22 +417,16 @@ void CircularSurveyComplexItem::_rebuildTransectsPhase1()
}
QList<QPolygonF> convexPolygons;
decomposeToConvex(surveyPolygon, convexPolygons);
// generate transects
QList<QList<QPointF>> fullPath;
for (int i = 0; i < convexPolygons.size(); i++) {
const QPolygonF &polygon = convexPolygons[i];
QList<QList<QPointF>> transectPath;
double r = r_min;
QList<QList<QPointF>> currPolyPath;
while (r < r_max) {
Circle circle(r, origin);
QList<QPointFList> intersectPoints;
QList<IntersectType> typeList;
QList<QPair<int, int>> neighbourList;
if (intersects(circle, polygon, intersectPoints, neighbourList, typeList)) {
if (intersects(circle, surveyPolygon, intersectPoints, neighbourList, typeList)) {
// intersection Points between circle and polygon, entering polygon
// when walking in counterclockwise direction along circle
......@@ -437,8 +438,8 @@ void CircularSurveyComplexItem::_rebuildTransectsPhase1()
for (int j = 0; j < intersectPoints.size(); j++) {
QList<QPointF> intersects = intersectPoints[j];
QPointF p1 = polygon[neighbourList[j].first];
QPointF p2 = polygon[neighbourList[j].second];
QPointF p1 = surveyPolygon[neighbourList[j].first];
QPointF p2 = surveyPolygon[neighbourList[j].second];
QLineF intersetLine(p1, p2);
double lineAngle = truncateAngle(angle(intersetLine));
......@@ -484,45 +485,42 @@ void CircularSurveyComplexItem::_rebuildTransectsPhase1()
QList<QPointF> sectorPath = circle.approximateSektor(double(dalpha), alpha1, alpha2);
// use shortestPath() here if necessary, could be a problem if dr >>
if (sectorPath.size() > 0)
currPolyPath.append(sectorPath);
transectPath.append(sectorPath);
}
} else if (originInside) {
// circle fully inside polygon
QList<QPointF> sectorPath = circle.approximateSektor(double(dalpha), 0, 2*M_PI);
// use shortestPath() here if necessary, could be a problem if dr >>
currPolyPath.append(sectorPath);
transectPath.append(sectorPath);
}
r += dr;
}
if (currPolyPath.size() > 0) {
fullPath.append(currPolyPath);
}
}
if (fullPath.size() == 0)
if (transectPath.size() == 0)
return;
// remove short transects
for (int i = 0; i < fullPath.size(); i++) {
auto transect = fullPath[i];
for (int i = 0; i < transectPath.size(); i++) {
auto transect = transectPath[i];
double len = 0;
for (int j = 0; j < transect.size()-1; ++j) {
len += PlanimetryCalculus::distance(transect[j], transect[j+1]);
}
if (len < lmin)
fullPath.removeAt(i--);
transectPath.removeAt(i--);
}
if (fullPath.size() == 0)
if (transectPath.size() == 0)
return;
// optimize path to snake or zig-zag pattern
bool isSnakePattern = _isSnakePath.rawValue().toBool();
QList<QPointF> currentSection = fullPath.takeFirst();
QList<QPointF> currentSection = transectPath.takeFirst();
if ( currentSection.isEmpty() )
return;
QList<QList<QPointF>> optiPath; // optimized path
while( !fullPath.empty() ) {
while( !transectPath.empty() ) {
optiPath.append(currentSection);
QPointF endVertex = currentSection.last();
double minDist = std::numeric_limits<double>::infinity();
......@@ -530,8 +528,8 @@ void CircularSurveyComplexItem::_rebuildTransectsPhase1()
bool reversePath = false;
// iterate over all paths in fullPath and assign the one with the shortest distance to endVertex to currentSection
for (int i = 0; i < fullPath.size(); i++) {
auto iteratorPath = fullPath[i];
for (int i = 0; i < transectPath.size(); i++) {
auto iteratorPath = transectPath[i];
double dist = PlanimetryCalculus::distance(endVertex, iteratorPath.first());
if ( dist < minDist ) {
minDist = dist;
......@@ -545,7 +543,7 @@ void CircularSurveyComplexItem::_rebuildTransectsPhase1()
reversePath = true;
}
}
currentSection = fullPath.takeAt(index);
currentSection = transectPath.takeAt(index);
if (reversePath && isSnakePattern) {
PolygonCalculus::reversePath(currentSection);
}
......
......@@ -13,15 +13,18 @@ WimaPlaner::WimaPlaner(QObject *parent)
, _currentAreaIndex (-1)
, _container (nullptr)
, _joinedArea (this)
, _joinedAreaValid (false)
, _measurementArea (this)
, _serviceArea (this)
, _corridor (this)
, _circularSurvey (nullptr)
, _surveyRefChanging (false)
, _syncronizedWithController (false)
, _readyForSync (false)
{
connect(this, &WimaPlaner::currentPolygonIndexChanged, this, &WimaPlaner::recalcPolygonInteractivity);
connect(&_updateTimer, &QTimer::timeout, this, &WimaPlaner::updateTimerSlot);
connect(this, &WimaPlaner::joinedAreaValidChanged, this, &WimaPlaner::updateMission);
_updateTimer.setInterval(500); // 250 ms means: max update time 2*250 ms
_updateTimer.start();
}
......@@ -87,6 +90,11 @@ bool WimaPlaner::syncronizedWithController()
return _syncronizedWithController;
}
bool WimaPlaner::readyForSync()
{
return _readyForSync;
}
void WimaPlaner::removeArea(int index)
{
if(index >= 0 && index < _visualItems.count()){
......@@ -189,17 +197,14 @@ void WimaPlaner::removeAll()
bool WimaPlaner::updateMission()
{
QString errorString;
#define debug 0
setReadyForSync(false);
if ( !recalcJoinedArea(errorString)) {
qgcApp()->showMessage(tr(errorString.toLocal8Bit().data()));
if ( !_joinedAreaValid) {
if (_joinedAreaErrorString.size() > 0)
qgcApp()->showMessage(_joinedAreaErrorString);
return false;
}
#if debug
_visualItems.append(&_joinedArea);
#endif
// extract old survey data
QmlObjectListModel* missionItems = _missionController->visualItems();
......@@ -234,6 +239,7 @@ bool WimaPlaner::updateMission()
calcArrivalAndReturnPath();
setReadyForSync(true);
return true;
}
......@@ -326,9 +332,7 @@ bool WimaPlaner::loadFromFile(const QString &filename)
if (jsonArea.contains(WimaArea::areaTypeName) && jsonArea[WimaArea::areaTypeName].isString()) {
if ( jsonArea[WimaArea::areaTypeName] == WimaMeasurementArea::WimaMeasurementAreaName) {
print(_measurementArea);
bool success = _measurementArea.loadFromJson(jsonArea, errorString);
print(_measurementArea);
if ( !success ) {
qgcApp()->showMessage(errorMessage.arg(errorString));
......@@ -425,8 +429,8 @@ bool WimaPlaner::loadFromFile(const QString &filename)
_circularSurvey = missionItems->value<CircularSurveyComplexItem *>(i);
if (_circularSurvey != nullptr) {
if ( !recalcJoinedArea(errorString)) {
qgcApp()->showMessage(tr(errorString.toLocal8Bit().data()));
if ( !recalcJoinedArea()) {
qgcApp()->showMessage(_joinedAreaErrorString);
return false;
}
......@@ -449,6 +453,9 @@ bool WimaPlaner::loadFromFile(const QString &filename)
qWarning("WimaPlaner::loadFromFile(): not able to remove temporary file.");
}
_syncronizedWithController = false;
_readyForSync = false;
return true;
} else if ( fileInfo.suffix() == AppSettings::planFileExtension ){
......@@ -474,6 +481,8 @@ void WimaPlaner::recalcPolygonInteractivity(int index)
bool WimaPlaner::calcArrivalAndReturnPath()
{
setReadyForSync(false);
// extract old survey data
QmlObjectListModel *missionItems = _missionController->visualItems();
......@@ -540,8 +549,8 @@ bool WimaPlaner::calcArrivalAndReturnPath()
QGeoCoordinate end = _circularSurvey->coordinate();
#ifdef QT_DEBUG
if (!_visualItems.contains(&_joinedArea))
_visualItems.append(&_joinedArea);
//if (!_visualItems.contains(&_joinedArea))
//_visualItems.append(&_joinedArea);
#endif
QList<QGeoCoordinate> path;
......@@ -585,35 +594,39 @@ bool WimaPlaner::calcArrivalAndReturnPath()
if (restorePlanViewIndex)
_missionController->setCurrentPlanViewIndex(missionItems->indexOf(_circularSurvey), false);
setSyncronizedWithControllerFalse();
setReadyForSync(true);
return true;
}
bool WimaPlaner::recalcJoinedArea(QString &errorString)
bool WimaPlaner::recalcJoinedArea()
{
_joinedAreaErrorString.clear();
setJoinedAreaValid(false);
// check if area paths form simple polygons
if ( !_serviceArea.isSimplePolygon() ) {
errorString.append(tr("Service area is self intersecting and thus not a simple polygon. Only simple polygons allowed.\n"));
_joinedAreaErrorString.append(tr("Service area is self intersecting and thus not a simple polygon. Only simple polygons allowed.\n"));
return false;
}
if ( !_corridor.isSimplePolygon() && _corridor.count() > 0) {
errorString.append(tr("Corridor is self intersecting and thus not a simple polygon. Only simple polygons allowed.\n"));
_joinedAreaErrorString.append(tr("Corridor is self intersecting and thus not a simple polygon. Only simple polygons allowed.\n"));
return false;
}
if ( !_measurementArea.isSimplePolygon() ) {
errorString.append(tr("Measurement area is self intersecting and thus not a simple polygon. Only simple polygons allowed.\n"));
_joinedAreaErrorString.append(tr("Measurement area is self intersecting and thus not a simple polygon. Only simple polygons allowed.\n"));
return false;
}
_joinedArea.setPath(_serviceArea.path());
_joinedArea.join(_corridor);
if ( !_joinedArea.join(_measurementArea) ) {
errorString.append(tr("Not able to join areas. Service area and measurement"
_joinedAreaErrorString.append(tr("Not able to join areas. Service area and measurement"
" must have a overlapping section, or be connected through a corridor."));
return false; // this happens if all areas are pairwise disjoint
}
// join service area, op area and corridor
setJoinedAreaValid(true);
return true;
}
......@@ -710,6 +723,24 @@ void WimaPlaner::setSyncronizedWithController(bool sync)
}
}
void WimaPlaner::setReadyForSync(bool ready)
{
if( _readyForSync != ready) {
_readyForSync = ready;
emit readyForSyncChanged();
}
}
void WimaPlaner::setJoinedAreaValid(bool valid)
{
if (_joinedAreaValid != valid) {
_joinedAreaValid = valid;
emit joinedAreaValidChanged();
}
}
void WimaPlaner::updateTimerSlot()
{
// General operation of this function:
......@@ -728,10 +759,47 @@ void WimaPlaner::updateTimerSlot()
}
}
// measurementArea
if (_measurementAreaChanging) {
if (_measurementArea.path() == _lastMeasurementAreaPath) { // is it still changing?
recalcJoinedArea();
_measurementAreaChanging = false;
}
} else {
if (_measurementArea.path() != _lastMeasurementAreaPath) // does it started changing?
_measurementAreaChanging = true;
}
// corridor
if (_corridorChanging) {
if (_corridor.path() == _lastCorridorPath) { // is it still changing?
recalcJoinedArea();
_corridorChanging = false;
}
} else {
if (_corridor.path() != _lastCorridorPath) // does it started changing?
_corridorChanging = true;
}
// service area
if (_serviceAreaChanging) {
if (_serviceArea.path() == _lastServiceAreaPath) { // is it still changing?
recalcJoinedArea();
_serviceAreaChanging = false;
}
} else {
if (_serviceArea.path() != _lastServiceAreaPath) // does it started changing?
_serviceAreaChanging = true;
}
// update old values
if (_circularSurvey != nullptr)
_lastSurveyRefPoint = _circularSurvey->refPoint() ;
_lastSurveyRefPoint = _circularSurvey->refPoint();
_lastMeasurementAreaPath = _measurementArea.path();
_lastCorridorPath = _corridor.path();
_lastServiceAreaPath = _serviceArea.path();
}
void WimaPlaner::setSyncronizedWithControllerFalse()
......
......@@ -60,6 +60,7 @@ public:
Q_PROPERTY(QGeoCoordinate joinedAreaCenter READ joinedAreaCenter CONSTANT)
Q_PROPERTY(WimaDataContainer* dataContainer READ dataContainer WRITE setDataContainer NOTIFY dataContainerChanged)
Q_PROPERTY(bool syncronized READ syncronizedWithController NOTIFY syncronizedWithControllerChanged)
Q_PROPERTY(bool readyForSync READ readyForSync NOTIFY readyForSyncChanged)
// Property accessors
PlanMasterController* masterController (void) { return _masterController; }
......@@ -82,6 +83,7 @@ public:
// Property acessors
bool syncronizedWithController ();
bool readyForSync ();
// Member Methodes
Q_INVOKABLE bool addMeasurementArea();
......@@ -122,18 +124,24 @@ signals:
void currentFileChanged ();
void dataContainerChanged ();
void syncronizedWithControllerChanged (void);
void readyForSyncChanged (void);
private slots:
void recalcPolygonInteractivity (int index);
bool calcArrivalAndReturnPath (void);
bool recalcJoinedArea (QString &errorString);
bool recalcJoinedArea ();
// called by _updateTimer::timeout signal, updates different mission parts, if parameters (e.g. survey or areas) have changed
void updateTimerSlot ();
void setSyncronizedWithControllerFalse (void);
private:
signals:
void joinedAreaValidChanged();
private:
// Member Functions
WimaPlanData toPlanData();
void setSyncronizedWithController(bool sync);
void setSyncronizedWithController (bool sync);
void setReadyForSync (bool ready);
void setJoinedAreaValid (bool valid);
// Member Variables
PlanMasterController *_masterController;
......@@ -143,6 +151,8 @@ private:
WimaDataContainer *_container; // container for data exchange with WimaController
QmlObjectListModel _visualItems; // contains all visible areas
WimaJoinedArea _joinedArea; // joined area fromed by _measurementArea, _serviceArea, _corridor
QString _joinedAreaErrorString; // contains errors which appeared in recalcJoinedArea
bool _joinedAreaValid;
WimaMeasurementArea _measurementArea; // measurement area
WimaServiceArea _serviceArea; // area for supplying
WimaCorridor _corridor; // corridor connecting _measurementArea and _serviceArea
......@@ -151,9 +161,18 @@ private:
CircularSurveyComplexItem* _circularSurvey; // pointer to the CircularSurvey item in _missionController.visualItems()
// auto update
QTimer _updateTimer; // on this timers timeout different mission parts will be updated, if parameters (e.g. survey or areas) have changed
QGeoCoordinate _lastSurveyRefPoint;
bool _surveyRefChanging;
QGeoCoordinate _lastSurveyRefPoint; // stores the SurveyRefPoint of the previous timer call
bool _surveyRefChanging; // true if SurveyRefPoint is changing
QVariantList _lastMeasurementAreaPath; // stores the path of _measurementArea, at the time instance of the previous timer call
bool _measurementAreaChanging; // true if the path of the _measurementArea is changing
QVariantList _lastCorridorPath; // stores the path of _corridor, at the time instance of the previous timer call
bool _corridorChanging; // true if the path of the _corridor is changing
QVariantList _lastServiceAreaPath; // stores the path of _serviceArea, at the time instance of the previous timer call
bool _serviceAreaChanging; // true if the path of the _serviceArea is changing
// sync stuff
bool _syncronizedWithController; // true if planData is syncronized with wimaController
bool _readyForSync; // gets set by updateMission and calcArrivalAndReturnPath
};
......@@ -287,15 +287,19 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter
text: qsTr("Sync WiMA")
enabled: true
visible: true
onClicked: wimaPlaner.pushToContainer()
visible: wimaPlaner ? wimaPlaner.readyForSync : false
onClicked: {
if (wimaPlaner && wimaPlaner.readyForSync) {
wimaPlaner.pushToContainer()
}
}
PropertyAnimation on opacity {
easing.type: Easing.OutQuart
from: 0.5
to: 1
loops: Animation.Infinite
running: !wimaPlaner.syncronized
running: wimaPlaner ? !wimaPlaner.syncronized && wimaPlaner.readyForSync : false
alwaysRunToEnd: true
duration: 2000
}
......
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