9#include <QtCore/QJsonArray>
17 , _entryPointLocation (EntryPointDefaultOrder)
19 , _corridorWidthFact (settingsGroup, _metaDataMap[corridorWidthName])
21 _editorQml =
"qrc:/qml/QGroundControl/Controls/CorridorScanEditor.qml";
24 if (_cameraCalc.isManualCamera() || !_cameraCalc.valueSetIsDistance()->rawValue().toBool()) {
25 _cameraCalc.distanceToSurface()->setRawValue(SettingsManager::instance()->appSettings()->defaultMissionItemAltitude()->rawValue());
34 connect(&_corridorWidthFact, &
Fact::valueChanged,
this, &CorridorScanComplexItem::_rebuildCorridorPolygon);
39 if (!kmlOrShpFile.isEmpty()) {
40 _corridorPolyline.loadKMLOrSHPFile(kmlOrShpFile);
41 _corridorPolyline.setDirty(
false);
48 QJsonObject saveObject;
50 _saveCommon(saveObject);
51 planItems.append(saveObject);
56 QJsonObject saveObject;
58 _saveCommon(saveObject);
62void CorridorScanComplexItem::_saveCommon(QJsonObject& saveObject)
70 saveObject[_jsonEntryPointKey] =
static_cast<int>(_entryPointLocation);
80 if (!_loadWorker(presetObject, 0,
errorString,
true )) {
81 qgcApp()->showAppMessage(QStringLiteral(
"Internal Error: Preset load failed. Name: %1 Error: %2").arg(presetName).arg(
errorString));
86bool CorridorScanComplexItem::_loadWorker(
const QJsonObject& complexObject,
int sequenceNumber, QString&
errorString,
bool forPresets)
90 QList<JsonHelper::KeyValidateInfo> keyInfoList = {
95 { _jsonEntryPointKey, QJsonValue::Double,
true },
106 errorString = tr(
"%1 does not support loading this complex mission item type: %2:%3").arg(
qgcApp()->applicationName()).arg(itemType).arg(complexType);
134 _entryPointLocation =
static_cast<EntryPointLocation
>(complexObject[_jsonEntryPointKey].toInt());
141 _recalcCameraShots();
154 return _corridorPolyline.
count() > 1;
165 const QList<QGeoCoordinate> vertices = _corridorPolyline.
coordinateList();
167 QList<QGeoCoordinate> translatedVertices;
168 translatedVertices.reserve(vertices.count());
169 for (
const QGeoCoordinate& vertex: vertices) {
170 translatedVertices.append(vertex.atDistanceAndAzimuth(distanceMeters, azimuthDegrees));
173 _corridorPolyline.
setPath(translatedVertices);
176int CorridorScanComplexItem::_calcTransectCount(
void)
const
178 double fullWidth = _corridorWidthFact.rawValue().toDouble();
179 return fullWidth > 0.0 ? qCeil(fullWidth / _calcTransectSpacing()) : 1;
182void CorridorScanComplexItem::_polylineDirtyChanged(
bool dirty)
191 int modeAsInt =
static_cast<int>(_entryPointLocation);
193 if (_calcTransectCount() < 2) {
200 if (modeAsInt > EntryPointStartOppositeEndOppositeSide) {
204 _entryPointLocation =
static_cast<EntryPointLocation
>(modeAsInt);
209void CorridorScanComplexItem::_rebuildCorridorPolygon(
void)
211 if (_corridorPolyline.
count() < 2) {
216 double halfWidth = _corridorWidthFact.rawValue().toDouble() / 2.0;
218 QList<QGeoCoordinate> firstSideVertices = _corridorPolyline.
offsetPolyline(halfWidth);
219 QList<QGeoCoordinate> secondSideVertices = _corridorPolyline.
offsetPolyline(-halfWidth);
223 QList<QGeoCoordinate> rgCoord;
224 for (
const QGeoCoordinate& vertex: firstSideVertices) {
225 rgCoord.append(vertex);
227 for (
int i=secondSideVertices.count() - 1; i >= 0; i--) {
228 rgCoord.append(secondSideVertices[i]);
233void CorridorScanComplexItem::_rebuildTransectsPhase1(
void)
246 double transectSpacing = _calcTransectSpacing();
247 double fullWidth = _corridorWidthFact.rawValue().toDouble();
248 double halfWidth = fullWidth / 2.0;
249 int transectCount = _calcTransectCount();
250 double normalizedTransectPosition = transectSpacing / 2.0;
252 if (_corridorPolyline.
count() >= 2) {
255 for (
int i=0; i<transectCount; i++) {
257 double offsetDistance;
258 if (transectCount == 1) {
263 offsetDistance = halfWidth - normalizedTransectPosition;
267 QList<TransectStyleComplexItem::CoordInfo_t> transect;
268 QList<QGeoCoordinate> transectCoords = _corridorPolyline.
offsetPolyline(offsetDistance);
269 for (
int j=1; j<transectCoords.count() - 1; j++) {
271 transect.append(coordInfo);
274 transect.prepend(coordInfo);
276 transect.append(coordInfo);
280 QGeoCoordinate turnaroundCoord;
283 double azimuth = transectCoords[0].azimuthTo(transectCoords[1]);
285 turnaroundCoord.setAltitude(qQNaN());
287 transect.prepend(turnaroundCoordInfo);
289 azimuth = transectCoords.last().azimuthTo(transectCoords[transectCoords.count() - 2]);
291 turnaroundCoord.setAltitude(qQNaN());
293 transect.append(coordInfo);
297 qDebug() <<
"transect debug";
304 normalizedTransectPosition += transectSpacing;
313 bool reverseTransects =
false;
314 bool reverseVertices =
false;
315 switch (_entryPointLocation) {
316 case EntryPointDefaultOrder:
317 reverseTransects =
false;
318 reverseVertices =
false;
320 case EntryPointStartSameEndOppositeSide:
321 reverseTransects =
true;
322 reverseVertices =
false;
324 case EntryPointStartOppositeEndSameSide:
325 reverseTransects =
false;
326 reverseVertices =
true;
328 case EntryPointStartOppositeEndOppositeSide:
329 reverseTransects =
true;
330 reverseVertices =
true;
333 if (reverseTransects) {
334 QList<QList<TransectStyleComplexItem::CoordInfo_t>> reversedTransects;
335 for (
const QList<TransectStyleComplexItem::CoordInfo_t>& transect:
_transects) {
336 reversedTransects.prepend(transect);
340 if (reverseVertices) {
342 QList<TransectStyleComplexItem::CoordInfo_t> reversedVertices;
344 reversedVertices.prepend(vertex);
351 reverseVertices =
false;
354 QList<TransectStyleComplexItem::CoordInfo_t> transectVertices =
_transects[i];
355 if (reverseVertices) {
356 reverseVertices =
false;
357 QList<TransectStyleComplexItem::CoordInfo_t> reversedVertices;
358 for (
int j=transectVertices.count()-1; j>=0; j--) {
359 reversedVertices.append(transectVertices[j]);
369 transectVertices = reversedVertices;
371 reverseVertices =
true;
378void CorridorScanComplexItem::_recalcCameraShots(
void)
388 _cameraShots = singleTransectImageCount * _calcTransectCount();
404double CorridorScanComplexItem::_calcTransectSpacing(
void)
const
414 return transectSpacing;
417void CorridorScanComplexItem::_updateWizardMode(
void)
#define QGC_LOGGING_CATEGORY(name, categoryStr)
Fact * adjustedFootprintSide(void)
Fact * adjustedFootprintFrontal(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)
bool load(const QJsonObject &complexObject, int sequenceNumber, QString &errorString) final
void savePreset(const QString &name)
void setCoordinate(const QGeoCoordinate &coordinate) final
double timeBetweenShots(void) final
void save(QJsonArray &planItems) final
static constexpr const char * corridorWidthName
bool specifiesCoordinate(void) const final
void loadPreset(const QString &name)
void rotateEntryPoint(void)
static constexpr const char * jsonComplexItemTypeValue
ReadyForSaveState readyForSaveState(void) const final
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.
void appendVertices(const QVariantList &varCoords)
QList< QGeoCoordinate > offsetPolyline(double distance)
void dirtyChanged(bool dirty)
static constexpr const char * jsonPolylineKey
void traceModeChanged(bool traceMode)
void setPath(const QList< QGeoCoordinate > &path)
void saveToJson(QJsonObject &json)
QList< QGeoCoordinate > coordinateList(void) const
Returns the path in a list of QGeoCoordinate's format.
void isValidChanged(void)
bool loadFromJson(const QJsonObject &json, bool required, QString &errorString)
double length(void) const
Returns the length of the polyline in meters.
bool traceMode(void) const
static constexpr double _minimumTransectSpacingMeters
QObject * _loadedMissionItemsParent
Parent for all items in _loadedMissionItems for simpler delete.
QList< QList< CoordInfo_t > > _transects
QList< MissionItem * > _loadedMissionItems
Mission items loaded from plan file.
void _recalcComplexDistance(void)
void setSequenceNumber(int sequenceNumber) final
QGeoCoordinate coordinate(void) const final
bool _hasTurnaround(void) const
int sequenceNumber(void) const final
ReadyForSaveState readyForSaveState(void) const override
bool _load(const QJsonObject &complexObject, bool forPresets, QString &errorString)
static constexpr double _forceLargeTransectSpacingMeters
QGCMapPolygon _surveyAreaPolygon
Fact * turnAroundDistance(void)
SettingsFact _cameraTriggerInTurnAroundFact
double triggerDistance(void) const
void cameraShotsChanged(void)
void _save(QJsonObject &saveObject)
void _rebuildTransects(void)
bool dirty(void) const final
SettingsFact _turnAroundDistanceFact
void setDirty(bool dirty) final
QGeoCoordinate _entryCoordinate
@ CoordTypeTurnaround
Turnaround extension waypoint.
@ CoordTypeSurveyExit
Waypoint at exit edge of survey polygon.
@ CoordTypeInterior
Interior waypoint for flight path only (example: interior corridor point)
@ 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
constexpr const char * jsonVersionKey
bool validateKeys(const QJsonObject &jsonObject, const QList< KeyValidateInfo > &keyInfo, QString &errorString)