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)
, _flyView (true)
, _readyForSaveSend (false)
, _currentPolygonIndex (-1)
, _container (nullptr)
, _joinedArea (this)
, _opArea (this)
, _serArea (this)
, _corridor (this)
{
connect(this, &WimaController::currentPolygonIndexChanged, this, &WimaController::recalcPolygonInteractivity);
}
const QmlObjectListModel* WimaController::visualItems() const
{
}
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;
QGeoCoordinate WimaController::joinedAreaCenter() const
{
return _joinedArea.center();
}
WimaArea WimaController::joinedArea() const
{
}
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::setDataContainer(WimaDataContainer *container)
{
if (_container == nullptr && container != nullptr) {
if (_flyView) {
downloadFromContainer();
_visualItems.append(&_opArea);
_visualItems.append(&_serArea);
_visualItems.append(&_joinedArea);
connect(_container, &WimaDataContainer::opAreaChanged, this, &WimaController::setOpArea);
connect(_container, &WimaDataContainer::serAreaChanged, this, &WimaController::setSerArea);
connect(_container, &WimaDataContainer::corridorChanged, this, &WimaController::setCorridor);
connect(_container, &WimaDataContainer::joinedAreaChanged, this, &WimaController::setJoinedArea);
}
emit dataContainerChanged();
}
}
void WimaController::startWimaController(bool flyView)
{
_flyView = flyView;
}
void WimaController::removeArea(int index)
{
if(index >= 0 && index < _visualItems.count()){
if (_flyView) { //not editing allowed in flyView
return;
}
WimaArea* area = qobject_cast<WimaArea*>(_visualItems.removeAt(index));
if ( area == nullptr) {
qWarning("WimaController::removeArea(): nullptr catched, internal error.");
return;
}
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()
if (!_flyView && !_visualItems.contains(&_opArea)) {
_visualItems.append(&_opArea);
int newIndex = _visualItems.count()-1;
setCurrentPolygonIndex(newIndex);
emit visualItemsChanged();
return true;
} else {
return false;
}
bool WimaController::addServiceArea()
if (!_flyView && !_visualItems.contains(&_serArea)) {
_visualItems.append(&_serArea);
int newIndex = _visualItems.count()-1;
setCurrentPolygonIndex(newIndex);
emit visualItemsChanged();
return true;
} else {
return false;
}
bool WimaController::addVehicleCorridor()
if (!_flyView && !_visualItems.contains(&_corridor)) {
_visualItems.append(&_corridor);
int newIndex = _visualItems.count()-1;
setCurrentPolygonIndex(newIndex);
emit visualItemsChanged();
return true;
} else {
return false;
}
void WimaController::removeAll()
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()
{
if (!_flyView) {
setReadyForSaveSend(false);
#define debug 0
if ( !updateJoinedArea()) {
qgcApp()->showMessage(tr("Not able to join areas. Areas must be overlapping"));
return false;
#if debug
_visualItems.append(&_joinedArea);
#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());
// create take off position item
int sequenceNumber = _missionController->insertSimpleMissionItem(_serArea.center(), missionItems->count());
_missionController->setCurrentPlanViewIndex(sequenceNumber, true);
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
// 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");
return false;
} 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;
if ( !WimaArea::dijkstraPath(start, end, _joinedArea, path)) {
qgcApp()->showMessage(tr("Not able to calculate the path from takeoff position to measurement area."));
return false;
}
for (int i = 1; i < path.count()-1; i++) {
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();
if ( ! WimaArea::dijkstraPath(start, end, _joinedArea, path)) {
qgcApp()->showMessage(tr("Not able to calculate the path from measurement area to landing position."));
return false;
}
for (int i = 1; i < path.count()-1; i++) {
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);
}
}
updateContainer();
setReadyForSaveSend(true);
return true;
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();
_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] == WimaGOperationArea::wimaGOperationAreaName) {
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) {
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) {
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();
463
464
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
// 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::recalcPolygonInteractivity(int index)
if (index >= 0 && index < _visualItems.count()) {
resetAllInteractive();
WimaArea* interactivePoly = qobject_cast<WimaArea*>(_visualItems.get(index));
interactivePoly->setInteractive(true);
}
bool WimaController::updateJoinedArea()
// join service area, op area and corridor
_joinedArea = _serArea;
_joinedArea.join(_corridor);
if ( !_joinedArea.join(_opArea) )
return false;
else {
emit joinedAreaChanged() ;
return true;
}
void WimaController::updateContainer()
if (_container != nullptr) {
_container->setOpArea(_opArea);
_container->setSerArea(_serArea);
_container->setCorridor(_corridor);
_container->setJoinedArea(_joinedArea);
} else {
qWarning("WimaController::uploadToContainer(): no container assigned.");
void WimaController::downloadFromContainer()
if (_flyView) {
_opArea = _container->opArea();
_serArea = _container->serArea();
_corridor = _container->corridor();
_joinedArea = _container->joinedArea();
void WimaController::setOpArea(const WimaGOperationArea &area)
{
if (_flyView) {
_opArea = area;
void WimaController::setSerArea(const WimaServiceArea &area)
{
if (_flyView) {
_serArea = area;
void WimaController::setCorridor(const WimaVCorridor &area)
{
if (_flyView) {
_corridor = area;
}
}
void WimaController::setJoinedArea(const WimaArea &area)
{
if (_flyView) {
_joinedArea = area;
}
}
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();
void WimaController::setReadyForSaveSend(bool ready)
{
if (ready != _readyForSaveSend) {
_readyForSaveSend = ready;
emit readyForSaveSendChanged(ready);
}
}