13 changed files with 694 additions and 286 deletions
@ -0,0 +1,38 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"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 |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,204 @@ |
|||||||
|
/****************************************************************************
|
||||||
|
* |
||||||
|
* (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(); |
||||||
|
} |
||||||
|
|
@ -0,0 +1,153 @@ |
|||||||
|
/****************************************************************************
|
||||||
|
* |
||||||
|
* (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; |
||||||
|
}; |
Loading…
Reference in new issue