Unverified Commit 65b75a05 authored by Don Gagne's avatar Don Gagne Committed by GitHub

Merge pull request #6105 from DonLakeFlyer/TransectStyleComplexItem

New TransectStyleComplexItem base class
parents 9e5b18c5 e3919343
......@@ -540,6 +540,7 @@ HEADERS += \
src/MissionManager/SpeedSection.h \
src/MissionManager/StructureScanComplexItem.h \
src/MissionManager/SurveyMissionItem.h \
src/MissionManager/TransectStyleComplexItem.h \
src/MissionManager/VisualMissionItem.h \
src/PositionManager/PositionManager.h \
src/PositionManager/SimulatedPosition.h \
......@@ -733,6 +734,7 @@ SOURCES += \
src/MissionManager/SpeedSection.cc \
src/MissionManager/StructureScanComplexItem.cc \
src/MissionManager/SurveyMissionItem.cc \
src/MissionManager/TransectStyleComplexItem.cc \
src/MissionManager/VisualMissionItem.cc \
src/PositionManager/PositionManager.cpp \
src/PositionManager/SimulatedPosition.cc \
......
......@@ -204,6 +204,7 @@
<file alias="Guided.SettingsGroup.json">src/Settings/Guided.SettingsGroup.json</file>
<file alias="QGCMapCircle.Facts.json">src/MissionManager/QGCMapCircle.Facts.json</file>
<file alias="RTK.SettingsGroup.json">src/Settings/RTK.SettingsGroup.json</file>
<file alias="TransectStyle.SettingsGroup.json">src/MissionManager/TransectStyle.SettingsGroup.json</file>
<file alias="Survey.SettingsGroup.json">src/MissionManager/Survey.SettingsGroup.json</file>
<file alias="CorridorScan.SettingsGroup.json">src/MissionManager/CorridorScan.SettingsGroup.json</file>
<file alias="StructureScan.SettingsGroup.json">src/MissionManager/StructureScan.SettingsGroup.json</file>
......
......@@ -14,15 +14,16 @@
#include <QQmlEngine>
const char* CameraCalc::_valueSetIsDistanceName = "ValueSetIsDistance";
const char* CameraCalc::_distanceToSurfaceName = "DistanceToSurface";
const char* CameraCalc::_imageDensityName = "ImageDensity";
const char* CameraCalc::_frontalOverlapName = "FrontalOverlap";
const char* CameraCalc::_sideOverlapName = "SideOverlap";
const char* CameraCalc::_adjustedFootprintFrontalName = "AdjustedFootprintFrontal";
const char* CameraCalc::_adjustedFootprintSideName = "AdjustedFootprintSide";
const char* CameraCalc::_jsonCameraNameKey = "CameraName";
const char* CameraCalc::_jsonCameraSpecTypeKey = "CameraSpecType";
const char* CameraCalc::_valueSetIsDistanceName = "ValueSetIsDistance";
const char* CameraCalc::_distanceToSurfaceName = "DistanceToSurface";
const char* CameraCalc::_distanceToSurfaceRelativeName = "DistanceToSurfaceRelative";
const char* CameraCalc::_imageDensityName = "ImageDensity";
const char* CameraCalc::_frontalOverlapName = "FrontalOverlap";
const char* CameraCalc::_sideOverlapName = "SideOverlap";
const char* CameraCalc::_adjustedFootprintFrontalName = "AdjustedFootprintFrontal";
const char* CameraCalc::_adjustedFootprintSideName = "AdjustedFootprintSide";
const char* CameraCalc::_jsonCameraNameKey = "CameraName";
const char* CameraCalc::_jsonCameraSpecTypeKey = "CameraSpecType";
CameraCalc::CameraCalc(Vehicle* vehicle, QObject* parent)
: CameraSpec (parent)
......@@ -30,6 +31,7 @@ CameraCalc::CameraCalc(Vehicle* vehicle, QObject* parent)
, _dirty (false)
, _cameraName (manualCameraName())
, _disableRecalc (false)
, _distanceToSurfaceRelative (true)
, _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/CameraCalc.FactMetaData.json"), this))
, _valueSetIsDistanceFact (0, _valueSetIsDistanceName, FactMetaData::valueTypeBool)
, _distanceToSurfaceFact (0, _distanceToSurfaceName, FactMetaData::valueTypeDouble)
......@@ -53,6 +55,7 @@ CameraCalc::CameraCalc(Vehicle* vehicle, QObject* parent)
_adjustedFootprintFrontalFact.setMetaData (_metaDataMap[_adjustedFootprintFrontalName], true);
connect(this, &CameraCalc::cameraNameChanged, this, &CameraCalc::_recalcTriggerDistance);
connect(this, &CameraCalc::cameraNameChanged, this, &CameraCalc::_adjustDistanceToSurfaceRelative);
connect(&_distanceToSurfaceFact, &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
connect(&_imageDensityFact, &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
......@@ -167,8 +170,9 @@ void CameraCalc::save(QJsonObject& json) const
json[JsonHelper::jsonVersionKey] = 1;
json[_adjustedFootprintSideName] = _adjustedFootprintSideFact.rawValue().toDouble();
json[_adjustedFootprintFrontalName] = _adjustedFootprintFrontalFact.rawValue().toDouble();
json[_distanceToSurfaceName] = _distanceToSurfaceFact.rawValue().toDouble();
json[_jsonCameraNameKey] = _cameraName;
json[_distanceToSurfaceName] = _distanceToSurfaceFact.rawValue().toDouble();
json[_distanceToSurfaceRelativeName] = _distanceToSurfaceRelative;
json[_jsonCameraNameKey] = _cameraName;
if (_cameraName != manualCameraName()) {
CameraSpec::save(json);
......@@ -209,6 +213,7 @@ bool CameraCalc::load(const QJsonObject& json, QString& errorString)
{ _adjustedFootprintSideName, QJsonValue::Double, true },
{ _adjustedFootprintFrontalName, QJsonValue::Double, true },
{ _distanceToSurfaceName, QJsonValue::Double, true },
{ _distanceToSurfaceRelativeName, QJsonValue::Bool, true },
};
if (!JsonHelper::validateKeys(v1Json, keyInfoList1, errorString)) {
return false;
......@@ -221,6 +226,8 @@ bool CameraCalc::load(const QJsonObject& json, QString& errorString)
_adjustedFootprintFrontalFact.setRawValue (v1Json[_adjustedFootprintFrontalName].toDouble());
_distanceToSurfaceFact.setRawValue (v1Json[_distanceToSurfaceName].toDouble());
_distanceToSurfaceRelative = v1Json[_distanceToSurfaceRelativeName].toBool();
if (_cameraName != manualCameraName()) {
QList<JsonHelper::KeyValidateInfo> keyInfoList2 = {
{ _valueSetIsDistanceName, QJsonValue::Bool, true },
......@@ -257,3 +264,18 @@ QString CameraCalc::manualCameraName(void)
{
return tr("Manual (no camera specs)");
}
void CameraCalc::_adjustDistanceToSurfaceRelative(void)
{
if (!isManualCamera()) {
setDistanceToSurfaceRelative(true);
}
}
void CameraCalc::setDistanceToSurfaceRelative(bool distanceToSurfaceRelative)
{
if (distanceToSurfaceRelative != _distanceToSurfaceRelative) {
_distanceToSurfaceRelative = distanceToSurfaceRelative;
emit distanceToSurfaceRelativeChanged(distanceToSurfaceRelative);
}
}
......@@ -20,17 +20,18 @@ class CameraCalc : public CameraSpec
public:
CameraCalc(Vehicle* vehicle, QObject* parent = NULL);
Q_PROPERTY(QString cameraName READ cameraName WRITE setCameraName NOTIFY cameraNameChanged)
Q_PROPERTY(QString customCameraName READ customCameraName CONSTANT) ///< Camera name for custom camera setting
Q_PROPERTY(QString manualCameraName READ manualCameraName CONSTANT) ///< Camera name for manual camera setting
Q_PROPERTY(bool isManualCamera READ isManualCamera NOTIFY cameraNameChanged) ///< true: using manual camera
Q_PROPERTY(Fact* valueSetIsDistance READ valueSetIsDistance CONSTANT) ///< true: distance specified, resolution calculated
Q_PROPERTY(Fact* distanceToSurface READ distanceToSurface CONSTANT) ///< Distance to surface for image foot print calculation
Q_PROPERTY(Fact* imageDensity READ imageDensity CONSTANT) ///< Image density on surface (cm/px)
Q_PROPERTY(Fact* frontalOverlap READ frontalOverlap CONSTANT)
Q_PROPERTY(Fact* sideOverlap READ sideOverlap CONSTANT)
Q_PROPERTY(Fact* adjustedFootprintSide READ adjustedFootprintSide CONSTANT) ///< Side footprint adjusted down for overlap
Q_PROPERTY(Fact* adjustedFootprintFrontal READ adjustedFootprintFrontal CONSTANT) ///< Frontal footprint adjusted down for overlap
Q_PROPERTY(QString cameraName READ cameraName WRITE setCameraName NOTIFY cameraNameChanged)
Q_PROPERTY(QString customCameraName READ customCameraName CONSTANT) ///< Camera name for custom camera setting
Q_PROPERTY(QString manualCameraName READ manualCameraName CONSTANT) ///< Camera name for manual camera setting
Q_PROPERTY(bool isManualCamera READ isManualCamera NOTIFY cameraNameChanged) ///< true: using manual camera
Q_PROPERTY(Fact* valueSetIsDistance READ valueSetIsDistance CONSTANT) ///< true: distance specified, resolution calculated
Q_PROPERTY(Fact* distanceToSurface READ distanceToSurface CONSTANT) ///< Distance to surface for image foot print calculation
Q_PROPERTY(Fact* imageDensity READ imageDensity CONSTANT) ///< Image density on surface (cm/px)
Q_PROPERTY(Fact* frontalOverlap READ frontalOverlap CONSTANT)
Q_PROPERTY(Fact* sideOverlap READ sideOverlap CONSTANT)
Q_PROPERTY(Fact* adjustedFootprintSide READ adjustedFootprintSide CONSTANT) ///< Side footprint adjusted down for overlap
Q_PROPERTY(Fact* adjustedFootprintFrontal READ adjustedFootprintFrontal CONSTANT) ///< Frontal footprint adjusted down for overlap
Q_PROPERTY(bool distanceToSurfaceRelative READ distanceToSurfaceRelative WRITE setDistanceToSurfaceRelative NOTIFY distanceToSurfaceRelativeChanged)
// The following values are calculated from the camera properties
Q_PROPERTY(double imageFootprintSide READ imageFootprintSide NOTIFY imageFootprintSideChanged) ///< Size of image size side in meters
......@@ -57,30 +58,35 @@ public:
const Fact* adjustedFootprintSide (void) const { return &_adjustedFootprintSideFact; }
const Fact* adjustedFootprintFrontal (void) const { return &_adjustedFootprintFrontalFact; }
bool isManualCamera (void) { return cameraName() == manualCameraName(); }
double imageFootprintSide (void) const { return _imageFootprintSide; }
double imageFootprintFrontal (void) const { return _imageFootprintFrontal; }
bool dirty (void) const { return _dirty; }
bool isManualCamera (void) { return cameraName() == manualCameraName(); }
double imageFootprintSide (void) const { return _imageFootprintSide; }
double imageFootprintFrontal (void) const { return _imageFootprintFrontal; }
bool distanceToSurfaceRelative (void) const { return _distanceToSurfaceRelative; }
bool dirty (void) const { return _dirty; }
void setDirty (bool dirty);
void setDirty (bool dirty);
void setDistanceToSurfaceRelative (bool distanceToSurfaceRelative);
void save(QJsonObject& json) const;
bool load(const QJsonObject& json, QString& errorString);
signals:
void cameraNameChanged (QString cameraName);
void dirtyChanged (bool dirty);
void imageFootprintSideChanged (double imageFootprintSide);
void imageFootprintFrontalChanged (double imageFootprintFrontal);
void cameraNameChanged (QString cameraName);
void dirtyChanged (bool dirty);
void imageFootprintSideChanged (double imageFootprintSide);
void imageFootprintFrontalChanged (double imageFootprintFrontal);
void distanceToSurfaceRelativeChanged (bool distanceToSurfaceRelative);
private slots:
void _recalcTriggerDistance(void);
void _recalcTriggerDistance (void);
void _adjustDistanceToSurfaceRelative (void);
private:
Vehicle* _vehicle;
bool _dirty;
QString _cameraName;
bool _disableRecalc;
bool _distanceToSurfaceRelative;
QMap<QString, FactMetaData*> _metaDataMap;
......@@ -99,6 +105,7 @@ private:
static const char* _valueSetIsDistanceName;
static const char* _distanceToSurfaceName;
static const char* _distanceToSurfaceRelativeName;
static const char* _imageDensityName;
static const char* _frontalOverlapName;
static const char* _sideOverlapName;
......
......@@ -35,8 +35,8 @@
"defaultValue": 30
},
{
"name": "TurnaroundDist",
"shortDescription": "Amount of additional distance to add outside the grid area for vehicle turnaround.",
"name": "TurnaroundDistance",
"shortDescription": "Amount of additional distance to add outside the survey area for vehicle turnaround.",
"type": "double",
"decimalPlaces": 2,
"min": 0,
......
......@@ -9,7 +9,7 @@
#pragma once
#include "ComplexMissionItem.h"
#include "TransectStyleComplexItem.h"
#include "MissionItem.h"
#include "SettingsFact.h"
#include "QGCLoggingCategory.h"
......@@ -19,120 +19,61 @@
Q_DECLARE_LOGGING_CATEGORY(CorridorScanComplexItemLog)
class CorridorScanComplexItem : public ComplexMissionItem
class CorridorScanComplexItem : public TransectStyleComplexItem
{
Q_OBJECT
public:
CorridorScanComplexItem(Vehicle* vehicle, QObject* parent = NULL);
Q_PROPERTY(CameraCalc* cameraCalc READ cameraCalc CONSTANT)
Q_PROPERTY(QGCMapPolyline* corridorPolyline READ corridorPolyline CONSTANT)
Q_PROPERTY(QGCMapPolygon* corridorPolygon READ corridorPolygon CONSTANT)
Q_PROPERTY(Fact* corridorWidth READ corridorWidth CONSTANT)
Q_PROPERTY(int cameraShots READ cameraShots NOTIFY cameraShotsChanged)
Q_PROPERTY(double timeBetweenShots READ timeBetweenShots NOTIFY timeBetweenShotsChanged)
Q_PROPERTY(double coveredArea READ coveredArea NOTIFY coveredAreaChanged)
Q_PROPERTY(double cameraMinTriggerInterval MEMBER _cameraMinTriggerInterval NOTIFY cameraMinTriggerIntervalChanged)
Q_PROPERTY(QVariantList transectPoints READ transectPoints NOTIFY transectPointsChanged)
CameraCalc* cameraCalc (void) { return &_cameraCalc; }
QGCMapPolyline* corridorPolyline(void) { return &_corridorPolyline; }
QGCMapPolygon* corridorPolygon (void) { return &_corridorPolygon; }
Fact* corridorWidth (void) { return &_corridorWidthFact; }
QVariantList transectPoints (void) { return _transectPoints; }
Q_PROPERTY(CameraCalc* cameraCalc READ cameraCalc CONSTANT)
Q_PROPERTY(QGCMapPolyline* corridorPolyline READ corridorPolyline CONSTANT)
Q_PROPERTY(Fact* corridorWidth READ corridorWidth CONSTANT)
int cameraShots (void) const { return _cameraShots; }
double timeBetweenShots (void);
double coveredArea (void) const;
Fact* corridorWidth (void) { return &_corridorWidthFact; }
QGCMapPolyline* corridorPolyline(void) { return &_corridorPolyline; }
Q_INVOKABLE void rotateEntryPoint(void);
// Overrides from ComplexMissionItem
double complexDistance (void) const final { return _scanDistance; }
int lastSequenceNumber (void) const final;
bool load (const QJsonObject& complexObject, int sequenceNumber, QString& errorString) final;
double greatestDistanceTo (const QGeoCoordinate &other) const final;
QString mapVisualQML (void) const final { return QStringLiteral("CorridorScanMapVisual.qml"); }
// Overrides from VisualMissionItem
bool dirty (void) const final { return _dirty; }
bool isSimpleItem (void) const final { return false; }
bool isStandaloneCoordinate (void) const final { return false; }
bool specifiesCoordinate (void) const final;
bool specifiesAltitudeOnly (void) const final { return false; }
QString commandDescription (void) const final { return tr("Corridor Scan"); }
QString commandName (void) const final { return tr("Corridor Scan"); }
QString abbreviation (void) const final { return "S"; }
QGeoCoordinate coordinate (void) const final { return _coordinate; }
QGeoCoordinate exitCoordinate (void) const final { return _exitCoordinate; }
int sequenceNumber (void) const final { return _sequenceNumber; }
double specifiedFlightSpeed (void) final { return std::numeric_limits<double>::quiet_NaN(); }
double specifiedGimbalYaw (void) final { return std::numeric_limits<double>::quiet_NaN(); }
double specifiedGimbalPitch (void) final { return std::numeric_limits<double>::quiet_NaN(); }
void appendMissionItems (QList<MissionItem*>& items, QObject* missionItemParent) final;
void setMissionFlightStatus (MissionController::MissionFlightStatus_t& missionFlightStatus) final;
void applyNewAltitude (double newAltitude) final;
bool coordinateHasRelativeAltitude (void) const final { return true /*_altitudeRelative*/; }
bool exitCoordinateHasRelativeAltitude (void) const final { return true /*_altitudeRelative*/; }
bool exitCoordinateSameAsEntry (void) const final { return false; }
void setDirty (bool dirty) final;
void setCoordinate (const QGeoCoordinate& coordinate) final { Q_UNUSED(coordinate); }
void setSequenceNumber (int sequenceNumber) final;
void save (QJsonArray& missionItems) final;
int lastSequenceNumber (void) const final;
bool load (const QJsonObject& complexObject, int sequenceNumber, QString& errorString) final;
QString mapVisualQML (void) const final { return QStringLiteral("CorridorScanMapVisual.qml"); }
// Overrides from TransectStyleComplexItem
void save (QJsonArray& missionItems) final;
bool specifiesCoordinate (void) const final;
void appendMissionItems (QList<MissionItem*>& items, QObject* missionItemParent) final;
void applyNewAltitude (double newAltitude) final;
static const char* jsonComplexItemTypeValue;
signals:
void cameraShotsChanged (void);
void timeBetweenShotsChanged (void);
void cameraMinTriggerIntervalChanged(double cameraMinTriggerInterval);
void altitudeRelativeChanged (bool altitudeRelative);
void transectPointsChanged (void);
void coveredAreaChanged (void);
static const char* settingsGroup;
static const char* corridorWidthName;
private slots:
void _setDirty (void);
void _polylineDirtyChanged (bool dirty);
void _polylineCountChanged (int count);
void _clearInternal (void);
void _updateCoordinateAltitudes (void);
void _signalLastSequenceNumberChanged (void);
void _rebuildCorridor (void);
void _rebuildTransects (void);
// Overrides from TransectStyleComplexItem
virtual void _rebuildTransects (void) final;
private:
void _setExitCoordinate (const QGeoCoordinate& coordinate);
void _setScanDistance (double scanDistance);
void _setCameraShots (int cameraShots);
double _triggerDistance (void) const;
int _transectCount (void) const;
void _rebuildCorridorPolygon(void);
int _sequenceNumber;
bool _dirty;
QGeoCoordinate _coordinate;
QGeoCoordinate _exitCoordinate;
QGCMapPolyline _corridorPolyline;
QGCMapPolygon _corridorPolygon;
Fact _corridorWidthFact;
QVariantList _transectPoints;
bool _ignoreRecalc;
double _scanDistance;
int _cameraShots;
double _timeBetweenShots;
double _cameraMinTriggerInterval;
double _cruiseSpeed;
CameraCalc _cameraCalc;
QGCMapPolyline _corridorPolyline;
QList<QList<QGeoCoordinate>> _transectSegments; ///< Internal transect segments including grid exit, turnaround and internal camera points
static QMap<QString, FactMetaData*> _metaDataMap;
bool _ignoreRecalc;
int _entryPoint;
static const char* _corridorWidthFactName;
QMap<QString, FactMetaData*> _metaDataMap;
SettingsFact _corridorWidthFact;
static const char* _jsonCameraCalcKey;
static const char* _entryPointName;
};
......@@ -43,7 +43,7 @@ void CorridorScanComplexItemTest::init(void)
_rgCorridorPolygonSignals[corridorPolygonPathChangedIndex] = SIGNAL(pathChanged());
_multiSpyCorridorPolygon = new MultiSignalSpy();
QCOMPARE(_multiSpyCorridorPolygon->init(_corridorItem->corridorPolygon(), _rgCorridorPolygonSignals, _cCorridorPolygonSignals), true);
QCOMPARE(_multiSpyCorridorPolygon->init(_corridorItem->surveyAreaPolygon(), _rgCorridorPolygonSignals, _cCorridorPolygonSignals), true);
}
void CorridorScanComplexItemTest::cleanup(void)
......
[
{
"name": "TurnAroundDistance",
"shortDescription": "Amount of additional distance to add outside the survey area for vehicle turn around.",
"type": "double",
"decimalPlaces": 2,
"min": 0,
"units": "m",
"defaultValue": 30
},
{
"name": "TurnAroundDistanceMultiRotor",
"shortDescription": "Amount of additional distance to add outside the survey area for vehicle turn around.",
"type": "double",
"decimalPlaces": 2,
"min": 0,
"units": "m",
"defaultValue": 10
},
{
"name": "CameraTriggerInTurnAround",
"shortDescription": "Camera continues taking images in turn arounds.",
"type": "bool",
"defaultValue": true
},
{
"name": "HoverAndCapture",
"shortDescription": "Stop and Hover at each image point before taking image",
"type": "bool",
"defaultValue": false
},
{
"name": "Refly90Degrees",
"shortDescription": "Refly the pattern at a 90 degree angle",
"type": "bool",
"defaultValue": false
}
]
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#include "TransectStyleComplexItem.h"
#include "JsonHelper.h"
#include "MissionController.h"
#include "QGCGeo.h"
#include "QGroundControlQmlGlobal.h"
#include "QGCQGeoCoordinate.h"
#include "SettingsManager.h"
#include "AppSettings.h"
#include "QGCQGeoCoordinate.h"
#include <QPolygonF>
QGC_LOGGING_CATEGORY(TransectStyleComplexItemLog, "TransectStyleComplexItemLog")
const char* TransectStyleComplexItem::turnAroundDistanceName = "TurnAroundDistance";
const char* TransectStyleComplexItem::turnAroundDistanceMultiRotorName = "TurnAroundDistanceMultiRotor";
const char* TransectStyleComplexItem::cameraTriggerInTurnAroundName = "CameraTriggerInTurnAround";
const char* TransectStyleComplexItem::hoverAndCaptureName = "HoverAndCapture";
const char* TransectStyleComplexItem::refly90DegreesName = "Refly90Degrees";
const char* TransectStyleComplexItem::_jsonCameraCalcKey = "CameraCalc";
TransectStyleComplexItem::TransectStyleComplexItem(Vehicle* vehicle, QString settingsGroup, QObject* parent)
: ComplexMissionItem (vehicle, parent)
, _settingsGroup (settingsGroup)
, _sequenceNumber (0)
, _dirty (false)
, _ignoreRecalc (false)
, _scanDistance (0.0)
, _cameraShots (0)
, _cameraMinTriggerInterval (0)
, _cameraCalc (vehicle)
, _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/TransectStyle.SettingsGroup.json"), this))
, _turnAroundDistanceFact (_settingsGroup, _metaDataMap[_vehicle->multiRotor() ? turnAroundDistanceMultiRotorName : turnAroundDistanceName])
, _cameraTriggerInTurnAroundFact(_settingsGroup, _metaDataMap[cameraTriggerInTurnAroundName])
, _hoverAndCaptureFact (_settingsGroup, _metaDataMap[hoverAndCaptureName])
, _refly90DegreesFact (_settingsGroup, _metaDataMap[refly90DegreesName])
{
connect(this, &TransectStyleComplexItem::altitudeRelativeChanged, this, &TransectStyleComplexItem::_setDirty);
connect(this, &TransectStyleComplexItem::altitudeRelativeChanged, this, &TransectStyleComplexItem::coordinateHasRelativeAltitudeChanged);
connect(this, &TransectStyleComplexItem::altitudeRelativeChanged, this, &TransectStyleComplexItem::exitCoordinateHasRelativeAltitudeChanged);
connect(_cameraCalc.adjustedFootprintSide(), &Fact::valueChanged, this, &TransectStyleComplexItem::_rebuildTransects);
connect(_cameraCalc.adjustedFootprintSide(), &Fact::valueChanged, this, &TransectStyleComplexItem::_signalLastSequenceNumberChanged);
connect(&_turnAroundDistanceFact, &Fact::valueChanged, this, &TransectStyleComplexItem::_rebuildTransects);
connect(&_surveyAreaPolygon, &QGCMapPolygon::pathChanged, this, &TransectStyleComplexItem::coveredAreaChanged);
connect(this, &TransectStyleComplexItem::transectPointsChanged, this, &TransectStyleComplexItem::complexDistanceChanged);
connect(this, &TransectStyleComplexItem::transectPointsChanged, this, &TransectStyleComplexItem::greatestDistanceToChanged);
}
void TransectStyleComplexItem::_setScanDistance(double scanDistance)
{
if (!qFuzzyCompare(_scanDistance, scanDistance)) {
_scanDistance = scanDistance;
emit complexDistanceChanged();
}
}
void TransectStyleComplexItem::_setCameraShots(int cameraShots)
{
if (_cameraShots != cameraShots) {
_cameraShots = cameraShots;
emit cameraShotsChanged();
}
}
void TransectStyleComplexItem::setDirty(bool dirty)
{
if (_dirty != dirty) {
_dirty = dirty;
emit dirtyChanged(_dirty);
}
}
void TransectStyleComplexItem::_save(QJsonObject& complexObject)
{
complexObject[turnAroundDistanceName] = _turnAroundDistanceFact.rawValue().toDouble();
complexObject[cameraTriggerInTurnAroundName] = _cameraTriggerInTurnAroundFact.rawValue().toBool();
complexObject[hoverAndCaptureName] = _hoverAndCaptureFact.rawValue().toBool();
complexObject[refly90DegreesName] = _refly90DegreesFact.rawValue().toBool();
QJsonObject cameraCalcObject;
_cameraCalc.save(cameraCalcObject);
complexObject[_jsonCameraCalcKey] = cameraCalcObject;
}
void TransectStyleComplexItem::setSequenceNumber(int sequenceNumber)
{
if (_sequenceNumber != sequenceNumber) {
_sequenceNumber = sequenceNumber;
emit sequenceNumberChanged(sequenceNumber);
emit lastSequenceNumberChanged(lastSequenceNumber());
}
}
bool TransectStyleComplexItem::_load(const QJsonObject& complexObject, QString& errorString)
{
QList<JsonHelper::KeyValidateInfo> keyInfoList = {
{ turnAroundDistanceName, QJsonValue::Double, true },
{ cameraTriggerInTurnAroundName, QJsonValue::Bool, true },
{ hoverAndCaptureName, QJsonValue::Bool, true },
{ refly90DegreesName, QJsonValue::Bool, true },
{ _jsonCameraCalcKey, QJsonValue::Object, true },
};
if (!JsonHelper::validateKeys(complexObject, keyInfoList, errorString)) {
return false;
}
if (!_cameraCalc.load(complexObject[_jsonCameraCalcKey].toObject(), errorString)) {
return false;
}
_turnAroundDistanceFact.setRawValue (complexObject[turnAroundDistanceName].toDouble());
_cameraTriggerInTurnAroundFact.setRawValue (complexObject[cameraTriggerInTurnAroundName].toBool());
_hoverAndCaptureFact.setRawValue (complexObject[hoverAndCaptureName].toBool());
_hoverAndCaptureFact.setRawValue (complexObject[refly90DegreesName].toBool());
return true;
}
double TransectStyleComplexItem::greatestDistanceTo(const QGeoCoordinate &other) const
{
double greatestDistance = 0.0;
for (int i=0; i<_transectPoints.count(); i++) {
QGeoCoordinate vertex = _transectPoints[i].value<QGeoCoordinate>();
double distance = vertex.distanceTo(other);
if (distance > greatestDistance) {
greatestDistance = distance;
}
}
return greatestDistance;
}
void TransectStyleComplexItem::setMissionFlightStatus(MissionController::MissionFlightStatus_t& missionFlightStatus)
{
ComplexMissionItem::setMissionFlightStatus(missionFlightStatus);
if (!qFuzzyCompare(_cruiseSpeed, missionFlightStatus.vehicleSpeed)) {
_cruiseSpeed = missionFlightStatus.vehicleSpeed;
emit timeBetweenShotsChanged();
}
}
void TransectStyleComplexItem::_setDirty(void)
{
setDirty(true);
}
void TransectStyleComplexItem::applyNewAltitude(double newAltitude)
{
Q_UNUSED(newAltitude);
// FIXME: NYI
//_altitudeFact.setRawValue(newAltitude);
}
double TransectStyleComplexItem::timeBetweenShots(void)
{
return _cruiseSpeed == 0 ? 0 : _cameraCalc.adjustedFootprintSide()->rawValue().toDouble() / _cruiseSpeed;
}
void TransectStyleComplexItem::_updateCoordinateAltitudes(void)
{
emit coordinateChanged(coordinate());
emit exitCoordinateChanged(exitCoordinate());
}
void TransectStyleComplexItem::_signalLastSequenceNumberChanged(void)
{
emit lastSequenceNumberChanged(lastSequenceNumber());
}
double TransectStyleComplexItem::coveredArea(void) const
{
return _surveyAreaPolygon.area();
}
bool TransectStyleComplexItem::_hasTurnaround(void) const
{
return _turnaroundDistance() > 0;
}
double TransectStyleComplexItem::_turnaroundDistance(void) const
{
return _turnAroundDistanceFact.rawValue().toDouble();
}
bool TransectStyleComplexItem::hoverAndCaptureAllowed(void) const
{
return _vehicle->multiRotor() || _vehicle->vtol();
}
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#pragma once
#include "ComplexMissionItem.h"
#include "MissionItem.h"
#include "SettingsFact.h"
#include "QGCLoggingCategory.h"
#include "QGCMapPolyline.h"
#include "QGCMapPolygon.h"
#include "CameraCalc.h"
Q_DECLARE_LOGGING_CATEGORY(TransectStyleComplexItemLog)
class TransectStyleComplexItem : public ComplexMissionItem
{
Q_OBJECT
public:
TransectStyleComplexItem(Vehicle* vehicle, QString settignsGroup, QObject* parent = NULL);
Q_PROPERTY(QGCMapPolygon* surveyAreaPolygon READ surveyAreaPolygon CONSTANT)
Q_PROPERTY(CameraCalc* cameraCalc READ cameraCalc CONSTANT)
Q_PROPERTY(Fact* turnAroundDistance READ turnAroundDistance CONSTANT)
Q_PROPERTY(Fact* cameraTriggerInTurnAround READ cameraTriggerInTurnAround CONSTANT)
Q_PROPERTY(Fact* hoverAndCapture READ hoverAndCapture CONSTANT)
Q_PROPERTY(Fact* refly90Degrees READ refly90Degrees CONSTANT)
Q_PROPERTY(int cameraShots READ cameraShots NOTIFY cameraShotsChanged)
Q_PROPERTY(double timeBetweenShots READ timeBetweenShots NOTIFY timeBetweenShotsChanged)
Q_PROPERTY(double coveredArea READ coveredArea NOTIFY coveredAreaChanged)
Q_PROPERTY(double cameraMinTriggerInterval READ cameraMinTriggerInterval NOTIFY cameraMinTriggerIntervalChanged)
Q_PROPERTY(bool hoverAndCaptureAllowed READ hoverAndCaptureAllowed CONSTANT)
Q_PROPERTY(QVariantList transectPoints READ transectPoints NOTIFY transectPointsChanged)
QGCMapPolygon* surveyAreaPolygon (void) { return &_surveyAreaPolygon; }
CameraCalc* cameraCalc (void) { return &_cameraCalc; }
QVariantList transectPoints (void) { return _transectPoints; }
Fact* turnAroundDistance (void) { return &_turnAroundDistanceFact; }
Fact* cameraTriggerInTurnAround (void) { return &_cameraTriggerInTurnAroundFact; }
Fact* hoverAndCapture (void) { return &_hoverAndCaptureFact; }
Fact* refly90Degrees (void) { return &_refly90DegreesFact; }
int cameraShots (void) const { return _cameraShots; }
double timeBetweenShots (void);
double coveredArea (void) const;
double cameraMinTriggerInterval(void) const { return _cameraMinTriggerInterval; }
bool hoverAndCaptureAllowed (void) const;
// Overrides from ComplexMissionItem
int lastSequenceNumber (void) const override = 0;
QString mapVisualQML (void) const override = 0;
bool load (const QJsonObject& complexObject, int sequenceNumber, QString& errorString) override = 0;
double complexDistance (void) const final { return _scanDistance; }
double greatestDistanceTo (const QGeoCoordinate &other) const final;
// Overrides from VisualMissionItem
void save (QJsonArray& missionItems) override = 0;
bool specifiesCoordinate (void) const override = 0;
void appendMissionItems (QList<MissionItem*>& items, QObject* missionItemParent) override = 0;
void applyNewAltitude (double newAltitude) override = 0;
bool dirty (void) const final { return _dirty; }
bool isSimpleItem (void) const final { return false; }
bool isStandaloneCoordinate (void) const final { return false; }
bool specifiesAltitudeOnly (void) const final { return false; }
QString commandDescription (void) const final { return tr("Corridor Scan"); }
QString commandName (void) const final { return tr("Corridor Scan"); }
QString abbreviation (void) const final { return "S"; }
QGeoCoordinate coordinate (void) const final { return _coordinate; }
QGeoCoordinate exitCoordinate (void) const final { return _exitCoordinate; }
int sequenceNumber (void) const final { return _sequenceNumber; }
double specifiedFlightSpeed (void) final { return std::numeric_limits<double>::quiet_NaN(); }
double specifiedGimbalYaw (void) final { return std::numeric_limits<double>::quiet_NaN(); }
double specifiedGimbalPitch (void) final { return std::numeric_limits<double>::quiet_NaN(); }
void setMissionFlightStatus (MissionController::MissionFlightStatus_t& missionFlightStatus) final;
bool coordinateHasRelativeAltitude (void) const final { return true /*_altitudeRelative*/; }
bool exitCoordinateHasRelativeAltitude (void) const final { return true /*_altitudeRelative*/; }
bool exitCoordinateSameAsEntry (void) const final { return false; }
void setDirty (bool dirty) final;
void setCoordinate (const QGeoCoordinate& coordinate) final { Q_UNUSED(coordinate); }
void setSequenceNumber (int sequenceNumber) final;
static const char* turnAroundDistanceName;
static const char* turnAroundDistanceMultiRotorName;
static const char* cameraTriggerInTurnAroundName;
static const char* hoverAndCaptureName;
static const char* refly90DegreesName;
signals:
void cameraShotsChanged (void);
void timeBetweenShotsChanged (void);
void cameraMinTriggerIntervalChanged(double cameraMinTriggerInterval);
void altitudeRelativeChanged (bool altitudeRelative);
void transectPointsChanged (void);
void coveredAreaChanged (void);
protected slots:
virtual void _rebuildTransects (void) = 0;
void _setDirty (void);
void _updateCoordinateAltitudes (void);
void _signalLastSequenceNumberChanged (void);
protected:
void _save (QJsonObject& saveObject);
bool _load (const QJsonObject& complexObject, QString& errorString);
void _setExitCoordinate (const QGeoCoordinate& coordinate);
void _setScanDistance (double scanDistance);
void _setCameraShots (int cameraShots);
double _triggerDistance (void) const;
int _transectCount (void) const;
bool _hasTurnaround (void) const;
double _turnaroundDistance (void) const;
QString _settingsGroup;
int _sequenceNumber;
bool _dirty;
QGeoCoordinate _coordinate;
QGeoCoordinate _exitCoordinate;
QVariantList _transectPoints;
QGCMapPolygon _surveyAreaPolygon;
bool _ignoreRecalc;
double _scanDistance;
int _cameraShots;
double _timeBetweenShots;
double _cameraMinTriggerInterval;
double _cruiseSpeed;
CameraCalc _cameraCalc;
QMap<QString, FactMetaData*> _metaDataMap;
SettingsFact _turnAroundDistanceFact;
SettingsFact _cameraTriggerInTurnAroundFact;
SettingsFact _hoverAndCaptureFact;
SettingsFact _refly90DegreesFact;
static const char* _jsonCameraCalcKey;
};
......@@ -100,6 +100,39 @@ Rectangle {
fact: missionItem.corridorWidth
Layout.fillWidth: true
}
QGCLabel { text: qsTr("Turnaround dist") }
FactTextField {
fact: missionItem.turnAroundDistance
Layout.fillWidth: true
}
FactCheckBox {
text: qsTr("Take images in turnarounds")
fact: missionItem.cameraTriggerInTurnAround
enabled: missionItem.hoverAndCaptureAllowed ? !missionItem.hoverAndCapture.rawValue : true
Layout.columnSpan: 2
}
QGCCheckBox {
id: relAlt
anchors.left: parent.left
text: qsTr("Relative altitude")
checked: missionItem.cameraCalc.distanceToSurfaceRelative
enabled: missionItem.cameraCalc.isManualCamera
Layout.columnSpan: 2
onClicked: missionItem.cameraCalc.distanceToSurfaceRelative = checked
Connections {
target: missionItem.cameraCalc
onDistanceToSurfaceRelativeChanged: relAlt.checked = missionItem.cameraCalc.distanceToSurfaceRelative
}
}
}
QGCButton {
text: qsTr("Rotate Entry Point")
onClicked: missionItem.rotateEntryPoint()
}
SectionHeader {
......
......@@ -56,7 +56,7 @@ Item {
QGCMapPolygonVisuals {
qgcView: _root.qgcView
mapControl: map
mapPolygon: object.corridorPolygon
mapPolygon: object.surveyAreaPolygon
interactive: false
interiorColor: "green"
interiorOpacity: 0.25
......
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