14#include <QtGui/QPolygonF>
15#include <QtCore/QJsonArray>
16#include <QtCore/QLineF>
23 , _gridAngleFact (settingsGroup, _metaDataMap[gridAngleName])
24 , _flyAlternateTransectsFact(settingsGroup, _metaDataMap[flyAlternateTransectsName])
25 , _splitConcavePolygonsFact (settingsGroup, _metaDataMap[splitConcavePolygonsName])
26 , _entryPoint (EntryLocationTopLeft)
28 _editorQml =
"qrc:/qml/QGroundControl/PlanView/SurveyItemEditor.qml";
30 if (_controllerVehicle && !(_controllerVehicle->fixedWing() || _controllerVehicle->vtol())) {
32 _flyAlternateTransectsFact.setRawValue(
false);
36 if (_cameraCalc.isManualCamera() || !_cameraCalc.valueSetIsDistance()->rawValue().toBool()) {
37 _cameraCalc.distanceToSurface()->setRawValue(
SettingsManager::instance()->appSettings()->defaultMissionItemAltitude()->rawValue());
53 if (!kmlOrShpFile.isEmpty()) {
54 _surveyAreaPolygon.loadKMLOrSHPFile(kmlOrShpFile);
55 _surveyAreaPolygon.setDirty(
false);
62 QJsonObject saveObject;
64 _saveCommon(saveObject);
65 planItems.append(saveObject);
70 QJsonObject saveObject;
72 _saveCommon(saveObject);
76void SurveyComplexItem::_saveCommon(QJsonObject& saveObject)
83 saveObject[_jsonGridAngleKey] = _gridAngleFact.
rawValue().toDouble();
84 saveObject[_jsonFlyAlternateTransectsKey] = _flyAlternateTransectsFact.
rawValue().toBool();
85 saveObject[_jsonSplitConcavePolygonsKey] = _splitConcavePolygonsFact.
rawValue().toBool();
86 saveObject[_jsonEntryPointKey] = _entryPoint;
97 if (!_loadV4V5(presetObject, 0,
errorString, 5,
true )) {
105 Q_UNUSED(prevAltitude);
112 QList<JsonParsing::KeyValidateInfo> versionKeyInfoList = {
120 if (version < 2 || version > 5) {
121 errorString = tr(
"Survey items do not support version %1").arg(version);
125 if (version == 4 || version == 5) {
133 _recalcCameraShots();
137 QJsonObject v3ComplexObject = complexObject;
156bool SurveyComplexItem::_loadV4V5(
const QJsonObject& complexObject,
int sequenceNumber, QString&
errorString,
int version,
bool forPresets)
158 QList<JsonParsing::KeyValidateInfo> keyInfoList = {
161 { _jsonEntryPointKey, QJsonValue::Double,
true },
162 { _jsonGridAngleKey, QJsonValue::Double,
true },
163 { _jsonFlyAlternateTransectsKey, QJsonValue::Bool,
false },
168 keyInfoList.append(jSplitPolygon);
178 errorString = tr(
"%1 does not support loading this complex mission item type: %2:%3").arg(
qgcApp()->applicationName()).arg(itemType).arg(complexType);
198 _gridAngleFact.
setRawValue (complexObject[_jsonGridAngleKey].toDouble());
199 _flyAlternateTransectsFact.
setRawValue (complexObject[_jsonFlyAlternateTransectsKey].toBool(
false));
202 _splitConcavePolygonsFact.
setRawValue (complexObject[_jsonSplitConcavePolygonsKey].toBool(
true));
205 _entryPoint = complexObject[_jsonEntryPointKey].toInt();
212bool SurveyComplexItem::_loadV3(
const QJsonObject& complexObject,
int sequenceNumber, QString&
errorString)
214 QList<JsonParsing::KeyValidateInfo> mainKeyInfoList = {
218 { _jsonV3GridObjectKey, QJsonValue::Object,
true },
219 { _jsonV3CameraObjectKey, QJsonValue::Object,
false },
220 { _jsonV3CameraTriggerDistanceKey, QJsonValue::Double,
true },
221 { _jsonV3ManualGridKey, QJsonValue::Bool,
true },
222 { _jsonV3FixedValueIsAltitudeKey, QJsonValue::Bool,
true },
223 { _jsonV3HoverAndCaptureKey, QJsonValue::Bool,
false },
224 { _jsonV3Refly90DegreesKey, QJsonValue::Bool,
false },
225 { _jsonV3CameraTriggerInTurnaroundKey, QJsonValue::Bool,
false },
234 errorString = tr(
"%1 does not support loading this complex mission item type: %2:%3").arg(
qgcApp()->applicationName()).arg(itemType).arg(complexType);
249 bool manualGrid = complexObject[_jsonV3ManualGridKey].toBool(
true);
251 QList<JsonParsing::KeyValidateInfo> gridKeyInfoList = {
252 { _jsonV3GridAltitudeKey, QJsonValue::Double,
true },
253 { _jsonV3GridAltitudeRelativeKey, QJsonValue::Bool,
true },
254 { _jsonV3GridAngleKey, QJsonValue::Double,
true },
255 { _jsonV3GridSpacingKey, QJsonValue::Double,
true },
256 { _jsonEntryPointKey, QJsonValue::Double,
false },
257 { _jsonV3TurnaroundDistKey, QJsonValue::Double,
true },
259 QJsonObject gridObject = complexObject[_jsonV3GridObjectKey].toObject();
265 _gridAngleFact.
setRawValue (gridObject[_jsonV3GridAngleKey].toDouble());
268 if (gridObject.contains(_jsonEntryPointKey)) {
269 _entryPoint = gridObject[_jsonEntryPointKey].toInt();
281 if (!complexObject.contains(_jsonV3CameraObjectKey)) {
282 errorString = tr(
"%1 but %2 object is missing").arg(
"manualGrid = false").arg(
"camera");
287 QJsonObject cameraObject = complexObject[_jsonV3CameraObjectKey].toObject();
290 QString incorrectImageSideOverlap =
"imageSizeOverlap";
291 if (cameraObject.contains(incorrectImageSideOverlap)) {
292 cameraObject[_jsonV3SideOverlapKey] = cameraObject[incorrectImageSideOverlap];
293 cameraObject.remove(incorrectImageSideOverlap);
296 QList<JsonParsing::KeyValidateInfo> cameraKeyInfoList = {
297 { _jsonV3GroundResolutionKey, QJsonValue::Double,
true },
298 { _jsonV3FrontalOverlapKey, QJsonValue::Double,
true },
299 { _jsonV3SideOverlapKey, QJsonValue::Double,
true },
300 { _jsonV3CameraSensorWidthKey, QJsonValue::Double,
true },
301 { _jsonV3CameraSensorHeightKey, QJsonValue::Double,
true },
302 { _jsonV3CameraResolutionWidthKey, QJsonValue::Double,
true },
303 { _jsonV3CameraResolutionHeightKey, QJsonValue::Double,
true },
304 { _jsonV3CameraFocalLengthKey, QJsonValue::Double,
true },
305 { _jsonV3CameraNameKey, QJsonValue::String,
true },
306 { _jsonV3CameraOrientationLandscapeKey, QJsonValue::Bool,
true },
307 { _jsonV3CameraMinTriggerIntervalKey, QJsonValue::Double,
false },
346void SurveyComplexItem::_reverseTransectOrder(QList<QList<QGeoCoordinate>>& transects)
348 QList<QList<QGeoCoordinate>> rgReversedTransects;
349 for (
int i=transects.count() - 1; i>=0; i--) {
350 rgReversedTransects.append(transects[i]);
352 transects = rgReversedTransects;
356void SurveyComplexItem::_reverseInternalTransectPoints(QList<QList<QGeoCoordinate>>& transects)
358 for (
int i=0; i<transects.count(); i++) {
359 QList<QGeoCoordinate> rgReversedCoords;
360 QList<QGeoCoordinate>& rgOriginalCoords = transects[i];
361 for (
int j=rgOriginalCoords.count()-1; j>=0; j--) {
362 rgReversedCoords.append(rgOriginalCoords[j]);
364 transects[i] = rgReversedCoords;
372void SurveyComplexItem::_optimizeTransectsForShortestDistance(
const QGeoCoordinate& distanceCoord, QList<QList<QGeoCoordinate>>& transects)
374 double rgTransectDistance[4];
375 rgTransectDistance[0] = transects.first().first().distanceTo(distanceCoord);
376 rgTransectDistance[1] = transects.first().last().distanceTo(distanceCoord);
377 rgTransectDistance[2] = transects.last().first().distanceTo(distanceCoord);
378 rgTransectDistance[3] = transects.last().last().distanceTo(distanceCoord);
380 int shortestIndex = 0;
381 double shortestDistance = rgTransectDistance[0];
382 for (
int i=1; i<3; i++) {
383 if (rgTransectDistance[i] < shortestDistance) {
385 shortestDistance = rgTransectDistance[i];
389 if (shortestIndex > 1) {
391 _reverseTransectOrder(transects);
393 if (shortestIndex & 1) {
395 _reverseInternalTransectPoints(transects);
399qreal SurveyComplexItem::_ccw(QPointF pt1, QPointF pt2, QPointF pt3)
401 return (pt2.x()-pt1.x())*(pt3.y()-pt1.y()) - (pt2.y()-pt1.y())*(pt3.x()-pt1.x());
404qreal SurveyComplexItem::_dp(QPointF pt1, QPointF pt2)
406 return (pt2.x()-pt1.x())/qSqrt((pt2.x()-pt1.x())*(pt2.x()-pt1.x()) + (pt2.y()-pt1.y())*(pt2.y()-pt1.y()));
409void SurveyComplexItem::_swapPoints(QList<QPointF>& points,
int index1,
int index2)
411 QPointF temp = points[index1];
412 points[index1] = points[index2];
413 points[index2] = temp;
417bool SurveyComplexItem::_gridAngleIsNorthSouthTransects()
424void SurveyComplexItem::_adjustTransectsToEntryPointLocation(QList<QList<QGeoCoordinate>>& transects)
426 if (transects.count() == 0) {
430 bool reversePoints =
false;
431 bool reverseTransects =
false;
434 reversePoints =
true;
437 reverseTransects =
true;
441 qCDebug(SurveyComplexItemLog) <<
"_adjustTransectsToEntryPointLocation Reverse Points";
442 _reverseInternalTransectPoints(transects);
444 if (reverseTransects) {
445 qCDebug(SurveyComplexItemLog) <<
"_adjustTransectsToEntryPointLocation Reverse Transects";
446 _reverseTransectOrder(transects);
449 qCDebug(SurveyComplexItemLog) <<
"_adjustTransectsToEntryPointLocation Modified entry point:entryLocation" << transects.first().first() << _entryPoint;
452QPointF SurveyComplexItem::_rotatePoint(
const QPointF& point,
const QPointF& origin,
double angle)
455 double radians = (M_PI / 180.0) * -angle;
457 rotated.setX(((point.x() - origin.x()) * cos(radians)) - ((point.y() - origin.y()) * sin(radians)) + origin.x());
458 rotated.setY(((point.x() - origin.x()) * sin(radians)) + ((point.y() - origin.y()) * cos(radians)) + origin.y());
463void SurveyComplexItem::_intersectLinesWithRect(
const QList<QLineF>& lineList,
const QRectF& boundRect, QList<QLineF>& resultLines)
465 QLineF topLine (boundRect.topLeft(), boundRect.topRight());
466 QLineF bottomLine (boundRect.bottomLeft(), boundRect.bottomRight());
467 QLineF leftLine (boundRect.topLeft(), boundRect.bottomLeft());
468 QLineF rightLine (boundRect.topRight(), boundRect.bottomRight());
470 for (
int i=0; i<lineList.count(); i++) {
471 QPointF intersectPoint;
472 QLineF intersectLine;
473 const QLineF& line = lineList[i];
475 auto isLineBoundedIntersect = [&line, &intersectPoint](
const QLineF& linePosition) {
476 return line.intersects(linePosition, &intersectPoint) == QLineF::BoundedIntersection;
480 if (isLineBoundedIntersect(topLine)) {
481 intersectLine.setP1(intersectPoint);
484 if (isLineBoundedIntersect(rightLine)) {
485 if (foundCount == 0) {
486 intersectLine.setP1(intersectPoint);
488 if (foundCount != 1) {
489 qWarning() <<
"Found more than two intersecting points";
491 intersectLine.setP2(intersectPoint);
495 if (isLineBoundedIntersect(bottomLine)) {
496 if (foundCount == 0) {
497 intersectLine.setP1(intersectPoint);
499 if (foundCount != 1) {
500 qWarning() <<
"Found more than two intersecting points";
502 intersectLine.setP2(intersectPoint);
506 if (isLineBoundedIntersect(leftLine)) {
507 if (foundCount == 0) {
508 intersectLine.setP1(intersectPoint);
510 if (foundCount != 1) {
511 qWarning() <<
"Found more than two intersecting points";
513 intersectLine.setP2(intersectPoint);
518 if (foundCount == 2) {
519 resultLines += intersectLine;
524void SurveyComplexItem::_intersectLinesWithPolygon(
const QList<QLineF>& lineList,
const QPolygonF& polygon, QList<QLineF>& resultLines)
528 for (
int i=0; i<lineList.count(); i++) {
529 const QLineF& line = lineList[i];
530 QList<QPointF> intersections;
533 for (
int j=0; j<polygon.count()-1; j++) {
534 QPointF intersectPoint;
535 QLineF polygonLine = QLineF(polygon[j], polygon[j+1]);
537 auto intersect = line.intersects(polygonLine, &intersectPoint);
538 if (intersect == QLineF::BoundedIntersection) {
539 if (!intersections.contains(intersectPoint)) {
540 intersections.append(intersectPoint);
547 if (intersections.count() > 1) {
550 double currentMaxDistance = 0;
552 for (
int intersectionIndex=0; intersectionIndex<intersections.count(); intersectionIndex++) {
553 for (
int compareIndex=0; compareIndex<intersections.count(); compareIndex++) {
554 QLineF lineTest(intersections[intersectionIndex], intersections[compareIndex]);
555 double newMaxDistance = lineTest.length();
556 if (newMaxDistance > currentMaxDistance) {
557 firstPoint = intersections[intersectionIndex];
558 secondPoint = intersections[compareIndex];
559 currentMaxDistance = newMaxDistance;
564 resultLines += QLineF(firstPoint, secondPoint);
570void SurveyComplexItem::_adjustLineDirection(
const QList<QLineF>& lineList, QList<QLineF>& resultLines)
572 qreal firstAngle = 0;
573 for (
int i=0; i<lineList.count(); i++) {
574 const QLineF& line = lineList[i];
578 firstAngle = line.angle();
581 if (qAbs(line.angle() - firstAngle) > 1.0) {
582 adjustedLine.setP1(line.p2());
583 adjustedLine.setP2(line.p1());
588 resultLines += adjustedLine;
592double SurveyComplexItem::_clampGridAngle90(
double gridAngle)
603bool SurveyComplexItem::_nextTransectCoord(
const QList<QGeoCoordinate>& transectPoints,
int pointIndex, QGeoCoordinate& coord)
605 if (pointIndex > transectPoints.count()) {
606 qWarning() <<
"Bad grid generation";
610 coord = transectPoints[pointIndex];
614bool SurveyComplexItem::_hasTurnaround(
void)
const
619double SurveyComplexItem::_turnaroundDistance(
void)
const
624void SurveyComplexItem::_rebuildTransectsPhase1(
void)
626 _rebuildTransectsPhase1WorkerSinglePolygon(
false );
628 _rebuildTransectsPhase1WorkerSinglePolygon(
true );
632void SurveyComplexItem::_rebuildTransectsPhase1WorkerSinglePolygon(
bool refly)
651 QList<QPointF> polygonPoints;
653 qCDebug(SurveyComplexItemLog) <<
"_rebuildTransectsPhase1 Convert polygon to NED - _surveyAreaPolygon.count():tangentOrigin" <<
_surveyAreaPolygon.
count() << tangentOrigin;
663 polygonPoints += QPointF(x, y);
664 qCDebug(SurveyComplexItemLog) <<
"_rebuildTransectsPhase1 vertex:x:y" << vertex << polygonPoints.last().x() << polygonPoints.last().y();
674 qCDebug(SurveyComplexItemLog) <<
"_rebuildTransectsPhase1 Clamped grid angle" <<
gridAngle;
676 qCDebug(SurveyComplexItemLog) <<
"_rebuildTransectsPhase1 gridSpacing:gridAngle:refly" << gridSpacing <<
gridAngle << refly;
680 qCDebug(SurveyComplexItemLog) <<
"_rebuildTransectsPhase1 Polygon";
682 for (
int i=0; i<polygonPoints.count(); i++) {
683 qCDebug(SurveyComplexItemLog) <<
"Vertex" << polygonPoints[i];
684 polygon << polygonPoints[i];
686 polygon << polygonPoints[0];
687 QRectF boundingRect = polygon.boundingRect();
688 QPointF boundingCenter = boundingRect.center();
689 qCDebug(SurveyComplexItemLog) <<
"Bounding rect" << boundingRect.topLeft().x() << boundingRect.topLeft().y() << boundingRect.bottomRight().x() << boundingRect.bottomRight().y();
694 QList<QLineF> lineList;
701 const double diagonal = qSqrt(boundingRect.width() * boundingRect.width() + boundingRect.height() * boundingRect.height());
702 double maxWidth = diagonal * 1.5;
703 if (maxWidth <= 0.0) {
704 qCWarning(SurveyComplexItemLog) <<
"Degenerate polygon bounding rect (all vertices coincident or collinear), aborting transect rebuild";
708 if (gridSpacing <= 0) {
710 qCWarning(SurveyComplexItemLog) <<
"Grid spacing" << gridSpacing <<
"is invalid, falling back to single center transect";
711 const double halfW = maxWidth / 2.0;
713 _rotatePoint(QPointF(boundingCenter.x(), boundingCenter.y() - halfW), boundingCenter,
gridAngle),
714 _rotatePoint(QPointF(boundingCenter.x(), boundingCenter.y() + halfW), boundingCenter,
gridAngle));
719 qCWarning(SurveyComplexItemLog) <<
"Transect spacing" << gridSpacing <<
"raised to" << diagonal /
maxTransectCount <<
"to limit transect count to" <<
maxTransectCount;
723 double halfWidth = maxWidth / 2.0;
724 double transectX = boundingCenter.x() - halfWidth;
725 double transectXMax = transectX + maxWidth;
726 while (transectX < transectXMax) {
727 double transectYTop = boundingCenter.y() - halfWidth;
728 double transectYBottom = boundingCenter.y() + halfWidth;
730 lineList += QLineF(_rotatePoint(QPointF(transectX, transectYTop), boundingCenter,
gridAngle), _rotatePoint(QPointF(transectX, transectYBottom), boundingCenter,
gridAngle));
731 transectX += gridSpacing;
736 QList<QLineF> intersectLines;
738 _intersectLinesWithPolygon(lineList, polygon, intersectLines);
741 intersectLines = lineList;
747 if (intersectLines.count() < 2) {
749 QLineF firstLine = lineList.first();
750 QPointF lineCenter = firstLine.pointAt(0.5);
751 QPointF centerOffset = boundingCenter - lineCenter;
752 firstLine.translate(centerOffset);
754 lineList.append(firstLine);
755 intersectLines = lineList;
756 _intersectLinesWithPolygon(lineList, polygon, intersectLines);
761 QList<QLineF> resultLines;
762 _adjustLineDirection(intersectLines, resultLines);
765 QList<QList<QGeoCoordinate>> transects;
766 for (
const QLineF& line : resultLines) {
767 QGeoCoordinate coord;
768 QList<QGeoCoordinate> transect;
771 transect.append(coord);
773 transect.append(coord);
775 transects.append(transect);
778 _adjustTransectsToEntryPointLocation(transects);
781 _optimizeTransectsForShortestDistance(
_transects.last().last().coord, transects);
784 if (_flyAlternateTransectsFact.
rawValue().toBool()) {
785 QList<QList<QGeoCoordinate>> alternatingTransects;
786 for (
int i=0; i<transects.count(); i++) {
788 alternatingTransects.append(transects[i]);
791 for (
int i=transects.count()-1; i>0; i--) {
793 alternatingTransects.append(transects[i]);
796 transects = alternatingTransects;
800 bool reverseVertices =
false;
801 for (
int i=0; i<transects.count(); i++) {
803 QList<QGeoCoordinate> transectVertices = transects[i];
804 if (reverseVertices) {
805 reverseVertices =
false;
806 QList<QGeoCoordinate> reversedVertices;
807 for (
int j=transectVertices.count()-1; j>=0; j--) {
808 reversedVertices.append(transectVertices[j]);
810 transectVertices = reversedVertices;
812 reverseVertices =
true;
814 transects[i] = transectVertices;
818 for (
const QList<QGeoCoordinate>& transect : transects) {
819 QGeoCoordinate coord;
820 QList<TransectStyleComplexItem::CoordInfo_t> coordInfoTransect;
824 coordInfoTransect.append(coordInfo);
826 coordInfoTransect.append(coordInfo);
830 double transectLength = transect[0].distanceTo(transect[1]);
831 double transectAzimuth = transect[0].azimuthTo(transect[1]);
833 int cInnerHoverPoints =
static_cast<int>(floor(transectLength /
triggerDistance()));
834 qCDebug(SurveyComplexItemLog) <<
"cInnerHoverPoints" << cInnerHoverPoints;
835 for (
int i=0; i<cInnerHoverPoints; i++) {
836 QGeoCoordinate hoverCoord = transect[0].atDistanceAndAzimuth(
triggerDistance() * (i + 1), transectAzimuth);
838 coordInfoTransect.insert(1 + i, hoverCoordInfo);
844 if (_hasTurnaround()) {
845 QGeoCoordinate turnaroundCoord;
848 double azimuth = transect[0].azimuthTo(transect[1]);
850 turnaroundCoord.setAltitude(qQNaN());
852 coordInfoTransect.prepend(turnaroundCoordInfo);
854 azimuth = transect.last().azimuthTo(transect[transect.count() - 2]);
856 turnaroundCoord.setAltitude(qQNaN());
858 coordInfoTransect.append(coordInfo);
866void SurveyComplexItem::_recalcCameraShots(
void)
870 if (triggerDistance == 0) {
883 _cameraShots += missionItem->command() == MAV_CMD_IMAGE_START_CAPTURE ? 1 : 0;
886 bool waitingForTriggerStop =
false;
887 QGeoCoordinate distanceStartCoord;
888 QGeoCoordinate distanceEndCoord;
890 if (missionItem->command() == MAV_CMD_NAV_WAYPOINT) {
891 if (waitingForTriggerStop) {
892 distanceEndCoord = QGeoCoordinate(missionItem->param5(), missionItem->param6());
894 distanceStartCoord = QGeoCoordinate(missionItem->param5(), missionItem->param6());
896 }
else if (missionItem->command() == MAV_CMD_DO_SET_CAM_TRIGG_DIST) {
897 if (missionItem->param1() > 0) {
899 waitingForTriggerStop =
true;
902 waitingForTriggerStop =
false;
904 distanceStartCoord = QGeoCoordinate();
905 distanceEndCoord = QGeoCoordinate();
913 for (
const QList<TransectStyleComplexItem::CoordInfo_t>& transect:
_transects) {
914 QGeoCoordinate firstCameraCoord, lastCameraCoord;
916 firstCameraCoord = transect[1].coord;
917 lastCameraCoord = transect[transect.count() - 2].coord;
919 firstCameraCoord = transect.first().coord;
920 lastCameraCoord = transect.last().coord;
956 double hoverTime = 0;
959 for (
const QList<TransectStyleComplexItem::CoordInfo_t>& transect:
_transects) {
967void SurveyComplexItem::_updateWizardMode(
void)
Geographic coordinate conversion utilities using GeographicLib.
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void _setCameraNameFromV3TransectLoad(const QString &cameraName)
void setDistanceMode(QGroundControlQmlGlobal::AltitudeFrame altFrame)
Fact * imageDensity(void)
Fact * adjustedFootprintSide(void)
Fact * distanceToSurface(void)
Fact * adjustedFootprintFrontal(void)
void setCameraBrand(const QString &cameraBrand)
Fact * valueSetIsDistance(void)
Fact * frontalOverlap(void)
static QString canonicalManualCameraName(void)
SettingsFact * minTriggerInterval(void)
SettingsFact * imageHeight(void)
SettingsFact * sensorWidth(void)
SettingsFact * fixedOrientation(void)
SettingsFact * focalLength(void)
SettingsFact * sensorHeight(void)
SettingsFact * imageWidth(void)
SettingsFact * landscape(void)
void _savePresetJson(const QString &name, QJsonObject &presetObject)
static constexpr const char * jsonComplexItemTypeKey
This mission item attribute specifies the type of the complex item.
QJsonObject _loadPresetJson(const QString &name)
void setRawValue(const QVariant &value)
QVariant rawValue() const
Value after translation.
void valueChanged(const QVariant &value)
This signal is only meant for use by the QT property system. It should not be connected to by client ...
Master controller for mission, fence, rally.
QmlObjectListModel & pathModel(void)
bool traceMode(void) const
QGeoCoordinate center(void) const
void traceModeChanged(bool traceMode)
void saveToJson(QJsonObject &json)
static constexpr const char * jsonPolygonKey
Q_INVOKABLE void clear(void)
bool isValidChanged(void)
bool loadFromJson(const QJsonObject &json, bool required, QString &errorString)
This is a QGeoCoordinate within a QObject such that it can be used on a QmlObjectListModel.
Provides access to group of settings.
static SettingsManager * instance()
double timeBetweenShots(void) final
static constexpr const char * jsonComplexItemTypeValue
Q_INVOKABLE void rotateEntryPoint(void)
void refly90DegreesChanged(bool refly90Degrees)
ReadyForSaveState readyForSaveState(void) const final
double additionalTimeDelay(void) const final
bool load(const QJsonObject &complexObject, int sequenceNumber, QString &errorString) final
void applyPreviousAltitudeFrame(QGroundControlQmlGlobal::AltitudeFrame prevAltFrame, double prevAltitude) final
static constexpr const char * jsonV3ComplexItemTypeValue
void loadPreset(const QString &name)
void savePreset(const QString &name)
@ EntryLocationBottomRight
@ EntryLocationBottomLeft
void save(QJsonArray &planItems) final
QObject * _loadedMissionItemsParent
Parent for all items in _loadedMissionItems for simpler delete.
QList< QList< CoordInfo_t > > _transects
SettingsFact _refly90DegreesFact
bool hoverAndCaptureEnabled(void) const
QList< MissionItem * > _loadedMissionItems
Mission items loaded from plan file.
void _recalcComplexDistance(void)
void setSequenceNumber(int sequenceNumber) final
QGeoCoordinate coordinate(void) const final
int sequenceNumber(void) const final
bool triggerCamera(void) const
static constexpr int maxTransectCount
Maximum number of transects allowed; spacing is raised to enforce this limit.
ReadyForSaveState readyForSaveState(void) const override
double _turnAroundDistance(void) const
bool _load(const QJsonObject &complexObject, bool forPresets, QString &errorString)
static constexpr int _hoverAndCaptureDelaySeconds
QGCMapPolygon _surveyAreaPolygon
Fact * turnAroundDistance(void)
SettingsFact _hoverAndCaptureFact
SettingsFact _cameraTriggerInTurnAroundFact
double triggerDistance(void) const
void cameraShotsChanged(void)
void _save(QJsonObject &saveObject)
void _rebuildTransects(void)
SettingsFact _turnAroundDistanceFact
void setDirty(bool dirty) final
@ CoordTypeTurnaround
Turnaround extension waypoint.
@ CoordTypeSurveyExit
Waypoint at exit edge of survey polygon.
@ CoordTypeInteriorHoverTrigger
Interior waypoint for hover and capture trigger.
@ CoordTypeSurveyEntry
Waypoint at entry edge of survey polygon.
static constexpr const char * jsonTypeComplexItemValue
Item type is Complex Item.
void setWizardMode(bool wizardMode)
static constexpr const char * jsonTypeKey
Json file attribute which specifies the item type.
double azimuth(void) const
bool validateKeys(const QJsonObject &jsonObject, const QList< KeyValidateInfo > &keyInfo, QString &errorString)
Validates that all required keys are present and that listed keys have the expected type.
constexpr const char * jsonVersionKey
void convertGeoToNed(const QGeoCoordinate &coord, const QGeoCoordinate &origin, double &x, double &y, double &z)
void convertNedToGeo(double x, double y, double z, const QGeoCoordinate &origin, QGeoCoordinate &coord)
void showAppMessage(const QString &message, const QString &title)
Modal application message. Queued if the UI isn't ready yet.