dRonin  adbada4
dRonin GCS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
flightdatamodel.cpp
Go to the documentation of this file.
1 
12 /*
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  * for more details.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, see <http://www.gnu.org/licenses/>
25  */
26 
27 #include "flightdatamodel.h"
29 #include "homelocation.h"
30 #include <QFile>
31 #include <QDomDocument>
32 #include <QMainWindow>
33 #include <QMessageBox>
34 #include <waypoint.h>
35 #include <coreplugin/icore.h>
38 #include "uavobjects/uavobject.h"
39 
40 QMap<int, QString> FlightDataModel::modeNames = QMap<int, QString>();
41 
44  : QAbstractTableModel(parent)
45 {
46  valPaused = false;
47 
48  // This could be auto populated from the waypoint object but nothing else in the
49  // model depends on run time properties and we might want to exclude certain modes
50  // being presented later (e.g. driving on a multirotor)
51  modeNames.clear();
52  modeNames.insert(Waypoint::MODE_VECTOR, tr("Vector"));
53  modeNames.insert(Waypoint::MODE_CIRCLELEFT, tr("Circle Left"));
54  modeNames.insert(Waypoint::MODE_CIRCLERIGHT, tr("Circle Right"));
55  modeNames.insert(Waypoint::MODE_ENDPOINT, tr("Endpoint"));
56  modeNames.insert(Waypoint::MODE_CIRCLEPOSITIONLEFT, tr("Circle Position Left"));
57  modeNames.insert(Waypoint::MODE_CIRCLEPOSITIONRIGHT, tr("Circle Position Right"));
58  modeNames.insert(Waypoint::MODE_LAND, tr("Land"));
59 }
60 
62 int FlightDataModel::rowCount(const QModelIndex & /*parent*/) const
63 {
64  return dataStorage.length();
65 }
66 
68 int FlightDataModel::columnCount(const QModelIndex &parent) const
69 {
70  if (parent.isValid())
71  return 0;
72  return LASTCOLUMN;
73 }
74 
81 QVariant FlightDataModel::data(const QModelIndex &index, int role) const
82 {
83  if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole) {
84 
85  if (!index.isValid() || index.row() > dataStorage.length() - 1)
86  return QVariant::Invalid;
87 
88  PathPlanData *row = dataStorage.at(index.row());
89 
90  // For the case of mode we want the model to normally return the string value
91  // associated with that enum for display purposes. However in the case of
92  // Qt::UserRole this should fall through and return the numerical value of
93  // the enum
94  if (index.column() == (int)FlightDataModel::MODE && role == Qt::DisplayRole) {
95  return modeNames.value(row->mode);
96  }
97 
98  struct FlightDataModel::NED NED;
99  switch (index.column()) {
100  case WPDESCRIPTION:
101  return row->wpDescription;
102  case LATPOSITION:
103  return row->latPosition;
104  case LNGPOSITION:
105  return row->lngPosition;
106  case ALTITUDE:
107  return row->altitude;
108  case NED_NORTH:
109  NED = getNED(row);
110  return NED.North;
111  case NED_EAST:
112  NED = getNED(row);
113  return NED.East;
114  case NED_DOWN:
115  NED = getNED(row);
116  return NED.Down;
117  case VELOCITY:
118  return row->velocity;
119  case MODE:
120  return row->mode;
121  case MODE_PARAMS:
122  return row->mode_params;
123  case LOCKED:
124  return row->locked;
125  }
126  }
127 
128  return QVariant::Invalid;
129 }
130 
138 QVariant FlightDataModel::headerData(int section, Qt::Orientation orientation, int role) const
139 {
140  if (role == Qt::DisplayRole) {
141  if (orientation == Qt::Vertical) {
142  return QString::number(section + 1);
143  } else if (orientation == Qt::Horizontal) {
144  switch (section) {
145  case WPDESCRIPTION:
146  return QString("Description");
147  case LATPOSITION:
148  return QString("Latitude");
149  case LNGPOSITION:
150  return QString("Longitude");
151  case ALTITUDE:
152  return QString("Altitude");
153  case NED_NORTH:
154  return QString("Relative North");
155  case NED_EAST:
156  return QString("Relative East");
157  case NED_DOWN:
158  return QString("Relative Down");
159  case VELOCITY:
160  return QString("Velocity");
161  case MODE:
162  return QString("Mode");
163  case MODE_PARAMS:
164  return QString("Mode parameters");
165  case LOCKED:
166  return QString("Locked");
167  default:
168  return QVariant::Invalid;
169  }
170  }
171  }
172 
173  return QAbstractTableModel::headerData(section, orientation, role);
174 }
175 
183 bool FlightDataModel::setData(const QModelIndex &index, const QVariant &value, int role)
184 {
185  if (index.isValid() && role == Qt::EditRole) {
186  PathPlanData *row = dataStorage.at(index.row());
187 
188  // Do not allow changing any values except locked when the column is locked
189  if (row->locked && index.column() != (int)FlightDataModel::LOCKED)
190  return false;
191 
192  struct FlightDataModel::NED NED;
193  QModelIndex otherIndex;
194  switch (index.column()) {
195  case WPDESCRIPTION:
196  row->wpDescription = value.toString();
197  break;
198  case LATPOSITION:
199  row->latPosition = value.toDouble();
200  // Indicate this also changed the north
201  otherIndex = this->index(index.row(), FlightDataModel::NED_NORTH);
202  emit dataChanged(otherIndex, otherIndex);
203  break;
204  case LNGPOSITION:
205  row->lngPosition = value.toDouble();
206  // Indicate this also changed the east
207  otherIndex = this->index(index.row(), FlightDataModel::NED_EAST);
208  emit dataChanged(otherIndex, otherIndex);
209  break;
210  case ALTITUDE:
211  row->altitude = value.toDouble();
212  // Indicate this also changed the NED down
213  otherIndex = this->index(index.row(), FlightDataModel::NED_DOWN);
214  emit dataChanged(otherIndex, otherIndex);
215  break;
216  case NED_NORTH:
217  NED = getNED(row);
218  NED.North = value.toDouble();
219  setNED(row, NED);
220  // Indicate this also changed the latitude
221  otherIndex = this->index(index.row(), FlightDataModel::LATPOSITION);
222  emit dataChanged(otherIndex, otherIndex);
223  break;
224  case NED_EAST:
225  NED = getNED(index.row());
226  NED.East = value.toDouble();
227  setNED(row, NED);
228  // Indicate this also changed the longitude
229  otherIndex = this->index(index.row(), FlightDataModel::LNGPOSITION);
230  emit dataChanged(otherIndex, otherIndex);
231  break;
232  case NED_DOWN:
233  NED = getNED(index.row());
234  NED.Down = value.toDouble();
235  setNED(row, NED);
236  // Indicate this also changed the altitude
237  otherIndex = this->index(index.row(), FlightDataModel::ALTITUDE);
238  emit dataChanged(otherIndex, otherIndex);
239  break;
240  case VELOCITY:
241  row->velocity = value.toFloat();
242  break;
243  case MODE:
244  row->mode = value.toInt();
245  break;
246  case MODE_PARAMS:
247  row->mode_params = value.toFloat();
248  break;
249  case LOCKED:
250  row->locked = value.toBool();
251  break;
252  default:
253  return false;
254  }
255 
257 
258  emit dataChanged(index, index);
259  return true;
260  }
261  return false;
262 }
263 
268 Qt::ItemFlags FlightDataModel::flags(const QModelIndex &index) const
269 {
270  // Locked is always editable
271  if (index.column() == (int)FlightDataModel::LOCKED)
272  return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
273 
274  // Suppress editable flag if row is locked
275  PathPlanData *row = dataStorage.at(index.row());
276  if (row->locked)
277  return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
278 
279  return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
280 }
281 
288 bool FlightDataModel::insertRows(int row, int count, const QModelIndex & /*parent*/)
289 {
291  beginInsertRows(QModelIndex(), row, row + count - 1);
292  for (int x = 0; x < count; ++x) {
293  // Initialize new internal representation
294  data = new PathPlanData;
295  data->latPosition = 0;
296  data->lngPosition = 0;
297 
298  // If there is a previous waypoint, initialize some of the fields to that value
299  if (rowCount() > 0) {
300  PathPlanData *prevRow = dataStorage.at(rowCount() - 1);
301  data->altitude = prevRow->altitude;
302  data->velocity = prevRow->velocity;
303  data->mode = prevRow->mode;
304  data->mode_params = prevRow->mode_params;
305  data->locked = prevRow->locked;
306  } else {
307  data->altitude = 0;
308  data->velocity = 0;
309  data->mode = Waypoint::MODE_VECTOR;
310  data->mode_params = 0;
311  data->locked = false;
312  }
313  dataStorage.insert(row, data);
314  }
315 
316  endInsertRows();
317 
318  return true;
319 }
320 
327 bool FlightDataModel::removeRows(int row, int count, const QModelIndex & /*parent*/)
328 {
329  if (row < 0)
330  return false;
331  beginRemoveRows(QModelIndex(), row, row + count - 1);
332  for (int x = 0; x < count; ++x) {
333  delete dataStorage.at(row);
334  dataStorage.removeAt(row);
335  }
336  endRemoveRows();
337 
339 
340  return true;
341 }
342 
348 bool FlightDataModel::writeToFile(QString fileName)
349 {
350  double homeLLA[3];
351 
352  QFile file(fileName);
353 
354  if (!file.open(QIODevice::WriteOnly)) {
355  QMessageBox::information(dynamic_cast<QWidget *>(Core::ICore::instance()->mainWindow()),
356  tr("Unable to open file"), file.errorString());
357  return false;
358  }
359  QDataStream out(&file);
360  QDomDocument doc("PathPlan");
361 
362  QDomElement root = doc.createElement("pathplan");
363  doc.appendChild(root);
364 
365  // First of all, we want the home location, because we are going to store the
366  // waypoints relative to the home location, so that the flight path can be
367  // loaded either absolute or relative to the home location
368  QDomElement homeloc = doc.createElement("homelocation");
369  root.appendChild(homeloc);
370  getHomeLocation(homeLLA);
371  QDomElement field = doc.createElement("field");
372  field.setAttribute("value", homeLLA[0]);
373  field.setAttribute("name", "latitude");
374  homeloc.appendChild(field);
375 
376  field = doc.createElement("field");
377  field.setAttribute("value", homeLLA[1]);
378  field.setAttribute("name", "longitude");
379  homeloc.appendChild(field);
380 
381  field = doc.createElement("field");
382  field.setAttribute("value", homeLLA[2]);
383  field.setAttribute("name", "altitude");
384  homeloc.appendChild(field);
385 
386  QDomElement wpts = doc.createElement("waypoints");
387  root.appendChild(wpts);
388 
389  foreach (PathPlanData *obj, dataStorage) {
390 
391  double NED[3];
392  double LLA[3] = { obj->latPosition, obj->lngPosition, obj->altitude };
393  Utils::CoordinateConversions().LLA2NED_HomeLLA(LLA, homeLLA, NED);
394 
395  QDomElement waypoint = doc.createElement("waypoint");
396  waypoint.setAttribute("number", dataStorage.indexOf(obj));
397  wpts.appendChild(waypoint);
398  QDomElement field = doc.createElement("field");
399  field.setAttribute("value", obj->wpDescription);
400  field.setAttribute("name", "description");
401  waypoint.appendChild(field);
402 
403  field = doc.createElement("field");
404  field.setAttribute("value", NED[0]);
405  field.setAttribute("name", "north");
406  waypoint.appendChild(field);
407 
408  field = doc.createElement("field");
409  field.setAttribute("value", NED[1]);
410  field.setAttribute("name", "east");
411  waypoint.appendChild(field);
412 
413  field = doc.createElement("field");
414  field.setAttribute("value", NED[2]);
415  field.setAttribute("name", "down");
416  waypoint.appendChild(field);
417 
418  field = doc.createElement("field");
419  field.setAttribute("value", obj->velocity);
420  field.setAttribute("name", "velocity");
421  waypoint.appendChild(field);
422 
423  field = doc.createElement("field");
424  field.setAttribute("value", obj->mode);
425  field.setAttribute("name", "mode");
426  waypoint.appendChild(field);
427 
428  field = doc.createElement("field");
429  field.setAttribute("value", obj->mode_params);
430  field.setAttribute("name", "mode_params");
431  waypoint.appendChild(field);
432 
433  field = doc.createElement("field");
434  field.setAttribute("value", obj->locked);
435  field.setAttribute("name", "is_locked");
436  waypoint.appendChild(field);
437  }
438  file.write(doc.toString().toLatin1());
439  file.close();
440  return true;
441 }
442 
443 void FlightDataModel::showErrorDialog(const char *title, const char *message)
444 {
445  QMessageBox msgBox(dynamic_cast<QWidget *>(Core::ICore::instance()->mainWindow()));
446  msgBox.setText(tr(title));
447  msgBox.setInformativeText(tr(message));
448  msgBox.setStandardButtons(QMessageBox::Ok);
449  msgBox.exec();
450  return;
451 }
452 
454 {
455  valPaused = pausing;
456 
457  if (!pausing) {
459  }
460 }
461 
463 {
464  struct FlightDataModel::NED prevNED = { 0.0, 0.0, 0.0 };
465 
466  // Skip validation when there's a download from firmware in process.
467  if (valPaused) {
468  return;
469  }
470 
471  for (int i = 0; i < rowCount(); i++) {
472  PathPlanData *row = dataStorage.at(i);
473 
474  bool dirty = false;
475 
476  struct FlightDataModel::NED thisNED = getNED(row);
477 
478  if (i == 0) {
479  switch (row->mode) {
480  case Waypoint::MODE_CIRCLELEFT:
481  case Waypoint::MODE_CIRCLERIGHT:
482  row->mode = Waypoint::MODE_VECTOR;
483 
484  showErrorDialog("Waypoint corrected",
485  "First waypoint may not be the endpoint of an arc");
486  dirty = true;
487 
488  break;
489  default:
490  break;
491  }
492  }
493 
494  double distance =
495  sqrt(pow(thisNED.North - prevNED.North, 2) + pow(thisNED.East - prevNED.East, 2));
496 
497  if (distance > 600) {
498  // If the distance is more than 600m, presume it's invalid.
499  // Distances larger than this begin to become problematic
500  // with local tangent plane approximation.
501  //
502  // If this happens, move the location of this waypoint to the
503  // previous location.
504 
505  thisNED = prevNED;
506  setNED(row, thisNED);
507  distance = 0;
508 
509  showErrorDialog("Waypoint corrected", "Over-long leg shortened.");
510 
511  dirty = true;
512  }
513 
514  switch (row->mode) {
515  case Waypoint::MODE_CIRCLELEFT:
516  case Waypoint::MODE_CIRCLERIGHT:
517  if (row->mode_params < (distance / 2 + 0.1f)) {
518  row->mode_params = distance / 2 + 0.2f;
519 
520  showErrorDialog("Waypoint corrected", "Radius of circle increased to minimum");
521 
522  dirty = true;
523  }
524 
525  break;
526  case Waypoint::MODE_CIRCLEPOSITIONLEFT:
527  case Waypoint::MODE_CIRCLEPOSITIONRIGHT:
528  if (row->mode_params < 0.5f) {
529  row->mode_params = 0.5f;
530 
531  showErrorDialog("Waypoint corrected", "Radius of circle increased to minimum");
532 
533  dirty = true;
534  } else if (row->mode_params > 300) {
535  row->mode_params = 300;
536 
537  showErrorDialog("Waypoint corrected", "Radius of circle decreased to maximum");
538 
539  dirty = true;
540  }
541 
542  break;
543 
544  default:
545  break;
546  }
547 
548  if (dirty) {
549  /* Let anyone listening know we changed it - Fire an event for the
550  * entire row being changed. (Because changing NED changes lots of
551  * columns) */
552  QModelIndex leftIndex, rightIndex;
553 
554  leftIndex = this->index(i, LATPOSITION);
555  rightIndex = this->index(i, LASTCOLUMN - 1);
556 
557  emit dataChanged(leftIndex, rightIndex);
558  }
559 
560  prevNED = thisNED;
561  }
562 }
563 
568 void FlightDataModel::readFromFile(QString fileName)
569 {
570  double HomeLLA[3];
571 
572  removeRows(0, rowCount());
573  QFile file(fileName);
574  if (!file.open(QIODevice::ReadOnly)) {
575  showErrorDialog("Unable to open file", "Unable to open file");
576  return;
577  }
578 
579  QDomDocument doc("PathPlan");
580  QByteArray array = file.readAll();
581  QString error;
582 
583  file.close();
584 
585  if (!doc.setContent(array, &error)) {
586  showErrorDialog("File Parsing Failure", "This file is not a correct XML file");
587  return;
588  }
589 
590  QDomElement root = doc.documentElement();
591 
592  // First of all, read in the Home Location and reset it:
593 
594  if (root.isNull() || root.tagName() != "pathplan") {
595  showErrorDialog("Wrong file contents", "This is not a valid flight plan file");
596  return;
597  }
598 
599  PathPlanData *data = NULL;
600 
601  // First of all, find the Home location saved in the file
602  QDomNodeList hlist = root.elementsByTagName("homelocation");
603  if (hlist.length() != 1) {
604  showErrorDialog("Wrong file contents", "File format is incorrect (missing home location)");
605  return;
606  }
607 
608  QDomNode homelocField = hlist.at(0).firstChild();
609  while (!homelocField.isNull()) {
610  QDomElement field = homelocField.toElement();
611  if (field.tagName() == "field") {
612  if (field.attribute("name") == "latitude") {
613  HomeLLA[0] = field.attribute("value").toDouble();
614  } else if (field.attribute("name") == "longitude") {
615  HomeLLA[1] = field.attribute("value").toDouble();
616  } else if (field.attribute("name") == "altitude") {
617  HomeLLA[2] = field.attribute("value").toDouble();
618  }
619  }
620  homelocField = homelocField.nextSibling();
621  }
622 
623  // For now, reset home location to the location in the file.
624  // In a future revision, we should consider asking the user whether to remap the flight plan
625  // to the current home location or use the one in the flight plan
626  if (!setHomeLocation(HomeLLA)) {
627  showErrorDialog("Home location error", "Home location coordinates invalid");
628  return;
629  }
630 
631  hlist = root.elementsByTagName("waypoints");
632  if (hlist.length() != 1) {
633  showErrorDialog("Wrong file contents", "File format is incorrect (missing waypoints)");
634  }
635  QDomNode node = hlist.at(0).firstChild();
636  while (!node.isNull()) {
637  QDomElement e = node.toElement();
638  if (e.tagName() == "waypoint") {
639  QDomNode fieldNode = e.firstChild();
640  data = new PathPlanData;
641  double wpLLA[3];
642  double wpNED[3];
643  int params = 0;
644  while (!fieldNode.isNull()) {
645  QDomElement field = fieldNode.toElement();
646  if (field.tagName() == "field") {
647  if (field.attribute("name") == "down") {
648  wpNED[2] = field.attribute("value").toDouble();
649  params++;
650  } else if (field.attribute("name") == "description") {
651  data->wpDescription = field.attribute("value");
652  params++;
653  } else if (field.attribute("name") == "north") {
654  wpNED[0] = field.attribute("value").toDouble();
655  params++;
656  } else if (field.attribute("name") == "east") {
657  wpNED[1] = field.attribute("value").toDouble();
658  params++;
659  } else if (field.attribute("name") == "velocity") {
660  data->velocity = field.attribute("value").toFloat();
661  params++;
662  } else if (field.attribute("name") == "mode") {
663  data->mode = field.attribute("value").toInt();
664  params++;
665  } else if (field.attribute("name") == "mode_params") {
666  data->mode_params = field.attribute("value").toFloat();
667  params++;
668  } else if (field.attribute("name") == "is_locked") {
669  data->locked = field.attribute("value").toInt();
670  params++;
671  }
672  }
673  fieldNode = fieldNode.nextSibling();
674  }
675 
676  // We can't really check everything in the file is fully consistent, but
677  // at least we can make sure we have the right number of fields
678  if (params < 8) {
679  showErrorDialog("Waypoint error", "Waypoint coordinates invalid");
680  }
681 
682  Utils::CoordinateConversions().NED2LLA_HomeLLA(HomeLLA, wpNED, wpLLA);
683  data->latPosition = wpLLA[0];
684  data->lngPosition = wpLLA[1];
685  data->altitude = wpLLA[2];
686 
687  beginInsertRows(QModelIndex(), dataStorage.length(), dataStorage.length());
688  dataStorage.append(data);
689  endInsertRows();
690  }
691  node = node.nextSibling();
692  }
693 
695 }
696 
703 bool FlightDataModel::getHomeLocation(double *homeLLA) const
704 {
705  ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
706  Q_ASSERT(pm);
707  UAVObjectManager *objMngr = pm->getObject<UAVObjectManager>();
708  Q_ASSERT(objMngr);
709 
710  HomeLocation *home = HomeLocation::GetInstance(objMngr);
711  if (home == NULL)
712  return false;
713 
714  HomeLocation::DataFields homeLocation = home->getData();
715  homeLLA[0] = homeLocation.Latitude / 1e7;
716  homeLLA[1] = homeLocation.Longitude / 1e7;
717  homeLLA[2] = homeLocation.Altitude;
718 
719  return true;
720 }
721 
728 bool FlightDataModel::setHomeLocation(double *homeLLA)
729 {
730  ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
731  Q_ASSERT(pm);
732  UAVObjectManager *objMngr = pm->getObject<UAVObjectManager>();
733  Q_ASSERT(objMngr);
734 
735  HomeLocation *home = HomeLocation::GetInstance(objMngr);
736  if (home == NULL)
737  return false;
738 
739  // Check that home location is sensible
740  if (homeLLA[0] < -90 || homeLLA[0] > 90 || homeLLA[1] < -180 || homeLLA[1] > 180)
741  return false;
742 
743  HomeLocation::DataFields homeLocation = home->getData();
744  homeLocation.Latitude = homeLLA[0] * 1e7;
745  homeLocation.Longitude = homeLLA[1] * 1e7;
746  homeLocation.Altitude = homeLLA[2];
747 
748  home->setData(homeLocation);
749 
750  return true;
751 }
752 
753 struct FlightDataModel::NED FlightDataModel::getNED(PathPlanData *row) const
754 {
755  double f_NED[3];
756  double homeLLA[3];
757  double LLA[3] = { row->latPosition, row->lngPosition, row->altitude };
758 
759  getHomeLocation(homeLLA);
761 
762  struct NED NED;
763  NED.North = f_NED[0];
764  NED.East = f_NED[1];
765  NED.Down = f_NED[2];
766 
767  return NED;
768 }
769 
775 struct FlightDataModel::NED FlightDataModel::getNED(int index) const
776 {
777  PathPlanData *row = dataStorage.at(index);
778 
779  return getNED(row);
780 }
781 
782 bool FlightDataModel::setNED(PathPlanData *row, struct FlightDataModel::NED NED)
783 {
784  double homeLLA[3];
785  double LLA[3];
786  double f_NED[3] = { NED.North, NED.East, NED.Down };
787 
788  getHomeLocation(homeLLA);
789  Utils::CoordinateConversions().NED2LLA_HomeLLA(homeLLA, f_NED, LLA);
790 
791  row->latPosition = LLA[0];
792  row->lngPosition = LLA[1];
793  row->altitude = LLA[2];
794 
795  return true;
796 }
797 
804 bool FlightDataModel::setNED(int index, struct FlightDataModel::NED NED)
805 {
806  PathPlanData *row = dataStorage.at(index);
807 
808  return setNED(row, NED);
809 }
810 
817 {
818  // Delete existing data
819  removeRows(0, rowCount());
820 
821  for (int i = 0; i < newModel->rowCount(); i++) {
822  insertRow(i);
823  for (int j = 0; j < newModel->columnCount(); j++) {
824  // Use Qt::UserRole to make sure the mode is fetched numerically
825  setData(index(i, j), newModel->data(newModel->index(i, j), Qt::UserRole));
826  }
827  }
828 
830 
831  return true;
832 }
bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex())
FlightDataModel::insertRows Create a new waypoint.
double lngPosition
Longitude of the waypoint.
FlightDataModel(QObject *parent)
Initialize an empty flight plan.
int mode
Navigation mode for this waypoint.
double altitude
Altitude of the waypoint (m above ellipsoid)
static QMap< int, QString > modeNames
Core plugin system that manages the plugins, their life cycle and their registered objects...
Definition: pluginmanager.h:53
axis equal end function NED
Definition: OPPlots.m:63
Qt::ItemFlags flags(const QModelIndex &index) const
FlightDataModel::flags Tell QT MVC which flags are supported for items.
float velocity
Velocity associated with this waypoint.
void LLA2NED_HomeLLA(double LLA[3], double homeLLA[3], double NED[3])
for i
Definition: OPPlots.m:140
double latPosition
Latitude of the waypoint.
bool writeToFile(QString filename)
FlightDataModel::writeToFile Write the waypoints to an xml file.
int rowCount(const QModelIndex &parent=QModelIndex()) const
Return the number of waypoints.
QString wpDescription
Description for the waypoint.
void readFromFile(QString fileName)
FlightDataModel::readFromFile Read into the model from a flight plan xml file.
Parse log file
end function out
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex())
FlightDataModel::removeRows Remove waypoints from the model.
static ICore * instance()
Definition: coreimpl.cpp:46
bool replaceData(FlightDataModel *newModel)
Replace a model data with another model.
int columnCount(const QModelIndex &parent=QModelIndex()) const
Return the number of fields in the model.
int NED2LLA_HomeLLA(double homeLLA[3], double NED[3], double LLA[3])
The PathPlanData struct is the internal representation of the waypoints. Notice this is in absolute t...
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole)
FlightDataModel::setData Set the data at a given location.
QVariant headerData(int section, Qt::Orientation orientation, int role) const
FlightDataModel::headerData Get the names of the columns.
void pauseValidation(bool pausing)
Prevent validation/correction of data.
LLA
Definition: OPPlots.m:34
else error('Your technical computing program does not support file choosers.Please input the file name in the argument. ') end elseif nargin >0 logfile
x
Definition: OPPlots.m:100
bool locked
Lock a waypoint.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
FlightDataModel::data Fetch the data from the model.
float mode_params
Optional parameters associated with this waypoint.
e
Definition: OPPlots.m:99