27 #include <QMessageBox>
28 #include <QTextStream>
38 QString KmlExport::dateTimeFormat =
39 "yyyy-MM-ddThh:mm:ssZ";
43 20 // Vehicle velocity which corresponds to maximum color in color map. This shouldn't be
45 #define numberOfWallAxes 5 // Number of wall axes to plot. This shouldn't be hardcoded
46 #define wallAxesSeparation 20 // Wall axes separation height in [m]. This shouldn't be hardcoded
49 : outputFileName(outputKmlFileName)
51 logFile.setFileName(inputLogFileName);
61 airspeedActual = AirspeedActual::GetInstance(kmlUAVObjectManager);
62 attitudeActual = AttitudeActual::GetInstance(kmlUAVObjectManager);
63 gpsPosition = GPSPosition::GetInstance(kmlUAVObjectManager);
64 homeLocation = HomeLocation::GetInstance(kmlUAVObjectManager);
65 positionActual = PositionActual::GetInstance(kmlUAVObjectManager);
66 velocityActual = VelocityActual::GetInstance(kmlUAVObjectManager);
68 homeLocationData = homeLocation->getData();
69 gpsPositionData = gpsPosition->getData();
73 connect(positionActual, SIGNAL(objectUpdated(
UAVObject *)),
this,
74 SLOT(positionActualUpdated(
UAVObject *)), Qt::DirectConnection);
75 connect(homeLocation, SIGNAL(objectUpdated(
UAVObject *)),
this,
76 SLOT(homeLocationUpdated(
UAVObject *)), Qt::DirectConnection);
77 connect(gpsPosition, SIGNAL(objectUpdated(
UAVObject *)),
this,
78 SLOT(gpsPositionUpdated(
UAVObject *)), Qt::DirectConnection);
81 factory = KmlFactory::GetFactory();
84 document = factory->CreateDocument();
87 timestampFolder = factory->CreateFolder();
88 timestampFolder->set_name(
"Arrows");
90 trackFolder = factory->CreateFolder();
91 trackFolder->set_name(
"Track");
94 StyleMapPtr styleCBS = createCustomBalloonStyle();
95 document->add_styleselector(styleCBS);
97 StylePtr styleGT = createGroundTrackStyle();
98 document->add_styleselector(styleGT);
100 StyleMapPtr wallAxesStyle = createWallAxesStyle();
101 document->add_styleselector(wallAxesStyle);
104 for (
int i = 0;
i < numberOfWallAxes;
i++) {
105 CoordinatesPtr coordinates = factory->CreateCoordinates();
106 wallAxes.append(coordinates);
117 qDebug() <<
"Logfile failed to open during KML export";
124 qDebug() <<
"Logfile preparsing failed";
132 document->add_feature(trackFolder);
135 document->add_feature(timestampFolder);
139 LineStringPtr linestring = factory->CreateLineString();
140 linestring->set_extrude(
false);
141 linestring->set_altitudemode(kmldom::ALTITUDEMODE_CLAMPTOGROUND);
142 linestring->set_coordinates(wallAxes[0]);
144 MultiGeometryPtr multiGeometry = factory->CreateMultiGeometry();
145 multiGeometry->add_geometry(linestring);
147 PlacemarkPtr placemark = factory->CreatePlacemark();
148 placemark->set_geometry(multiGeometry);
149 placemark->set_styleurl(
"#ts_2_tb");
150 placemark->set_name(
"Ground track");
152 document->add_feature(placemark);
156 FolderPtr folder = factory->CreateFolder();
157 for (
int i = 0;
i < numberOfWallAxes;
i++) {
158 LineStringPtr linestring = factory->CreateLineString();
159 linestring->set_extrude(
false);
160 linestring->set_altitudemode(kmldom::ALTITUDEMODE_ABSOLUTE);
161 linestring->set_coordinates(wallAxes[
i]);
163 MultiGeometryPtr multiGeometry = factory->CreateMultiGeometry();
164 multiGeometry->add_geometry(linestring);
166 PlacemarkPtr placemark = factory->CreatePlacemark();
167 placemark->set_geometry(multiGeometry);
168 placemark->set_styleurl(
"#ts_1_tb");
170 folder->add_feature(placemark);
171 folder->set_name(
"Wall axes");
173 document->add_feature(folder);
176 KmlPtr kml = factory->CreateKml();
177 kml->set_feature(document);
180 std::string kml_data = kmldom::SerializePretty(kml);
183 if (QFileInfo(outputFileName).suffix().toLower() ==
"kmz") {
184 if (!kmlengine::KmzFile::WriteKmz(outputFileName.toStdString().c_str(), kml_data)) {
185 qDebug() <<
"KMZ write failed: " << outputFileName;
187 "Failed to write KMZ file.");
190 }
else if (QFileInfo(outputFileName).suffix().toLower() ==
"kml") {
191 if (!kmlbase::File::WriteStringToFile(kml_data, outputFileName.toStdString())) {
192 qDebug() <<
"KML write failed: " << outputFileName;
194 "Failed to write KML file.");
198 qDebug() <<
"Write failed. Invalid file name:" << outputFileName;
200 "Failed to write file. Invalid filename");
218 if (
logFile.open(QIODevice::ReadOnly) ==
false) {
219 qDebug() <<
"Unable to open " <<
logFile.fileName() <<
" for logging";
225 QString logGitHashString =
logFile.readLine().trimmed();
228 QString logUAVOHashString =
logFile.readLine().trimmed();
239 if (logUAVOHashString != uavoHash) {
241 msgBox.setText(
"Likely log file incompatibility.");
242 msgBox.setInformativeText(QString(
"The log file was made with branch %1, UAVO hash %2. GCS "
243 "will attempt to export the file.")
244 .arg(logGitHashString)
245 .arg(logUAVOHashString));
247 }
else if (logGitHashString != gitHash) {
249 msgBox.setText(
"Possible log file incompatibility.");
250 msgBox.setInformativeText(
251 QString(
"The log file was made with branch %1. GCS will attempt to export the file.")
252 .arg(logGitHashString));
256 QString tmpLine =
logFile.readLine();
258 while (tmpLine !=
"##\n" && cnt < 10 && !
logFile.atEnd()) {
259 tmpLine =
logFile.readLine().trimmed();
264 if (cnt >= 10 ||
logFile.atEnd()) {
266 msgBox.setText(
"Corrupted file.");
267 msgBox.setInformativeText(
"GCS cannot find the separation byte. GCS will attempt to export "
287 timestampBuffer.clear();
288 timestampPos.clear();
289 quint64 logFileStartIdx =
logFile.pos();
290 quint32 lastTimeStamp = 0;
296 timestampPos.append(
logFile.pos());
299 logFile.read(reinterpret_cast<char *>(&lastTimeStamp),
sizeof(lastTimeStamp));
300 logFile.read(reinterpret_cast<char *>(&dataSize),
sizeof(dataSize));
305 if ((dataSize & 0xFFFFFFFFFFFF0000) != 0) {
306 qDebug() <<
"Wrong sync byte. At file location 0x"
307 << QString(
"%1").arg(
logFile.pos(), 0, 16) <<
"Got 0x"
308 << QString(
"%1").arg(dataSize & 0xFFFFFFFFFFFF0000, 0, 16)
309 <<
", but expected 0x"
312 logFile.seek(timestampPos.last() + 1);
313 timestampPos.pop_back();
318 if (!timestampBuffer.isEmpty() && lastTimeStamp < timestampBuffer.last()) {
320 msgBox.setText(
"Corrupted file.");
321 msgBox.setInformativeText(
"Timestamps are not sequential. Playback may have unexpected "
326 qDebug() <<
"Timestamp: " << timestampBuffer.last() <<
" " << lastTimeStamp;
329 timestampBuffer.append(lastTimeStamp);
331 logFile.seek(timestampPos.last() +
sizeof(lastTimeStamp) +
sizeof(dataSize) + dataSize);
335 if (timestampBuffer.size() == 0) {
337 msgBox.setText(
"Empty logfile.");
338 msgBox.setInformativeText(
"No log data can be found.");
365 void KmlExport::parseLogFile()
368 quint32 timeStampIdx;
372 if (
logFile.bytesAvailable() < 4) {
377 logFile.read(reinterpret_cast<char *>(&timeStamp),
sizeof(timeStamp));
378 logFile.read(reinterpret_cast<char *>(&packetSize),
sizeof(packetSize));
380 if (packetSize < 1 || packetSize > (1024 * 1024)) {
381 qDebug() <<
"Error: Logfile corrupted! Unlikely packet size: " << packetSize <<
"\n";
382 QMessageBox::critical(
384 "Incorrect packet size. Stopping export. Data up to this point will be saved.");
389 if (
logFile.bytesAvailable() < packetSize) {
394 QByteArray dataBuffer;
395 dataBuffer.append(
logFile.read(packetSize));
401 for (
int i = 0;
i < dataBuffer.size();
i++) {
402 kmlTalk->processInputByte(dataBuffer[
i]);
416 StyleMapPtr KmlExport::createCustomBalloonStyle()
418 StyleMapPtr styleMap = factory->CreateStyleMap();
424 BalloonStylePtr balloonStyle = factory->CreateBalloonStyle();
425 balloonStyle->set_text(
"$[description]");
428 IconStyleIconPtr iconStyleIcon = factory->CreateIconStyleIcon();
429 iconStyleIcon->set_href(
"http://maps.google.com/mapfiles/kml/shapes/arrow.png");
432 LabelStylePtr labelStyle = factory->CreateLabelStyle();
433 labelStyle->set_color(kmlbase::Color32(255, 0, 255, 255));
434 labelStyle->set_scale(0.75);
437 IconStylePtr iconStyle = factory->CreateIconStyle();
438 iconStyle->set_icon(iconStyleIcon);
439 iconStyle->set_scale(0.65);
442 LineStylePtr lineStyle = factory->CreateLineStyle();
443 lineStyle->set_width(3.25);
446 StylePtr style = factory->CreateStyle();
447 style->set_balloonstyle(balloonStyle);
448 style->set_iconstyle(iconStyle);
449 style->set_linestyle(lineStyle);
450 style->set_labelstyle(labelStyle);
452 PairPtr pair = factory->CreatePair();
453 pair->set_styleselector(style);
454 pair->set_key(kmldom::STYLESTATE_NORMAL);
456 styleMap->add_pair(pair);
462 BalloonStylePtr balloonStyle = factory->CreateBalloonStyle();
463 balloonStyle->set_text(
"$[description]");
466 IconStyleIconPtr iconStyleIcon = factory->CreateIconStyleIcon();
467 iconStyleIcon->set_href(
"http://maps.google.com/mapfiles/kml/shapes/arrow.png");
470 IconStylePtr iconStyle = factory->CreateIconStyle();
471 iconStyle->set_icon(iconStyleIcon);
472 iconStyle->set_scale(0.65);
475 LabelStylePtr labelStyle = factory->CreateLabelStyle();
476 labelStyle->set_color(kmlbase::Color32(255, 0, 255, 255));
477 labelStyle->set_scale(0.9);
480 LineStylePtr lineStyle = factory->CreateLineStyle();
481 lineStyle->set_width(6.5);
484 StylePtr style = factory->CreateStyle();
485 style->set_balloonstyle(balloonStyle);
486 style->set_iconstyle(iconStyle);
487 style->set_linestyle(lineStyle);
488 style->set_labelstyle(labelStyle);
490 PairPtr pair = factory->CreatePair();
491 pair->set_styleselector(style);
492 pair->set_key(kmldom::STYLESTATE_HIGHLIGHT);
494 styleMap->add_pair(pair);
497 styleMap->set_id(
"directiveArrowStyle");
506 StylePtr KmlExport::createGroundTrackStyle()
510 BalloonStylePtr balloonStyle = factory->CreateBalloonStyle();
511 balloonStyle->set_text(
"$[id]");
514 IconStylePtr iconStyle = factory->CreateIconStyle();
515 iconStyle->set_scale(0);
518 LabelStylePtr labelStyle = factory->CreateLabelStyle();
519 labelStyle->set_color(kmlbase::Color32(255, 0, 255, 255));
520 labelStyle->set_scale(0);
523 LineStylePtr lineStyle = factory->CreateLineStyle();
524 lineStyle->set_color(kmlbase::Color32(255, 0, 0, 0));
525 lineStyle->set_width(9);
528 StylePtr style = factory->CreateStyle();
529 style->set_balloonstyle(balloonStyle);
530 style->set_iconstyle(iconStyle);
531 style->set_linestyle(lineStyle);
532 style->set_labelstyle(labelStyle);
534 style->set_id(
"ts_2_tb");
539 StyleMapPtr KmlExport::createWallAxesStyle()
541 StyleMapPtr styleMap = factory->CreateStyleMap();
546 BalloonStylePtr balloonStyle = factory->CreateBalloonStyle();
547 balloonStyle->set_text(
"$[id]");
550 IconStylePtr iconStyle = factory->CreateIconStyle();
551 iconStyle->set_scale(0);
554 LabelStylePtr labelStyle = factory->CreateLabelStyle();
555 labelStyle->set_color(kmlbase::Color32(255, 0, 255, 255));
556 labelStyle->set_scale(0);
559 LineStylePtr lineStyle = factory->CreateLineStyle();
560 lineStyle->set_color(kmlbase::Color32(255, 0, 0, 0));
561 lineStyle->set_width(.9);
564 StylePtr style = factory->CreateStyle();
565 style->set_balloonstyle(balloonStyle);
566 style->set_iconstyle(iconStyle);
567 style->set_linestyle(lineStyle);
568 style->set_labelstyle(labelStyle);
570 PairPtr pair = factory->CreatePair();
571 pair->set_styleselector(style);
572 pair->set_key(kmldom::STYLESTATE_NORMAL);
574 styleMap->add_pair(pair);
580 BalloonStylePtr balloonStyle = factory->CreateBalloonStyle();
581 balloonStyle->set_text(
"$[id]");
584 IconStylePtr iconStyle = factory->CreateIconStyle();
585 iconStyle->set_scale(0);
588 LabelStylePtr labelStyle = factory->CreateLabelStyle();
589 labelStyle->set_color(kmlbase::Color32(255, 0, 255, 255));
590 labelStyle->set_scale(0.75);
593 LineStylePtr lineStyle = factory->CreateLineStyle();
594 lineStyle->set_color(kmlbase::Color32(255, 0, 0, 0));
595 lineStyle->set_width(1.8);
598 StylePtr style = factory->CreateStyle();
599 style->set_balloonstyle(balloonStyle);
600 style->set_iconstyle(iconStyle);
601 style->set_linestyle(lineStyle);
602 style->set_labelstyle(labelStyle);
604 PairPtr pair = factory->CreatePair();
605 pair->set_styleselector(style);
606 pair->set_key(kmldom::STYLESTATE_HIGHLIGHT);
608 styleMap->add_pair(pair);
611 styleMap->set_id(
"ts_1_tb");
623 PlacemarkPtr KmlExport::CreateLineStringPlacemark(
const LLAVCoordinates &startPoint,
625 quint32 newPlacemarkTime)
627 CoordinatesPtr coordinates = factory->CreateCoordinates();
631 LineStringPtr linestring = factory->CreateLineString();
632 linestring->set_extrude(
true);
633 linestring->set_altitudemode(kmldom::ALTITUDEMODE_ABSOLUTE);
634 linestring->set_coordinates(coordinates);
636 StyleMapPtr styleMap = factory->CreateStyleMap();
640 BalloonStylePtr balloonStyle = factory->CreateBalloonStyle();
641 balloonStyle->set_text(
"$[description]");
647 LineStylePtr lineStyle = factory->CreateLineStyle();
648 lineStyle->set_color(mapVelocity2Color(currentVelocity));
650 PolyStylePtr polyStyle = factory->CreatePolyStyle();
651 polyStyle->set_color(mapVelocity2Color(currentVelocity, 100));
654 StylePtr style = factory->CreateStyle();
655 style->set_balloonstyle(balloonStyle);
656 style->set_linestyle(lineStyle);
657 style->set_polystyle(polyStyle);
659 PairPtr pair = factory->CreatePair();
660 pair->set_styleselector(style);
661 pair->set_key(kmldom::STYLESTATE_NORMAL);
663 styleMap->add_pair(pair);
670 LineStylePtr lineStyle = factory->CreateLineStyle();
671 lineStyle->set_color(mapVelocity2Color(currentVelocity));
673 PolyStylePtr polyStyle = factory->CreatePolyStyle();
674 polyStyle->set_color(mapVelocity2Color(currentVelocity, 100));
675 polyStyle->set_fill(
false);
678 StylePtr style = factory->CreateStyle();
679 style->set_balloonstyle(balloonStyle);
680 style->set_linestyle(lineStyle);
681 style->set_polystyle(polyStyle);
683 PairPtr pair = factory->CreatePair();
684 pair->set_styleselector(style);
685 pair->set_key(kmldom::STYLESTATE_HIGHLIGHT);
687 styleMap->add_pair(pair);
690 PlacemarkPtr placemark = factory->CreatePlacemark();
691 placemark->set_geometry(linestring);
692 placemark->set_styleselector(styleMap);
693 placemark->set_visibility(
true);
696 TimeSpanPtr timeSpan = factory->CreateTimeSpan();
698 QDateTime::currentDateTimeUtc().addMSecs(newPlacemarkTime);
701 QDateTime endTime = QDateTime::currentDateTimeUtc().addMSecs(newPlacemarkTime);
702 timeSpan->set_begin(startTime.toString(dateTimeFormat).toStdString());
703 timeSpan->set_end(endTime.toString(dateTimeFormat).toStdString());
706 QDateTime trackTime =
707 QDateTime::currentDateTimeUtc().addMSecs(newPlacemarkTime);
710 placemark->set_name(trackTime.toString(dateTimeFormat).toStdString());
713 placemark->set_description(informationString.toStdString());
716 placemark->set_timeprimitive(timeSpan);
730 PlacemarkPtr KmlExport::createTimespanPlacemark(
const LLAVCoordinates ×tampPoint,
731 quint32 lastPlacemarkTime, quint32 newPlacemarkTime)
734 CoordinatesPtr coordinates = factory->CreateCoordinates();
739 PointPtr point = factory->CreatePoint();
740 point->set_extrude(
true);
741 point->set_altitudemode(kmldom::ALTITUDEMODE_ABSOLUTE);
742 point->set_coordinates(coordinates);
745 TimeSpanPtr timeSpan = factory->CreateTimeSpan();
746 QDateTime startTime =
747 QDateTime::currentDateTimeUtc().addMSecs(lastPlacemarkTime);
750 QDateTime endTime = QDateTime::currentDateTimeUtc().addMSecs(newPlacemarkTime);
751 timeSpan->set_begin(startTime.toString(dateTimeFormat).toStdString());
752 timeSpan->set_end(endTime.toString(dateTimeFormat).toStdString());
755 AttitudeActual::DataFields attitudeActualData = attitudeActual->getData();
756 AirspeedActual::DataFields airspeedActualData = airspeedActual->getData();
757 IconStylePtr iconStyle = factory->CreateIconStyle();
758 iconStyle->set_color(mapVelocity2Color(airspeedActualData.CalibratedAirspeed));
759 iconStyle->set_heading(
760 attitudeActualData.Yaw
765 LineStylePtr lineStyle = factory->CreateLineStyle();
766 lineStyle->set_color(mapVelocity2Color(timestampPoint.
groundspeed));
769 StylePtr style = factory->CreateStyle();
770 style->set_linestyle(lineStyle);
771 style->set_iconstyle(iconStyle);
774 PlacemarkPtr placemark = factory->CreatePlacemark();
775 placemark->set_geometry(point);
776 placemark->set_timeprimitive(timeSpan);
777 placemark->set_name(QString(
"%1").arg(timeStamp / 1000.0).toStdString());
778 placemark->set_visibility(
true);
781 placemark->set_styleurl(
"#directiveArrowStyle");
782 placemark->set_styleselector(style);
785 placemark->set_description(informationString.toStdString());
796 kmlbase::Color32 KmlExport::mapVelocity2Color(
double velocity, quint8 alpha)
798 quint8 colorMapIdx = fmin(fabs(velocity / maxVelocity), 1) * 255;
804 return kmlbase::Color32(alpha, b, g, r);
813 void KmlExport::positionActualUpdated(
UAVObject *obj)
818 if (homeLocationData.Set == HomeLocation::SET_FALSE)
822 if (gpsPositionData.Status != GPSPosition::STATUS_FIX2D
823 && gpsPositionData.Status != GPSPosition::STATUS_FIX3D)
826 AirspeedActual::DataFields airspeedActualData = airspeedActual->getData();
827 PositionActual::DataFields positionActualData = positionActual->getData();
828 VelocityActual::DataFields velocityActualData = velocityActual->getData();
833 double homeLLA[3] = { homeLocationData.Latitude / 1e7, homeLocationData.Longitude / 1e7,
834 homeLocationData.Altitude };
835 double NED[3] = { positionActualData.North, positionActualData.East, positionActualData.Down };
843 newPoint.
groundspeed = sqrt(velocityActualData.North * velocityActualData.North
844 + velocityActualData.East * velocityActualData.East);
847 informationString.clear();
848 informationString.append(QString(
"Latitude: %1 deg\nLongitude: %2 deg\nAltitude: %3 "
849 "m\nAirspeed: %4 m/s\nGroundspeed: %5 m/s\n")
853 .arg(airspeedActualData.CalibratedAirspeed)
857 static bool firstPoint;
859 if (firstPoint ==
false) {
870 for (
int i = 0;
i < numberOfWallAxes;
i++) {
872 i * wallAxesSeparation + homeLocationData.Altitude);
876 PlacemarkPtr newPlacemark = CreateLineStringPlacemark(oldPoint, newPoint, timeStamp);
877 trackFolder->add_feature(newPlacemark);
880 if (timeStamp - lastPlacemarkTime > 2000) {
882 PlacemarkPtr newPlacemarkTimestamp =
883 createTimespanPlacemark(newPoint, lastPlacemarkTime, timeStamp);
884 timestampFolder->add_feature(newPlacemarkTimestamp);
885 lastPlacemarkTime = timeStamp;
895 void KmlExport::homeLocationUpdated(
UAVObject *obj)
898 homeLocationData = homeLocation->getData();
901 void KmlExport::gpsPositionUpdated(
UAVObject *obj)
904 gpsPositionData = gpsPosition->getData();
const char *const UAVOSHA1_STR
void UAVObjectsInitialize(UAVObjectManager *objMngr)
bool exportToKML()
KmlExport::exportToKML Triggers logfile export to KML.
KmlExport(QString inputFileName, QString outputFileName)
axis equal end function NED
bool open()
KmlExport::open Opens the logfile and ensures it's sane.
static ICore * instance()
int NED2LLA_HomeLLA(double homeLLA[3], double NED[3], double LLA[3])
const char *const GCS_REVISION_STR
const double ColorMap_Jet[256][3]
bool preparseLogFile()
KmlExport::preparseLogFile Ensures that the logfile has data to export.
bool stopExport()
KmlExport::stopExport Called to stop the export. Currently only closes the logfile.