10#include <QtCore/QJsonArray>
16 , _entryPointLocation (EntryPointDefaultOrder)
18 , _corridorWidthFact (settingsGroup, _metaDataMap[corridorWidthName])
20 _editorQml =
"qrc:/qml/QGroundControl/PlanView/CorridorScanEditor.qml";
23 if (_cameraCalc.isManualCamera() || !_cameraCalc.valueSetIsDistance()->rawValue().toBool()) {
24 _cameraCalc.distanceToSurface()->setRawValue(
SettingsManager::instance()->appSettings()->defaultMissionItemAltitude()->rawValue());
33 connect(&_corridorWidthFact, &
Fact::valueChanged,
this, &CorridorScanComplexItem::_rebuildCorridorPolygon);
38 if (!kmlOrShpFile.isEmpty()) {
39 _corridorPolyline.loadKMLOrSHPFile(kmlOrShpFile);
40 _corridorPolyline.setDirty(
false);
47 QJsonObject saveObject;
49 _saveCommon(saveObject);
50 planItems.append(saveObject);
55 QJsonObject saveObject;
57 _saveCommon(saveObject);
61void CorridorScanComplexItem::_saveCommon(QJsonObject& saveObject)
69 saveObject[_jsonEntryPointKey] =
static_cast<int>(_entryPointLocation);
79 if (!_loadWorker(presetObject, 0,
errorString,
true )) {
85bool CorridorScanComplexItem::_loadWorker(
const QJsonObject& complexObject,
int sequenceNumber, QString&
errorString,
bool forPresets)
89 QList<JsonParsing::KeyValidateInfo> keyInfoList = {
94 { _jsonEntryPointKey, QJsonValue::Double,
true },
105 errorString = tr(
"%1 does not support loading this complex mission item type: %2:%3").arg(
qgcApp()->applicationName()).arg(itemType).arg(complexType);
133 _entryPointLocation =
static_cast<EntryPointLocation>(complexObject[_jsonEntryPointKey].toInt());
140 _recalcCameraShots();
153 return _corridorPolyline.
count() > 1;
164 const QList<QGeoCoordinate> vertices = _corridorPolyline.
coordinateList();
166 QList<QGeoCoordinate> translatedVertices;
167 translatedVertices.reserve(vertices.count());
168 for (
const QGeoCoordinate& vertex: vertices) {
169 translatedVertices.append(vertex.atDistanceAndAzimuth(distanceMeters, azimuthDegrees));
172 _corridorPolyline.
setPath(translatedVertices);
175int CorridorScanComplexItem::_calcTransectCount(
void)
const
177 double fullWidth = _corridorWidthFact.
rawValue().toDouble();
178 return fullWidth > 0.0 ? qCeil(fullWidth / _calcTransectSpacing()) : 1;
181void CorridorScanComplexItem::_polylineDirtyChanged(
bool dirty)
190 int modeAsInt =
static_cast<int>(_entryPointLocation);
192 if (_calcTransectCount() < 2) {
208void CorridorScanComplexItem::_rebuildCorridorPolygon(
void)
210 if (_corridorPolyline.
count() < 2) {
215 double halfWidth = _corridorWidthFact.
rawValue().toDouble() / 2.0;
217 QList<QGeoCoordinate> firstSideVertices = _corridorPolyline.
offsetPolyline(halfWidth);
218 QList<QGeoCoordinate> secondSideVertices = _corridorPolyline.
offsetPolyline(-halfWidth);
222 QList<QGeoCoordinate> rgCoord;
223 for (
const QGeoCoordinate& vertex: firstSideVertices) {
224 rgCoord.append(vertex);
226 for (
int i=secondSideVertices.count() - 1; i >= 0; i--) {
227 rgCoord.append(secondSideVertices[i]);
232void CorridorScanComplexItem::_rebuildTransectsPhase1(
void)
245 double transectSpacing = _calcTransectSpacing();
246 double fullWidth = _corridorWidthFact.
rawValue().toDouble();
247 double halfWidth = fullWidth / 2.0;
248 int transectCount = _calcTransectCount();
249 double normalizedTransectPosition = transectSpacing / 2.0;
251 if (_corridorPolyline.
count() >= 2) {
254 for (
int i=0; i<transectCount; i++) {
256 double offsetDistance;
257 if (transectCount == 1) {
262 offsetDistance = halfWidth - normalizedTransectPosition;
266 QList<TransectStyleComplexItem::CoordInfo_t> transect;
267 QList<QGeoCoordinate> transectCoords = _corridorPolyline.
offsetPolyline(offsetDistance);
268 for (
int j=1; j<transectCoords.count() - 1; j++) {
270 transect.append(coordInfo);
273 transect.prepend(coordInfo);
275 transect.append(coordInfo);
279 QGeoCoordinate turnaroundCoord;
282 double azimuth = transectCoords[0].azimuthTo(transectCoords[1]);
284 turnaroundCoord.setAltitude(qQNaN());
286 transect.prepend(turnaroundCoordInfo);
288 azimuth = transectCoords.last().azimuthTo(transectCoords[transectCoords.count() - 2]);
290 turnaroundCoord.setAltitude(qQNaN());
292 transect.append(coordInfo);
296 qDebug() <<
"transect debug";
303 normalizedTransectPosition += transectSpacing;
312 bool reverseTransects =
false;
313 bool reverseVertices =
false;
314 switch (_entryPointLocation) {
316 reverseTransects =
false;
317 reverseVertices =
false;
320 reverseTransects =
true;
321 reverseVertices =
false;
324 reverseTransects =
false;
325 reverseVertices =
true;
328 reverseTransects =
true;
329 reverseVertices =
true;
332 if (reverseTransects) {
333 QList<QList<TransectStyleComplexItem::CoordInfo_t>> reversedTransects;
334 for (
const QList<TransectStyleComplexItem::CoordInfo_t>& transect:
_transects) {
335 reversedTransects.prepend(transect);
339 if (reverseVertices) {
341 QList<TransectStyleComplexItem::CoordInfo_t> reversedVertices;
343 reversedVertices.prepend(vertex);
350 reverseVertices =
false;
353 QList<TransectStyleComplexItem::CoordInfo_t> transectVertices =
_transects[i];
354 if (reverseVertices) {
355 reverseVertices =
false;
356 QList<TransectStyleComplexItem::CoordInfo_t> reversedVertices;
357 for (
int j=transectVertices.count()-1; j>=0; j--) {
358 reversedVertices.append(transectVertices[j]);
368 transectVertices = reversedVertices;
370 reverseVertices =
true;
377void CorridorScanComplexItem::_recalcCameraShots(
void)
387 _cameraShots = singleTransectImageCount * _calcTransectCount();
403double CorridorScanComplexItem::_calcTransectSpacing(
void)
const
413 return transectSpacing;
416void 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)
Q_INVOKABLE void rotateEntryPoint(void)
@ EntryPointStartOppositeEndSameSide
@ EntryPointStartOppositeEndOppositeSide
@ EntryPointStartSameEndOppositeSide
static constexpr const char * jsonComplexItemTypeValue
ReadyForSaveState readyForSaveState(void) const final
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.
Q_INVOKABLE void clear(void)
Q_INVOKABLE 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
Provides access to group of settings.
static SettingsManager * instance()
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
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 showAppMessage(const QString &message, const QString &title)
Modal application message. Queued if the UI isn't ready yet.