Newer
Older
const char* WimaController::wimaFileExtension = "wima";
const char* WimaController::areaItemsName = "AreaItems";
const char* WimaController::missionItemsName = "MissionItems";
const char* WimaController::settingsGroup = "WimaController";
const char* WimaController::enableWimaControllerName = "EnableWimaController";
const char* WimaController::overlapWaypointsName = "OverlapWaypoints";
const char* WimaController::maxWaypointsPerPhaseName = "MaxWaypointsPerPhase";
const char* WimaController::startWaypointIndexName = "StartWaypointIndex";
const char* WimaController::showAllMissionItemsName = "ShowAllMissionItems";
const char* WimaController::showCurrentMissionItemsName = "ShowCurrentMissionItems";
WimaController::WimaController(QObject *parent)
: QObject (parent)
, _container (nullptr)
, _joinedArea (this)
, _measurementArea (this)
, _serviceArea (this)
, _corridor (this)
, _localPlanDataValid (false)
, _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/WimaController.SettingsGroup.json"), this))
, _enableWimaController (settingsGroup, _metaDataMap[enableWimaControllerName])
, _overlapWaypoints (settingsGroup, _metaDataMap[overlapWaypointsName])
, _maxWaypointsPerPhase (settingsGroup, _metaDataMap[maxWaypointsPerPhaseName])
, _nextPhaseStartWaypointIndex (settingsGroup, _metaDataMap[startWaypointIndexName])
, _showAllMissionItems (settingsGroup, _metaDataMap[showAllMissionItemsName])
, _showCurrentMissionItems (settingsGroup, _metaDataMap[showCurrentMissionItemsName])
_nextPhaseStartWaypointIndex.setRawValue(int(1));
_showAllMissionItems.setRawValue(true);
_showCurrentMissionItems.setRawValue(true);
connect(&_overlapWaypoints, &Fact::rawValueChanged, this, &WimaController::updateNextWaypoint);
connect(&_maxWaypointsPerPhase, &Fact::rawValueChanged, this, &WimaController::recalcCurrentPhase);
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
Valentin Platzgummer
committed
QmlObjectListModel* WimaController::visualItems()
{
}
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;
WimaDataContainer *WimaController::dataContainer()
{
Valentin Platzgummer
committed
return _container;
}
QmlObjectListModel *WimaController::missionItems()
{
return &_missionItems;
}
QmlObjectListModel *WimaController::currentMissionItems()
{
return &_currentMissionItems;
}
QVariantList WimaController::waypointPath()
{
return _waypointPath;
}
QVariantList WimaController::currentWaypointPath()
{
return _currentWaypointPath;
}
Fact *WimaController::enableWimaController()
{
return &_enableWimaController;
}
Fact *WimaController::overlapWaypoints()
{
return &_overlapWaypoints;
}
Fact *WimaController::maxWaypointsPerPhase()
{
return &_maxWaypointsPerPhase;
}
Fact *WimaController::showAllMissionItems()
{
return &_showAllMissionItems;
}
Fact *WimaController::showCurrentMissionItems()
{
return &_showCurrentMissionItems;
}
Fact *WimaController::startWaypointIndex()
{
void WimaController::setMasterController(PlanMasterController *masterC)
{
_masterController = masterC;
emit masterControllerChanged();
}
void WimaController::setMissionController(MissionController *missionC)
{
_missionController = missionC;
emit missionControllerChanged();
}
Valentin Platzgummer
committed
/*!
* \fn void WimaController::setDataContainer(WimaDataContainer *container)
* Sets the pointer to the \c WimaDataContainer, which is meant to exchange data between the \c WimaController and the \c WimaPlaner.
*
* \sa WimaPlaner, WimaDataContainer, WimaPlanData
*/
void WimaController::setDataContainer(WimaDataContainer *container)
{
Valentin Platzgummer
committed
if (container != nullptr) {
if (_container != nullptr) {
disconnect(_container, &WimaDataContainer::newDataAvailable, this, &WimaController::fetchContainerData);
Valentin Platzgummer
committed
}
connect(_container, &WimaDataContainer::newDataAvailable, this, &WimaController::fetchContainerData);
emit dataContainerChanged();
}
}
void WimaController::nextPhase()
{
Valentin Platzgummer
committed
void WimaController::previousPhase()
{
if (_nextPhaseStartWaypointIndex.rawValue().toInt() > 0) {
_lastMissionPhaseReached = false;
_nextPhaseStartWaypointIndex.setRawValue( 1 + std::max(_startWaypointIndex
- _maxWaypointsPerPhase.rawValue().toInt()
+ _overlapWaypoints.rawValue().toInt(), 0));
Valentin Platzgummer
committed
}
void WimaController::resetPhase()
{
_lastMissionPhaseReached = false;
_nextPhaseStartWaypointIndex.setRawValue(int(1));
Valentin Platzgummer
committed
}
Valentin Platzgummer
committed
{
if (_currentMissionItems.count() < 1)
_missionController->removeAll();
// set homeposition of settingsItem
QmlObjectListModel* visuals = _missionController->visualItems();
MissionSettingsItem* settingsItem = visuals->value<MissionSettingsItem *>(0);
if (settingsItem == nullptr) {
qWarning("WimaController::updateCurrentMissionItems(): nullptr");
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
}
settingsItem->setCoordinate(_takeoffLandPostion);
// copy mission items from _currentMissionItems to _missionController
for (int i = 0; i < _currentMissionItems.count(); i++){
SimpleMissionItem *item = _currentMissionItems.value<SimpleMissionItem *>(i);
_missionController->insertSimpleMissionItem(*item, visuals->count());
}
// // set land command for last mission item
// SimpleMissionItem *landItem = visuals->value<SimpleMissionItem*>(visuals->count()-1);
// if (landItem == nullptr) {
// qWarning("WimaController::uploadToVehicle(): nullptr");
// _missionController->removeAll();
// return;
// }
// // check vehicle type, before setting land command
// 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);
// } else {
// _missionController->removeAll();
// return;
// }
for (int i = 1; i < visuals->count(); i++) {
SimpleMissionItem* item = visuals->value<SimpleMissionItem *>(i);
qWarning() << item->coordinate();
qWarning() << item->command();
qWarning() << item->missionItem().param1();
qWarning() << item->missionItem().param2();
qWarning() << item->missionItem().param3();
qWarning() << item->missionItem().param4();
qWarning() << item->missionItem().param5();
qWarning() << item->missionItem().param6();
qWarning() << item->missionItem().param7();
qWarning(" ");
}
Valentin Platzgummer
committed
void WimaController::removeFromVehicle()
{
_masterController->removeAllFromVehicle();
Valentin Platzgummer
committed
}
void WimaController::saveToFile(const QString& filename)
{
}
bool WimaController::loadFromFile(const QString &filename)
{
QJsonDocument WimaController::saveToJson(FileType fileType)
Valentin Platzgummer
committed
return QJsonDocument();
bool WimaController::calcShortestPath(const QGeoCoordinate &start, const QGeoCoordinate &destination, QList<QGeoCoordinate> &path)
{
using namespace GeoUtilities;
using namespace PolygonCalculus;
QList<QPointF> path2D;
bool retVal = PolygonCalculus::shortestPath(
toQPolygonF(toCartesian2D(_joinedArea.coordinateList(), /*origin*/ start)),
/*start point*/ QPointF(0,0),
/*destination*/ toCartesian2D(destination, start),
/*shortest path*/ path2D);
path.append(toGeo(path2D, /*origin*/ start));
return retVal;
}
bool WimaController::extractCoordinateList(QmlObjectListModel &missionItems, QList<QGeoCoordinate> &coordinateList)
{
return extractCoordinateList(missionItems, coordinateList, 0, missionItems.count()-1);
}
bool WimaController::extractCoordinateList(QmlObjectListModel &missionItems, QList<QGeoCoordinate> &coordinateList, int startIndex, int endIndex)
{
if ( startIndex >= 0
&& startIndex < missionItems.count()
&& endIndex >= 0
&& endIndex < missionItems.count()) {
if (startIndex > endIndex) {
if (!extractCoordinateList(missionItems, coordinateList, startIndex, missionItems.count()-1))
return false;
if (!extractCoordinateList(missionItems, coordinateList, 0, endIndex))
return false;
} else {
for (int i = startIndex; i <= endIndex; i++) {
SimpleMissionItem *mItem = missionItems.value<SimpleMissionItem *>(i);
if (mItem == nullptr) {
coordinateList.clear();
return false;
}
coordinateList.append(mItem->coordinate());
}
}
} else
return false;
return true;
}
bool WimaController::extractCoordinateList(QmlObjectListModel &missionItems, QVariantList &coordinateList)
{
return extractCoordinateList(missionItems, coordinateList, 0 , missionItems.count()-1);
}
bool WimaController::extractCoordinateList(QmlObjectListModel &missionItems, QVariantList &coordinateList, int startIndex, int endIndex)
{
QList<QGeoCoordinate> geoCoordintateList;
bool retValue = extractCoordinateList(missionItems, geoCoordintateList, startIndex, endIndex);
if (!retValue)
return false;
for (auto coordinate : geoCoordintateList)
coordinateList.append(QVariant::fromValue(coordinate));
return true;
}
Valentin Platzgummer
committed
/*!
* \fn void WimaController::containerDataValidChanged(bool valid)
* Pulls plan data generated by \c WimaPlaner from the \c _container if the data is valid (\a valid equals true).
* Is connected to the dataValidChanged() signal of the \c WimaDataContainer.
*
* \sa WimaDataContainer, WimaPlaner, WimaPlanData
*/
Valentin Platzgummer
committed
// reset visual items
_visualItems.clear();
_missionItems.clear();
_currentMissionItems.clear();
_waypointPath.clear();
_currentWaypointPath.clear();
Valentin Platzgummer
committed
emit visualItemsChanged();
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit currentWaypointPathChanged();
Valentin Platzgummer
committed
_localPlanDataValid = false;
_lastMissionPhaseReached = false;
Valentin Platzgummer
committed
if (_container == nullptr) {
qWarning("WimaController::fetchContainerData(): No container assigned!");
return false;
}
Valentin Platzgummer
committed
Valentin Platzgummer
committed
// extract list with WimaAreas
QList<const WimaAreaData*> areaList = planData.areaList();
Valentin Platzgummer
committed
int areaCounter = 0;
int numAreas = 4; // extract only numAreas Areas, if there are more they are invalid and ignored
for (int i = 0; i < areaList.size(); i++) {
const WimaAreaData *areaData = areaList[i];
Valentin Platzgummer
committed
if (areaData->type() == WimaServiceAreaData::typeString) { // is it a service area?
_serviceArea = *qobject_cast<const WimaServiceAreaData*>(areaData);
areaCounter++;
_visualItems.append(&_serviceArea);
Valentin Platzgummer
committed
Valentin Platzgummer
committed
if (areaData->type() == WimaMeasurementAreaData::typeString) { // is it a measurement area?
_measurementArea = *qobject_cast<const WimaMeasurementAreaData*>(areaData);
areaCounter++;
_visualItems.append(&_measurementArea);
Valentin Platzgummer
committed
Valentin Platzgummer
committed
}
if (areaData->type() == WimaCorridorData::typeString) { // is it a corridor?
_corridor = *qobject_cast<const WimaCorridorData*>(areaData);
areaCounter++;
//_visualItems.append(&_corridor); // not needed
Valentin Platzgummer
committed
Valentin Platzgummer
committed
if (areaData->type() == WimaJoinedAreaData::typeString) { // is it a corridor?
_joinedArea = *qobject_cast<const WimaJoinedAreaData*>(areaData);
areaCounter++;
_visualItems.append(&_joinedArea);
Valentin Platzgummer
committed
Valentin Platzgummer
committed
Valentin Platzgummer
committed
// extract mission items
QList<const MissionItem*> tempMissionItems = planData.missionItems();
if (tempMissionItems.size() < 1)
return false;
Valentin Platzgummer
committed
// create mission items
_missionController->removeAll();
QmlObjectListModel* missionControllerVisualItems = _missionController->visualItems();
// create SimpleMissionItem by using _missionController
for ( int i = 0; i < tempMissionItems.size(); i++) {
const MissionItem *missionItem = tempMissionItems[i];
_missionController->insertSimpleMissionItem(*missionItem, missionControllerVisualItems->count());
}
// copy mission items from _missionController to _missionItems
for ( int i = 1; i < missionControllerVisualItems->count(); i++) {
SimpleMissionItem *visualItem = qobject_cast<SimpleMissionItem *>((*missionControllerVisualItems)[i]);
if (visualItem == nullptr) {
qWarning("WimaController::fetchContainerData(): Nullptr at SimpleMissionItem!");
return false;
Valentin Platzgummer
committed
}
SimpleMissionItem *visualItemCopy = new SimpleMissionItem(*visualItem, true, this);
_missionItems.append(visualItemCopy);
}
if (areaCounter != numAreas)
return false;
Valentin Platzgummer
committed
if (!setTakeoffLandPosition())
return false;
// set _nextPhaseStartWaypointIndex to 1
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
_nextPhaseStartWaypointIndex.setRawValue(int(1));
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
_localPlanDataValid = true;
return true;
if (_missionItems.count() < 1 || _lastMissionPhaseReached)
return false;
_currentMissionItems.clear();
_currentWaypointPath.clear();
emit currentMissionItemsChanged();
emit currentWaypointPathChanged();
_startWaypointIndex = _nextPhaseStartWaypointIndex.rawValue().toInt()-1;
if (_startWaypointIndex > _missionItems.count()-1)
return false;
Valentin Platzgummer
committed
int maxWaypointsPerPhaseInt = _maxWaypointsPerPhase.rawValue().toInt();
// determine end waypoint index
_endWaypointIndex = std::min(_startWaypointIndex + maxWaypointsPerPhaseInt - 1, _missionItems.count()-1);
if (_endWaypointIndex == _missionItems.count() - 1)
_lastMissionPhaseReached = true;
QList<QGeoCoordinate> geoCoordinateList; // list with potential waypoints (from _missionItems), for _currentMissionItems
if (!extractCoordinateList(_missionItems, geoCoordinateList, _startWaypointIndex, _endWaypointIndex)) {
qWarning("WimaController::calcNextPhase(): error on waypoint extraction.");
return false;
// set start waypoint index for next phase
if (!_lastMissionPhaseReached) {
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
int untruncated = std::max(_endWaypointIndex + 1 - _overlapWaypoints.rawValue().toInt(), 0);
int truncated = std::min(untruncated , _missionItems.count()-1);
_nextPhaseStartWaypointIndex.setRawValue(truncated + 1);
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
// calculate path from home to first waypoint
QList<QGeoCoordinate> path;
if (!_takeoffLandPostion.isValid()){
qWarning("WimaController::calcNextPhase(): _takeoffLandPostion not valid.");
return false;
}
Valentin Platzgummer
committed
if ( !calcShortestPath(_takeoffLandPostion, geoCoordinateList[0], path) ) {
qWarning("WimaController::calcNextPhase(): Not able to calc path from home to first waypoint.");
return false;
}
// prepend to geoCoordinateList
for (int i = path.size()-2; i >= 0; i--) // i = path.size()-2 : last coordinate already in geoCoordinateList
geoCoordinateList.prepend(path[i]);
// calculate path from last waypoint to home
path.clear();
Valentin Platzgummer
committed
if ( !calcShortestPath(geoCoordinateList.last(), _takeoffLandPostion, path) ) {
qWarning("WimaController::calcNextPhase(): Not able to calc path from home to first waypoint.");
return false;
}
path.removeFirst(); // first coordinate already in geoCoordinateList
geoCoordinateList.append(path);
Valentin Platzgummer
committed
// create Mission Items
_missionController->removeAll();
QmlObjectListModel* missionControllerVisuals = _missionController->visualItems();
Valentin Platzgummer
committed
// set homeposition of settingsItem
MissionSettingsItem* settingsItem = missionControllerVisuals->value<MissionSettingsItem *>(0);
if (settingsItem == nullptr) {
qWarning("WimaController::calcNextPhase(): nullptr");
return false;
Valentin Platzgummer
committed
}
settingsItem->setCoordinate(_takeoffLandPostion);
for (auto coordinate : geoCoordinateList) {
_missionController->insertSimpleMissionItem(coordinate, missionControllerVisuals->count());
Valentin Platzgummer
committed
}
// set takeoff position for first mission item (bug)
SimpleMissionItem *takeoffItem = missionControllerVisuals->value<SimpleMissionItem*>(1);
if (takeoffItem == nullptr) {
qWarning("WimaController::calcNextPhase(): nullptr");
return false;
Valentin Platzgummer
committed
}
takeoffItem->setCoordinate(_takeoffLandPostion);
Valentin Platzgummer
committed
// set land command for last mission item
SimpleMissionItem *landItem = missionControllerVisuals->value<SimpleMissionItem*>(missionControllerVisuals->count()-1);
if (landItem == nullptr) {
qWarning("WimaController::calcNextPhase(): nullptr");
return false;
_missionController->setLandCommand(*landItem, *_masterController->controllerVehicle());
Valentin Platzgummer
committed
// copy to _currentMissionItems
for ( int i = 1; i < missionControllerVisuals->count(); i++) {
SimpleMissionItem *visualItem = missionControllerVisuals->value<SimpleMissionItem*>(i);
if (visualItem == nullptr) {
qWarning("WimaController::calcNextPhase(): Nullptr at SimpleMissionItem!");
Valentin Platzgummer
committed
Valentin Platzgummer
committed
SimpleMissionItem *visualItemCopy = new SimpleMissionItem(*visualItem, true, this);
qWarning() << visualItem->command();
qWarning() << visualItem->coordinate();
qWarning() << visualItemCopy->command();
qWarning() << visualItemCopy->command();
qWarning(" ");
_currentMissionItems.append(visualItemCopy);
}
_missionController->removeAll(); // remove items from _missionController, will be added on upload
void WimaController::updateWaypointPath()
{
_waypointPath.clear();
Valentin Platzgummer
committed
extractCoordinateList(_missionItems, _waypointPath, 0, _missionItems.count()-1);
emit waypointPathChanged();
}
void WimaController::updateCurrentPath()
{
_currentWaypointPath.clear();
Valentin Platzgummer
committed
extractCoordinateList(_currentMissionItems, _currentWaypointPath, 0, _currentMissionItems.count()-1);
emit currentWaypointPathChanged();
}
void WimaController::updateNextWaypoint()
{
if (_endWaypointIndex < _missionItems.count()-2) {
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
_nextPhaseStartWaypointIndex.setRawValue(1 + std::max(_endWaypointIndex + 1 - _overlapWaypoints.rawValue().toInt(), 0));
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
void WimaController::recalcCurrentPhase()
{
_lastMissionPhaseReached = false;
_nextPhaseStartWaypointIndex.setRawValue(_startWaypointIndex + 1);
}
bool WimaController::setTakeoffLandPosition()
{
_takeoffLandPostion.setAltitude(0);
_takeoffLandPostion.setLongitude(_serviceArea.center().longitude());
_takeoffLandPostion.setLatitude(_serviceArea.center().latitude());
return true;