Newer
Older
#include "WimaController.h"
const char* WimaController::wimaFileExtension = "wima";
const char* WimaController::areaItemsName = "AreaItems";
const char* WimaController::missionItemsName = "MissionItems";
WimaController::WimaController(QObject *parent) :
QObject (parent)
,_planView (true)
,_visualItems (new QmlObjectListModel(parent))
{
connect(this, &WimaController::currentPolygonIndexChanged, this, &WimaController::recalcPolygonInteractivity);
}
QStringList WimaController::loadNameFilters() const
{
QStringList filters;
filters << tr("Supported types (*.%1 *.%2)").arg(wimaFileExtension).arg(AppSettings::planFileExtension) <<
}
QStringList WimaController::saveNameFilters() const
{
QStringList filters;
filters << tr("Supported types (*.%1 *.%2)").arg(wimaFileExtension).arg(AppSettings::planFileExtension);
return filters;
void WimaController::setMasterController(PlanMasterController *masterC)
{
_masterController = masterC;
emit masterControllerChanged();
}
void WimaController::setMissionController(MissionController *missionC)
{
_missionController = missionC;
emit missionControllerChanged();
}
void WimaController::setCurrentPolygonIndex(int index)
{
if(index >= 0 && index < _visualItems->count() && index != _currentPolygonIndex){
_currentPolygonIndex = index;
emit currentPolygonIndexChanged(index);
}
}
void WimaController::removeArea(int index)
{
if(index >= 0 && index < _visualItems->count()){
WimaArea* area = qobject_cast<WimaArea*>(_visualItems->removeAt(index));
if ( area == nullptr) {
qWarning("WimaController::removeArea(): nullptr catched, internal error.");
return;
}
disconnect(area, &WimaArea::pathChanged, this, &WimaController::updateJoinedArea);
if (_visualItems->count() == 0) {
// this branch is reached if all items are removed
// to guarentee proper behavior, _currentPolygonIndex must be set to a invalid value, as on constructor init.
_currentPolygonIndex = -1;
return;
}
if(_currentPolygonIndex >= _visualItems->count()){
setCurrentPolygonIndex(_visualItems->count() - 1);
}else{
recalcPolygonInteractivity(_currentPolygonIndex);
}
}else{
qWarning("Index out of bounds!");
}
}
bool WimaController::addGOperationArea()
// check if opArea exists already
WimaGOperationArea* opArea = nullptr;
for (int i = 0; i < _visualItems->count(); i++) {
WimaGOperationArea* currentArea = qobject_cast<WimaGOperationArea*>(_visualItems->get(i));
if ( currentArea != nullptr ) {
opArea = currentArea;
return false;
}
}
// create one if no opArea available
opArea = new WimaGOperationArea(this);
connect(opArea, &WimaGOperationArea::pathChanged, this, &WimaController::updateJoinedArea);
_visualItems->append(opArea);
int newIndex = _visualItems->count()-1;
setCurrentPolygonIndex(newIndex);
return true;
bool WimaController::addServiceArea()
// check if serArea exists already
WimaServiceArea* serArea = nullptr;
for (int i = 0; i < _visualItems->count(); i++) {
WimaServiceArea* currentArea = qobject_cast<WimaServiceArea*>(_visualItems->get(i));
if ( currentArea != nullptr ) {
serArea = currentArea;
return false;
}
}
// create one if no serArea available
serArea = new WimaServiceArea(this);
connect(serArea, &WimaServiceArea::pathChanged, this, &WimaController::updateJoinedArea);
_visualItems->append(serArea);
int newIndex = _visualItems->count()-1;
setCurrentPolygonIndex(newIndex);
return true;
bool WimaController::addVehicleCorridor()
// check if corridor exists already
WimaVCorridor* corridor = nullptr;
for (int i = 0; i < _visualItems->count(); i++) {
WimaVCorridor* currentArea = qobject_cast<WimaVCorridor*>(_visualItems->get(i));
if ( currentArea != nullptr ) {
corridor = currentArea;
return false;
}
}
// create one if no corridor available
corridor = new WimaVCorridor(this);
connect(corridor, &WimaVCorridor::pathChanged, this, &WimaController::updateJoinedArea);
_visualItems->append(corridor);
int newIndex = _visualItems->count()-1;
setCurrentPolygonIndex(newIndex);
return true;
void WimaController::removeAll()
{
bool changesApplied = false;
while (_visualItems->count() > 0) {
removeArea(0);
_missionController->removeAll();
_currentFile = "";
emit currentFileChanged();
if ( changesApplied )
emit visualItemsChanged();
}
void WimaController::startMission()
{
}
void WimaController::abortMission()
{
}
void WimaController::pauseMission()
{
}
void WimaController::resumeMission()
{
}
bool WimaController::updateMission()
{
// pick first WimaGOperationArea
WimaGOperationArea* opArea = nullptr;
for (int i = 0; i < _visualItems->count(); i++) {
WimaGOperationArea* currentArea = qobject_cast<WimaGOperationArea*>(_visualItems->get(i));
if (currentArea != nullptr){
opArea = currentArea;
break;
}
}
// pick first WimaServiceArea
WimaServiceArea* serArea = nullptr;
for (int i = 0; i < _visualItems->count(); i++) {
WimaServiceArea* currentArea = qobject_cast<WimaServiceArea*>(_visualItems->get(i));
if (currentArea != nullptr){
serArea = currentArea;
break;
}
}
// pick first WimaVCorridor
WimaVCorridor* corridor = nullptr;
for (int i = 0; i < _visualItems->count(); i++) {
WimaVCorridor* currentArea = qobject_cast<WimaVCorridor*>(_visualItems->get(i));
if (currentArea != nullptr){
corridor = currentArea;
break;
#if debug
WimaArea* joinedAreaPt = new WimaArea(joinedArea, this);
_visualItems->append(joinedAreaPt);
#endif
// reset visual items
_missionController->removeAll();
QmlObjectListModel* missionItems = _missionController->visualItems();
// set home position to serArea center
MissionSettingsItem* settingsItem= qobject_cast<MissionSettingsItem*>(missionItems->get(0));
if (settingsItem == nullptr){
qWarning("WimaController::updateMission(): settingsItem == nullptr");
return false;
}
// set altitudes, temporary measure to solve bugs
QGeoCoordinate center = serArea->center();
center.setAltitude(0);
serArea->setCenter(center);
center = opArea->center();
center.setAltitude(0);
opArea->setCenter(center);
center = corridor->center();
center.setAltitude(0);
corridor->setCenter(center);
// set HomePos. to serArea center
settingsItem->setCoordinate(serArea->center());
int sequenceNumber = _missionController->insertSimpleMissionItem(serArea->center(), missionItems->count());
_missionController->setCurrentPlanViewIndex(sequenceNumber, true);
// create survey item, will be extened with more mission types in the future
_missionController->insertComplexMissionItem(_missionController->surveyComplexItemName(), opArea->center(), missionItems->count());
SurveyComplexItem* survey = qobject_cast<SurveyComplexItem*>(missionItems->get(missionItems->count()-1));
if (survey == nullptr){
qWarning("WimaController::updateMission(): survey == nullptr");
} else {
survey->surveyAreaPolygon()->clear();
survey->surveyAreaPolygon()->appendVertices(opArea->coordinateList());
//survey->
// calculate path from take off to opArea
QGeoCoordinate start = serArea->center();
QGeoCoordinate end = survey->visualTransectPoints().first().value<QGeoCoordinate>();
QList<QGeoCoordinate> path;
WimaArea::dijkstraPath(start, end, _joinedArea, path);
sequenceNumber = _missionController->insertSimpleMissionItem(path.value(i), missionItems->count()-1);
_missionController->setCurrentPlanViewIndex(sequenceNumber, true);
}
// calculate return path
start = survey->visualTransectPoints().last().value<QGeoCoordinate>();
end = serArea->center();
path.clear();
WimaArea::dijkstraPath(start, end, _joinedArea, path);
sequenceNumber = _missionController->insertSimpleMissionItem(path.value(i), missionItems->count());
_missionController->setCurrentPlanViewIndex(sequenceNumber, true);
// create land position item
sequenceNumber = _missionController->insertSimpleMissionItem(serArea->center(), missionItems->count());
_missionController->setCurrentPlanViewIndex(sequenceNumber, true);
SimpleMissionItem* landItem = qobject_cast<SimpleMissionItem*>(missionItems->get(missionItems->count()-1));
if (landItem == nullptr){
qWarning("WimaController::updateMission(): landItem == nullptr");
return false;
} else {
Vehicle* controllerVehicle = _masterController->controllerVehicle();
MAV_CMD landCmd = controllerVehicle->vtol() ? MAV_CMD_NAV_VTOL_LAND : MAV_CMD_NAV_LAND;
if (controllerVehicle->firmwarePlugin()->supportedMissionCommands().contains(landCmd)) {
landItem->setCommand(landCmd);
}
void WimaController::saveToFile(const QString& filename)
{
if (filename.isEmpty()) {
return;
}
QString planFilename = filename;
if (!QFileInfo(filename).fileName().contains(".")) {
planFilename += QString(".%1").arg(wimaFileExtension);
}
QFile file(planFilename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qgcApp()->showMessage(tr("Plan save error %1 : %2").arg(filename).arg(file.errorString()));
_currentFile.clear();
emit currentFileChanged();
} else {
FileType fileType = FileType::WimaFile;
if ( planFilename.contains(QString(".%1").arg(wimaFileExtension)) ) {
fileType = FileType::WimaFile;
} else if ( planFilename.contains(QString(".%1").arg(AppSettings::planFileExtension)) ) {
fileType = FileType::PlanFile;
} else {
if ( planFilename.contains(".") ) {
qgcApp()->showMessage(tr("File format not supported"));
} else {
qgcApp()->showMessage(tr("File without file extension not accepted."));
return;
}
}
QJsonDocument saveDoc = saveToJson(fileType);
file.write(saveDoc.toJson());
if(_currentFile != planFilename) {
_currentFile = planFilename;
emit currentFileChanged();
}
}
}
return loadFromFile(_currentFile);
}
bool WimaController::loadFromFile(const QString &filename)
{
#define debug 0
QString errorString;
QString errorMessage = tr("Error loading Plan file (%1). %2").arg(filename).arg("%1");
if (filename.isEmpty()) {
return false;
}
QFileInfo fileInfo(filename);
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
errorString = file.errorString() + QStringLiteral(" ") + filename;
qgcApp()->showMessage(errorMessage.arg(errorString));
return false;
}
if(fileInfo.suffix() == wimaFileExtension) {
QJsonDocument jsonDoc;
QByteArray bytes = file.readAll();
if (!JsonHelper::isJsonFile(bytes, jsonDoc, errorString)) {
qgcApp()->showMessage(errorMessage.arg(errorString));
return false;
}
QJsonObject json = jsonDoc.object();
// AreaItems
QJsonArray areaArray = json[areaItemsName].toArray();
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
_visualItems->clear();
for( int i = 0; i < areaArray.size(); i++) {
QJsonObject jsonArea = areaArray[i].toObject();
if (jsonArea.contains(WimaArea::areaTypeName) && jsonArea[WimaArea::areaTypeName].isString()) {
if ( jsonArea[WimaArea::areaTypeName] == WimaArea::wimaAreaName ) {
WimaArea* area = new WimaArea(this);
bool success = area->loadFromJson(jsonArea, errorString);
if ( !success ) {
qgcApp()->showMessage(errorMessage.arg(errorString));
return false;
}
_visualItems->append(area);
emit visualItemsChanged();
} else if ( jsonArea[WimaArea::areaTypeName] == WimaGOperationArea::wimaGOperationAreaName) {
WimaGOperationArea* opArea = new WimaGOperationArea(this);
bool success = opArea->loadFromJson(jsonArea, errorString);
if ( !success ) {
qgcApp()->showMessage(errorMessage.arg(errorString));
return false;
}
_visualItems->append(opArea);
emit visualItemsChanged();
} else if ( jsonArea[WimaArea::areaTypeName] == WimaServiceArea::wimaServiceAreaName) {
WimaServiceArea* serArea = new WimaServiceArea(this);
bool success = serArea->loadFromJson(jsonArea, errorString);
if ( !success ) {
qgcApp()->showMessage(errorMessage.arg(errorString));
return false;
}
_visualItems->append(serArea);
emit visualItemsChanged();
} else if ( jsonArea[WimaArea::areaTypeName] == WimaVCorridor::wimaVCorridorName) {
WimaVCorridor* corridor = new WimaVCorridor(this);
bool success = corridor->loadFromJson(jsonArea, errorString);
if ( !success ) {
qgcApp()->showMessage(errorMessage.arg(errorString));
return false;
}
_visualItems->append(corridor);
emit visualItemsChanged();
} else {
errorString += QString(tr("%s not supported.\n").arg(WimaArea::areaTypeName));
qgcApp()->showMessage(errorMessage.arg(errorString));
return false;
}
} else {
errorString += QString(tr("Invalid or non existing entry for %s.\n").arg(WimaArea::areaTypeName));
return false;
}
}
_currentFile.sprintf("%s/%s.%s", fileInfo.path().toLocal8Bit().data(), fileInfo.completeBaseName().toLocal8Bit().data(), wimaFileExtension);
emit currentFileChanged();
updateJoinedArea();
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
// MissionItems
// extrac MissionItems part
QJsonDocument missionJsonDoc = QJsonDocument(json[missionItemsName].toObject());
// create temporary file with missionItems
QFile temporaryFile;
QString cropedFileName = filename.section("/",0,-2);
#if debug
qWarning() << cropedFileName;
#endif
QString temporaryFileName;
for (int i = 0; ; i++) {
temporaryFileName = cropedFileName.append("/temp%1.%2").arg(i).arg(AppSettings::planFileExtension);
if ( !QFile::exists(temporaryFileName) ) {
temporaryFile.setFileName(temporaryFileName);
if ( temporaryFile.open(QIODevice::WriteOnly | QIODevice::Text) ) {
break;
}
}
if ( i > 1000) {
qWarning("WimaController::loadFromFile(): not able to create temporary file.");
return false;
}
}
temporaryFile.write(missionJsonDoc.toJson());
// load from temporary file
_masterController->loadFromFile(temporaryFileName);
// remove temporary file
if ( !temporaryFile.remove() ){
qWarning("WimaController::loadFromFile(): not able to remove temporary file.");
}
} else if ( fileInfo.suffix() == AppSettings::planFileExtension ){
_masterController->loadFromFile(filename);
return true;// might be wrong return value
} else {
errorString += QString(tr("File extension not supported.\n"));
qgcApp()->showMessage(errorMessage.arg(errorString));
}
void WimaController::recalcVehicleCorridor()
void WimaController::recalcVehicleMeasurementAreas()
{
}
void WimaController::recalcAll()
{
}
void WimaController::recalcPolygonInteractivity(int index)
{
if (index >= 0 && index < _visualItems->count()) {
resetAllInteractive();
WimaArea* interactivePoly = qobject_cast<WimaArea*>(_visualItems->get(index));
interactivePoly->setInteractive(true);
}
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
void WimaController::updateJoinedArea()
{
// pick first WimaGOperationArea
WimaGOperationArea* opArea = nullptr;
for (int i = 0; i < _visualItems->count(); i++) {
WimaGOperationArea* currentArea = qobject_cast<WimaGOperationArea*>(_visualItems->get(i));
if (currentArea != nullptr){
opArea = currentArea;
break;
}
}
if (opArea == nullptr)
return;
// pick first WimaServiceArea
WimaServiceArea* serArea = nullptr;
for (int i = 0; i < _visualItems->count(); i++) {
WimaServiceArea* currentArea = qobject_cast<WimaServiceArea*>(_visualItems->get(i));
if (currentArea != nullptr){
serArea = currentArea;
break;
}
}
if ( serArea == nullptr )
return;
// pick first WimaVCorridor
WimaVCorridor* corridor = nullptr;
for (int i = 0; i < _visualItems->count(); i++) {
WimaVCorridor* currentArea = qobject_cast<WimaVCorridor*>(_visualItems->get(i));
if (currentArea != nullptr){
corridor = currentArea;
break;
}
}
// join service area, op area and corridor
if (corridor != nullptr) {
WimaArea::join(*serArea, *corridor, _joinedArea);
_joinedArea.join(*opArea);
} else {
WimaArea::join(*serArea, *opArea, _joinedArea);
}
emit joinedAreaChanged() ;
}
void WimaController::resetAllInteractive()
{
int itemCount = _visualItems->count();
if (itemCount > 0){
for (int i = 0; i < itemCount; i++) {
WimaArea* iteratorPoly = qobject_cast<WimaArea*>(_visualItems->get(i));
iteratorPoly->setInteractive(false);
}
void WimaController::setInteractive()
{
recalcPolygonInteractivity(_currentPolygonIndex);
}
QJsonDocument WimaController::saveToJson(FileType fileType)
QJsonObject json;
if ( fileType == FileType::WimaFile ) {
QJsonArray jsonArray;
for (int i = 0; i < _visualItems->count(); i++) {
QJsonObject json;
WimaArea* area = qobject_cast<WimaArea*>(_visualItems->get(i));
if (area == nullptr) {
qWarning("WimaController::saveToJson(): Internal error, area == nullptr!");
return QJsonDocument();
}
WimaGOperationArea* opArea = qobject_cast<WimaGOperationArea*>(area);
if (opArea != nullptr) {
opArea->saveToJson(json);
jsonArray.append(json);
continue;
}
WimaServiceArea* serArea = qobject_cast<WimaServiceArea*>(area);
if (serArea != nullptr) {
serArea->saveToJson(json);
jsonArray.append(json);
continue;
}
WimaVCorridor* corridor = qobject_cast<WimaVCorridor*>(area);
if (corridor != nullptr) {
corridor->saveToJson(json);
jsonArray.append(json);
continue;
}
// if non of the obove branches was trigger, type must be WimaArea
area->saveToJson(json);
json[areaItemsName] = jsonArray;
json[missionItemsName] = _masterController->saveToJson().object();
return QJsonDocument(json);
} else if (fileType == FileType::PlanFile) {
return _masterController->saveToJson();