diff --git a/WimaDok/main.aux b/WimaDok/main.aux index ff1e60033538954a61cabc269d6094f75c01b623..ceafc3913937383ff80aa0e5b9ce5efeea3d0307 100644 --- a/WimaDok/main.aux +++ b/WimaDok/main.aux @@ -2,7 +2,7 @@ \@writefile{toc}{\contentsline {section}{\numberline {1}Introduction}{1}} \@writefile{toc}{\contentsline {section}{\numberline {2}Documentation}{1}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.1}Structure of QGroundControl with WiMA-Extension}{1}} +\@writefile{toc}{\contentsline {subsection}{\numberline {2.2}WiMA Main Window}{1}} \@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces Detail view of the QGC window, which appears after start-up. Marked in red is the button for switching to the plan view window, green indicates the flight view button (current window) and marked in magenta is the button for switching to the WiMA main window.}}{2}} \newlabel{fig:QGCMainButtonExplain}{{1}{2}} -\@writefile{toc}{\contentsline {section}{\numberline {3}WiMA Main Window}{2}} -\@writefile{toc}{\contentsline {section}{\numberline {4}ArduPilot Simulator}{2}} +\@writefile{toc}{\contentsline {subsection}{\numberline {2.3}ArduPilot Simulator}{2}} diff --git a/WimaDok/main.pdf b/WimaDok/main.pdf index 99e11f9cc71da5fc13d4c663e319c9054ce41cf3..c551ac0572e9213fd50afc4ad267b829846bc85e 100644 Binary files a/WimaDok/main.pdf and b/WimaDok/main.pdf differ diff --git a/WimaDok/main.synctex.gz b/WimaDok/main.synctex.gz index 3396f1902d99a8e43cb3cf2411844b098e16d330..087e64a8919c3a124c6c41f2ef9923797d43ccd9 100644 Binary files a/WimaDok/main.synctex.gz and b/WimaDok/main.synctex.gz differ diff --git a/WimaDok/main.tex b/WimaDok/main.tex index 2e299765e3d819bd0ec8f92f3cbd8fe8490037bd..f9d742092a27bf249097240b465999332536590f 100644 --- a/WimaDok/main.tex +++ b/WimaDok/main.tex @@ -21,9 +21,11 @@ \maketitle \section{Introduction} WiMA is a abbreviation for \textbf{Wi}reless \textbf{M}easurement \textbf{A}pplication. -Dieses Dokument soll einerseits die Funktionen der WiMA-Erweiterung dokumentieren und andererseits den Leser dazu anregen Fehler im Programm zu finden. Das Dokument ist in zwei abschnitte unterteilt. Die eigentliche Dokumentation und Vorschläge welche Funktionen getestet werden sollen. Da die WiMA-Erweiterung noch weiterentwickelt wird, können die Funktionen und das Aussehen des Programms von der in dieser Dokumentation dargestellten Inhalten abweichen. -Der Ordner deploy enthält eine unter Linux ausführbare Datei des Programms, mit dem nahmen "QGroundControl.AppImage". +This document was created to explain the functionality of the WiMA-Extension at one hand and to encourage the reader to find bugs inside the program. Hence the document is split in two parts. The first part contains instructions on how to use WiMA and the second part gives some suggestions for testing. As the extension is still beeing developed the contents demonstrated inside this document may differ from those ones in the program. + +The folder "deploy" in the QGroundControl root directory (can be cloned from Gitlab) contains a AppImage of the program. QGroundControl can be launched by double-clicking the AppImage. Currently only a Linux version is available. + \section{Documentation} \subsection{Structure of QGroundControl with WiMA-Extension} @@ -43,8 +45,9 @@ The \textbf{WiMA main window} is used to automatically generate flight paths on \end{figure} -\section{WiMA Main Window} -\section{ArduPilot Simulator} +\subsection{WiMA Main Window} +By clicking the wave symbol (see fig. \ref{fig:QGCMainButtonExplain}; magenta square) the WiMA main window appears. After entering, at the left edge the WiMA toolstrip will appear +\subsection{ArduPilot Simulator} For tasks like debugging, program verification or flight plan testing a simulated vehicle can be very useful. It can save time, money and prevent you from any excessive sunburns, if you forgot that you are actually outside, starring on your screen, exposed to the hot summer sun. For this task the ArduPilot simulator can be used. It simulates a vehicle runnig the ArduPilot flight stack (firmware) on your local machine. Data is beeing published by the simulator via UDP and should ideally connect to QGroundControl without any further tweaks. diff --git a/WimaDok/pics/WiMAToolstrip.png b/WimaDok/pics/WiMAToolstrip.png new file mode 100644 index 0000000000000000000000000000000000000000..84fa63996c9d67f7bf4f5ba21c7310fae7522cb3 Binary files /dev/null and b/WimaDok/pics/WiMAToolstrip.png differ diff --git a/deploy/QGroundControl.AppImage b/deploy/QGroundControl.AppImage index 89d3312616da9e98c47a933463a331a351ee063b..1aa033a520f81a005f1d7461aeaa48cb8fb0de7e 100755 Binary files a/deploy/QGroundControl.AppImage and b/deploy/QGroundControl.AppImage differ diff --git a/deploy/profile/QGroundControl.AppImage b/deploy/profile/QGroundControl.AppImage new file mode 100755 index 0000000000000000000000000000000000000000..1aa033a520f81a005f1d7461aeaa48cb8fb0de7e Binary files /dev/null and b/deploy/profile/QGroundControl.AppImage differ diff --git a/deploy/profile/callgrind.out.24464 b/deploy/profile/callgrind.out.24464 new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/deploy/profile/callgrind.out.24465 b/deploy/profile/callgrind.out.24465 new file mode 100644 index 0000000000000000000000000000000000000000..dd57401fc199254fcaae51aae365c9740c03c2d8 --- /dev/null +++ b/deploy/profile/callgrind.out.24465 @@ -0,0 +1,21 @@ +# callgrind format +version: 1 +creator: callgrind-3.13.0 +pid: 24465 +cmd: ./QGroundControl.AppImage +part: 1 + + +desc: I1 cache: +desc: D1 cache: +desc: LL cache: + +desc: Timerange: Basic block 0 - 206412 +desc: Trigger: Program termination + +positions: line +events: Ir +summary: 0 + + +totals: 0 diff --git a/deploy/profile/callgrind.out.24468 b/deploy/profile/callgrind.out.24468 new file mode 100644 index 0000000000000000000000000000000000000000..fe15865a40ad4c81a4887be3686b1697ea86e293 --- /dev/null +++ b/deploy/profile/callgrind.out.24468 @@ -0,0 +1,21 @@ +# callgrind format +version: 1 +creator: callgrind-3.13.0 +pid: 24468 +cmd: ./QGroundControl.AppImage +part: 1 + + +desc: I1 cache: +desc: D1 cache: +desc: LL cache: + +desc: Timerange: Basic block 0 - 366088887 +desc: Trigger: Program termination + +positions: line +events: Ir +summary: 0 + + +totals: 0 diff --git a/src/MissionManager/TransectStyleComplexItem.cc b/src/MissionManager/TransectStyleComplexItem.cc index 156818403f047e31ea17807fb6b567ca7f8877f7..15ad126fdf18462e0f4ea0a89885fc10b6c716a1 100644 --- a/src/MissionManager/TransectStyleComplexItem.cc +++ b/src/MissionManager/TransectStyleComplexItem.cc @@ -16,6 +16,7 @@ #include "SettingsManager.h" #include "AppSettings.h" #include "QGCQGeoCoordinate.h" +#include #include @@ -350,7 +351,10 @@ void TransectStyleComplexItem::_rebuildTransects(void) return; } + CALLGRIND_START_INSTRUMENTATION; + CALLGRIND_TOGGLE_COLLECT; _rebuildTransectsPhase1(); + CALLGRIND_TOGGLE_COLLECT; if (_followTerrain) { // Query the terrain data. Once available terrain heights will be calculated diff --git a/src/PlanView/CircularSurveyItemEditor.qml b/src/PlanView/CircularSurveyItemEditor.qml index 118674d9290a19e2017c67198882277f64cfa1a3..4e2efaeb5be28ba49460b9f03fcceed1914bd6b5 100644 --- a/src/PlanView/CircularSurveyItemEditor.qml +++ b/src/PlanView/CircularSurveyItemEditor.qml @@ -57,20 +57,19 @@ Rectangle { anchors.right: parent.right spacing: _margin - SectionHeader { - id: transectsHeader - text: qsTr("Transects") + id: generalHeader + text: qsTr("General") } + GridLayout { anchors.left: parent.left anchors.right: parent.right columnSpacing: _margin rowSpacing: _margin columns: 2 - visible: transectsHeader.checked - + visible: generalHeader.checked QGCLabel { text: qsTr("Altitude") } FactTextField { @@ -78,6 +77,23 @@ Rectangle { Layout.fillWidth: true //onUpdated: rSlider.value = missionItem.deltaR.value } + } + + SectionHeader { + id: transectsHeader + text: qsTr("Transects") + } + + GridLayout { + anchors.left: parent.left + anchors.right: parent.right + columnSpacing: _margin + rowSpacing: _margin + columns: 2 + visible: transectsHeader.checked + + + QGCLabel { text: qsTr("Delta R") } FactTextField { @@ -107,6 +123,13 @@ Rectangle { //onUpdated: angleSlider.value = missionItem.deltaAlpha.value } + QGCLabel { text: qsTr("Min. Length") } + FactTextField { + fact: missionItem.transectMinLength + Layout.fillWidth: true + //onUpdated: angleSlider.value = missionItem.deltaAlpha.value + } + /*QGCSlider { id: angleSlider minimumValue: 0.3 diff --git a/src/Wima/CircularSurvey.SettingsGroup.json b/src/Wima/CircularSurvey.SettingsGroup.json index 76ec08b4fe4b91e6abfa0d46e91b0f718a34c65e..e70d3b0e70957ec2e9582b3eec6867ea081e26b2 100644 --- a/src/Wima/CircularSurvey.SettingsGroup.json +++ b/src/Wima/CircularSurvey.SettingsGroup.json @@ -17,5 +17,14 @@ "max": 90, "decimalPlaces": 1, "defaultValue": 5.0 +}, +{ + "name": "TransectMinLength", + "shortDescription": "The minimal length transects must have to be accepted.", + "type": "double", + "units": "m", + "min": 0.3, + "decimalPlaces": 1, + "defaultValue": 5.0 } ] diff --git a/src/Wima/CircularSurveyComplexItem.cc b/src/Wima/CircularSurveyComplexItem.cc index ec6d4a1b29f1f33dc9923453c8bcf1e871938245..2af3f9b671faac577e175e8243c28b14ae80b646 100644 --- a/src/Wima/CircularSurveyComplexItem.cc +++ b/src/Wima/CircularSurveyComplexItem.cc @@ -2,13 +2,17 @@ #include "JsonHelper.h" #include "QGCApplication.h" + const char* CircularSurveyComplexItem::settingsGroup = "CircularSurvey"; const char* CircularSurveyComplexItem::deltaRName = "DeltaR"; const char* CircularSurveyComplexItem::deltaAlphaName = "DeltaAlpha"; +const char* CircularSurveyComplexItem::transectMinLengthName = "TransectMinLength"; + const char* CircularSurveyComplexItem::jsonComplexItemTypeValue = "circularSurvey"; const char* CircularSurveyComplexItem::jsonDeltaRKey = "deltaR"; const char* CircularSurveyComplexItem::jsonDeltaAlphaKey = "deltaAlpha"; +const char* CircularSurveyComplexItem::jsonTransectMinLengthKey = "transectMinLength"; const char* CircularSurveyComplexItem::jsonReferencePointLatKey = "referencePointLat"; const char* CircularSurveyComplexItem::jsonReferencePointLongKey = "referencePointLong"; const char* CircularSurveyComplexItem::jsonReferencePointAltKey = "referencePointAlt"; @@ -19,15 +23,15 @@ CircularSurveyComplexItem::CircularSurveyComplexItem(Vehicle *vehicle, bool flyV , _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/CircularSurvey.SettingsGroup.json"), this)) , _deltaR (settingsGroup, _metaDataMap[deltaRName]) , _deltaAlpha (settingsGroup, _metaDataMap[deltaAlphaName]) + , _transectMinLength (settingsGroup, _metaDataMap[transectMinLengthName]) , _autoGenerated (false) { _editorQml = "qrc:/qml/CircularSurveyItemEditor.qml"; - connect(&_deltaR, &Fact::valueChanged, this, &CircularSurveyComplexItem::_setDirty); - connect(&_deltaAlpha, &Fact::valueChanged, this, &CircularSurveyComplexItem::_setDirty); - connect(this, &CircularSurveyComplexItem::refPointChanged, this, &CircularSurveyComplexItem::_setDirty); + connect(&_deltaR, &Fact::valueChanged, this, &CircularSurveyComplexItem::_rebuildTransects); + connect(&_deltaAlpha, &Fact::valueChanged, this, &CircularSurveyComplexItem::_rebuildTransects); + connect(&_transectMinLength, &Fact::valueChanged, this, &CircularSurveyComplexItem::_rebuildTransects); + connect(this, &CircularSurveyComplexItem::refPointChanged, this, &CircularSurveyComplexItem::_rebuildTransects); - connect(&_updateTimer, &QTimer::timeout, this, &CircularSurveyComplexItem::_updateItem); - _updateTimer.start(100); } void CircularSurveyComplexItem::setRefPoint(const QGeoCoordinate &refPt) @@ -90,8 +94,9 @@ bool CircularSurveyComplexItem::load(const QJsonObject &complexObject, int seque { ComplexMissionItem::jsonComplexItemTypeKey, QJsonValue::String, true }, { jsonDeltaRKey, QJsonValue::Double, true }, { jsonDeltaAlphaKey, QJsonValue::Double, true }, + { jsonTransectMinLengthKey, QJsonValue::Double, true }, { jsonReferencePointLatKey, QJsonValue::Double, true }, - { jsonReferencePointLongKey, QJsonValue::Double, true }, + { jsonReferencePointLongKey, QJsonValue::Double, true }, { jsonReferencePointAltKey, QJsonValue::Double, true }, }; @@ -123,6 +128,7 @@ bool CircularSurveyComplexItem::load(const QJsonObject &complexObject, int seque _deltaR.setRawValue (complexObject[jsonDeltaRKey].toDouble()); _deltaAlpha.setRawValue (complexObject[jsonDeltaAlphaKey].toDouble()); + _transectMinLength.setRawValue (complexObject[jsonTransectMinLengthKey].toDouble()); _referencePoint.setLongitude (complexObject[jsonReferencePointLongKey].toDouble()); _referencePoint.setLatitude (complexObject[jsonReferencePointLatKey].toDouble()); _referencePoint.setAltitude (complexObject[jsonReferencePointAltKey].toDouble()); @@ -151,6 +157,7 @@ void CircularSurveyComplexItem::save(QJsonArray &planItems) saveObject[jsonDeltaRKey] = _deltaR.rawValue().toDouble(); saveObject[jsonDeltaAlphaKey] = _deltaAlpha.rawValue().toDouble(); + saveObject[jsonTransectMinLengthKey] = _transectMinLength.rawValue().toDouble(); saveObject[jsonReferencePointLongKey] = _referencePoint.longitude(); saveObject[jsonReferencePointLatKey] = _referencePoint.latitude(); saveObject[jsonReferencePointAltKey] = _referencePoint.altitude(); @@ -332,13 +339,25 @@ void CircularSurveyComplexItem::_rebuildTransectsPhase1() using namespace PlanimetryCalculus; - - if ( _surveyAreaPolygon.count() < 3) + // check if input is valid + if ( _surveyAreaPolygon.count() < 3) { + _transects.clear(); return; + } _transects.clear(); QPolygonF surveyPolygon = toQPolygonF(toCartesian2D(_surveyAreaPolygon.coordinateList(), _referencePoint)); + // some more checks + if (!PolygonCalculus::isSimplePolygon(surveyPolygon)) { + _transects.clear(); + return; + } + + // even more checks + if (!PolygonCalculus::hasClockwiseWinding(surveyPolygon)) + PolygonCalculus::reversePath(surveyPolygon); + QVector distances; for (const QPointF &p : surveyPolygon) distances.append(norm(p)); @@ -351,10 +370,10 @@ void CircularSurveyComplexItem::_rebuildTransectsPhase1() return; + // fetch input data double dalpha = _deltaAlpha.rawValue().toDouble()/180.0*M_PI; // radiants double dr = _deltaR.rawValue().toDouble(); // meter -// double dalpha = 1.0/180.0*M_PI; // radiants -// double dr = 10.0; // meter + double lmin = _transectMinLength.rawValue().toDouble(); double r_min = dr; // meter double r_max = (*std::max_element(distances.begin(), distances.end())); // meter @@ -380,13 +399,11 @@ void CircularSurveyComplexItem::_rebuildTransectsPhase1() originInside = false; } -// qWarning("r_min, r_max:"); -// qWarning() << r_min; -// qWarning() << r_max; QList convexPolygons; decomposeToConvex(surveyPolygon, convexPolygons); + // generate transects QList> fullPath; for (int i = 0; i < convexPolygons.size(); i++) { const QPolygonF &polygon = convexPolygons[i]; @@ -471,10 +488,25 @@ void CircularSurveyComplexItem::_rebuildTransectsPhase1() fullPath.append(currPolyPath); } } + if (fullPath.size() == 0) + return; - // optimize path to lawn pattern + // remove short transects + for (int i = 0; i < fullPath.size(); i++) { + auto transect = fullPath[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--); + } if (fullPath.size() == 0) return; + + + // optimize path to lawn pattern QList currentSection = fullPath.takeFirst(); if ( currentSection.isEmpty() ) return; @@ -493,6 +525,7 @@ void CircularSurveyComplexItem::_rebuildTransectsPhase1() if ( dist < minDist ) { minDist = dist; index = i; + reversePath = false; } dist = PlanimetryCalculus::distance(endVertex, iteratorPath.last()); if (dist < minDist) { @@ -539,16 +572,15 @@ void CircularSurveyComplexItem::_recalcCameraShots() _cameraShots = 0; } -void CircularSurveyComplexItem::_updateItem() -{ - if (_dirty) { - _rebuildTransects(); - qDebug() << "CircularSurveyComplexItem::_updateItem()"; - setDirty(false); - } +Fact *CircularSurveyComplexItem::transectMinLength() +{ + return &_transectMinLength; } + + + /*! \class CircularSurveyComplexItem \inmodule Wima @@ -560,3 +592,5 @@ void CircularSurveyComplexItem::_updateItem() \sa WimaArea */ + + diff --git a/src/Wima/CircularSurveyComplexItem.h b/src/Wima/CircularSurveyComplexItem.h index 3fc137c576bf52bdfd4a30bada04c9d41beb11bd..593ce63b636ed199d5849e19fcef3c55c660999e 100644 --- a/src/Wima/CircularSurveyComplexItem.h +++ b/src/Wima/CircularSurveyComplexItem.h @@ -21,6 +21,7 @@ public: Q_PROPERTY(QGeoCoordinate refPoint READ refPoint WRITE setRefPoint NOTIFY refPointChanged) Q_PROPERTY(Fact* deltaR READ deltaR CONSTANT) Q_PROPERTY(Fact* deltaAlpha READ deltaAlpha CONSTANT) + Q_PROPERTY(Fact* transectMinLength READ transectMinLength CONSTANT) Q_PROPERTY(bool autoGenerated READ autoGenerated NOTIFY autoGeneratedChanged) // Property setters @@ -32,6 +33,7 @@ public: QGeoCoordinate refPoint() const; Fact *deltaR(); Fact *deltaAlpha(); + Fact *transectMinLength(); // Is true if survey was automatically generated, prevents initialisation from gui. bool autoGenerated(); @@ -56,10 +58,12 @@ public: static const char* settingsGroup; static const char* deltaRName; static const char* deltaAlphaName; + static const char* transectMinLengthName; static const char* jsonComplexItemTypeValue; static const char* jsonDeltaRKey; static const char* jsonDeltaAlphaKey; + static const char* jsonTransectMinLengthKey; static const char* jsonReferencePointLongKey; static const char* jsonReferencePointLatKey; static const char* jsonReferencePointAltKey; @@ -73,7 +77,6 @@ private slots: void _rebuildTransectsPhase1 (void) final; void _recalcComplexDistance (void) final; void _recalcCameraShots (void) final; - void _updateItem (void); signals: @@ -89,6 +92,7 @@ private: SettingsFact _deltaR; SettingsFact _deltaAlpha; + SettingsFact _transectMinLength; QTimer _updateTimer;